The_Anatomy_of_the_1541_Disk_Drive_Jun84 The Anatomy Of 1541 Disk Drive Jun84

The_Anatomy_of_the_1541_Disk_Drive_Jun84 The_Anatomy_of_the_1541_Disk_Drive_Jun84

User Manual: The_Anatomy_of_the_1541_Disk_Drive_Jun84

Open the PDF directly: View PDF PDF.
Page Count: 336

DownloadThe_Anatomy_of_the_1541_Disk_Drive_Jun84 The Anatomy Of 1541 Disk Drive Jun84
Open PDF In BrowserView PDF
THE ANATOMY OF THE
1541 DISK DRIVE
A Complete Guide to Using
The Commodore Disk Drive

Authors:

Lothar Eng1isch
Norbert Szczepanowski

Edited by:

Greg Dykema
Arnie Lee

ABACUS SOFTWARE
P.O. BOX

7211

GRAND RAPIDS, MI 49510

Second English printing, June 1984
Printed in U.S.A
Copyright (C)1983 Data Becker GrngH
Merowingerstr. 30
4000 Dusseldorf W. Germany
Copyright (C)1984 Abacus Software
P.O. Box 7211
Grand Rapids, MI 49510
This book is copyrighted. No part of this publication may be
reproduced, stored in a retrieval system, or transmitted in
any form or by any means, electronic, mechanical,
photocopying, recording, or otherwise, without the prior
written permission of ABACUS Software, Inc.
ISBN

0-916439-01-1

PREFACE

The VIC-154l disk drive represents a very efficient external
storage medium for the Commodore user. It is an affordable
peripheral. In order to get the most from your 1541, you
need the appropriate information.
In months of long,
detailed work, Lothar Englisch and Norbert Szczepanowski
have discovered many secrets of the 1541.
This book progresses from simple storage techniques, to
direct access commands , to program chaining techniques.
Beginners will welcome the nUmerous sample programs that are
fully explained in clear text. Machine language programmers
will particularly like the detailed documentation listing of
the Disk Operating System (005).
This book contains many useful and ready-to-run programs
that need only be
typed in. Some of these programs
are: routines for extending BASIC, helpful routines such as
spooling, efficient address management, a complete household
budget planner and an easy-to-use DOS monitor to manipulate
individual sectors. Have fun with this book and your VIC1541 disk drive.

TABLE OF CONTENTS
Chapter 1: programming the VIC-1541 •••••••••••••••••••••••• 1
1.1 Getting Started •••••••••••••••••••••••••••••••••••••••• l
1.1.1 The Disk Operating System ••••••••••••••••••••••• l
1.1.2 The TEST/DEMO Diskette •••••••••••••••••••••••••• 2
1.1.3 Formatting New Diskettes •••••••••••••••••••••••• 2
1.1.4 Some Facts about a 1541 Diskette •••••••••••••••• 3
1.2 Storing Programs on Diskette ••••••••••••••••••••••••••• 4
1.2.1 SAVE - Storing BASIC Programs ••••••••••••••••••• 4
1.2.2 LOAD - Loading BASIC Programs ••••••••••••••••••• 4
1.2.3 VERIFY - Checking Stored prograros ••••••••••••••• 5
1.2.4 SAVE "@: ..... Replacing Prograros ••••••••••••••••• 5
1.2.5 Loading Machine Language Programs ••••••••••••••• 6
1.2.6 Storing Machine Language Programs ••••••••••••••• 7
1.3 Disk System Commands •••••••••••••••••••••••••••••••••• l0
1.3.1 Transmitting Commands to the Disk Drive •••••••• 10
1.3.2 NEW - Formatting Diskettes ••••••••••••••••••••• 11
1.3.3 Reading the Error Channel •••••••••••••••••••••• 12
1.3.4 LOAD "$",8 Loading the Directory •••••••••••••• 13
1.3.5 SCRATCH - Deleting Files ••••••••••••••••••••••• 14
1.3.6 RENAME - Renaming Files •••••••••••••••••••••••• 15
1.3.7 COpy - Copying Files ••••••••••••••••••••••••••• 16
1.3.8 INITIALIZE - Intitializing the Diskette •••••••• 16
1.3.9 VALIDATE - "Cleaning up· the Diskette •••••••••• 17
1.3.10 ? * - The Wildcards ••••••••••••••••••••••••••• 18
1.4 Sequential Data Storage ••••••••••••••••••••••••••••••• 20
1.4.1 The principle •••••••••••••••••••••••••••••••••• 20
1.4.2 OPENing a Sequential File •••••••••••••••••••••• 21
1.4.3 Transferring Data between Disk and Computer •••• 24
1.4.4 Adding Data to Sequential Files •••••••••••••••• 27
1.4.5 CLOSEing a sequential File ••••••••••••••••••••• 28
1.4.6 Redirecting the Screen Output ••••••••••••••• ·••• 29
1.4.7 Sequential Files as Tables in the Computer ••••• 30
1.4.8 Searching Tables ••••••••••••••••••••••••••• ~ ••• 32
1.4.9 Simple sorting of Tables ••••••••••••••••••••••• 35
1.4.10 Mailing List Management with Sequential
Data Storage •••••••••••••••••••••••••••••••• 38
1.4.11 Uses for Sequential Storage •••••••••••••••••••• 45
1.5 Relative Data Storage ••••••••••••••••••••••••••••••••• 46
1.5.1 The Principle •••••••••••••••••••••••••••••••••• 46
1.5.2 The Advantage over Sequential Storage •••••••••• 47
1.5.3 OPENing a Relative File •••••••••••••••••••••••• 47
1.5.4 Preparing the Data for Relative Storage •••••••• 50
1.5.5 Transferring Data •••••••••••••••••••••••••••••• 52
1.5.6 CLOSEing a Relative File ••••••••••••••••••••••• 55
1.5.7 Searching Records with the Binary Method ••••••• 55
1.5.8 Searching Records with a Separate Index File ••• 58
1.5.9 Changing Records ••••••••••••••••••••••••••••••• 61
1.5.10 Expanding a Relative File •••••••••••••••••••••• 62

1.5.11 Home Accounting with Relative Data Storage ••••• 64
1.6 Disk Error Messages and their Causes •••••••••••••••••• 72
1.7 Overview of Commands with a Comparison of
BASIC 2.0 - BASIC 4.0 - OOS 5.1 •••••••••••••••••••• 77
Chapter 2: Advanced Programming ••••••••••••••••••••••••••• 82
2.1 The Direct Access of any Block of the Diskette •••••••• 82
2.2 The Di rect
2.2.1 The
2.2.2 The
2.2.3 The
2.2.4 The
2.2.5 The
2.2.6 The

Access Commands ••••••••••••••••.••••••••••• 86
Block-Read Command ••••••••••••••••••••••••• 86
Block-Pointer Command •••••••••••••••••••••• 87
Block-Write Command •••••••••••••••••••••••• 88
Block-Allocate Command ••••••••••••••••••••• 89
Block-Free Command ••••••••••••••••••••••••• 90
Block-Execute Command •••••••••••••••••••••• 91

2.3 Uses of Di rect Access ••••••.•••••••••••••••••••••••••• 92
2.4 Accessing the DOS - The Memory Commands ••••••••••••••• 94
2.4.1 The Memory-Read Command •••••••••••••••••••••••• 94
2.4.2 The Memory-Write Command ••••••••••••••••••••••• 95
2.4.3 The Memory-Execute Command ••••••••••••••••••••• 96
2.4.4 The User Commands •••••••••••••••••••••••••••••• 97
Chapter 3: Technical Information •••••••••••••••••••••••••• 99
3.1 The Construction the VIC-154l ••••••••••••••.•••••••••• 99
3.1.1 Block Diagram of the Disk Drive •••••••••••••••• 99
3.1.2 DOS Memory Map - ROM, RAM, 1/0 •••••••••••••••• 100
3.2 Operation of the DOS - An Overview •••••••••.••••••••• l04
3.3 The Structure of the Diskette •••••••••••••••••••••••• 106
3.3.1 The BAM of the VIC 1541 ••••••••••••••••••••••• 106
3.3.2 The Directory ••••••••••••••••••••••••••••••••• l07
3.3.3 The Directory Format •••••••••••••••••••••••••• l09
3.4 The Organization of Relative Files ••••••••••••••••••• 114
3.5 OOS 2.6 Rom Listings ••••••••••••••••••••••••••••••••• 118
Chapter 4:

Programs and Tips For utilization
of the VIC-154l ••••••••••••••••••••••••.••••••• 269

4.1 Utility Programs ••••••••••••••••••••••••••••••••••••• 269
4.1.1 Displaying all File Parameters •••••••••••••••• 269
4.1.2 Scratch-protect Files - File Protect ••.••••••• 273
4.1.3 Backup Program - Copying a Diskette ••••••••••• 278
4.1.4 Copying Individual Files to another Diskette •• 280

4.1.5

Reading the Directory from within a program ••• 281

4.2 The Utility Programs on the TEST/DEMO Disk, •••••••••• 283
4.2 .1 008 5.1 •••.•••••••••••••••••••••••••.••••••••• 283
4.2.2 COPY/ALL •••••••••••••••••••••••••••••••••••••• 284
4.2.3 DISK ADDR CHANGE •••••••••••••••••••••••••••••• 284
4.2.4 DIR ••••.•••••••••••••.•••••••••••••••••••••••• 2fS
4.2.5 VIEW BAM •••••••••••••••••••••••••••••••••••••• 285
4.2.6 CHECK D1 SK •••••••••••••••••••••••••••••••••••• 285
4.2.7 DISPLAY T&S ••••••••••••••••••••••••••••••••••• 286
4.2.8 PERFORMANCE TEST •••••••••••••••••••••••••••••• 286
4.3 BASIC-Expansion and Programs for
Easy Use of the 1541 •••••••••••••••••••••••••• 287
4.3.1 Input strings of desired Length from the Disk.287
4.3.2 Easy preparation of Data Records •••••••••••••• 290
4.3.3 Spooling - Printing Directly from the Disk •••• 295
4.4 OVerlay Technique and Chaining
Machine Language Programs ••••••••••••••••••••• 299
4.5 Merge - Appending BASIC Programs ••••••••••••••••••••• 302
4.6 Disk-Monitor for Commodore 64 and VIC 20 ••••••••••••• 304
Chapter 5: The Larger CBM Disks •••••••••••••••••••••••••• 317
5.1 IEEE-Bus and Serial Bus •••••••••••••••••••••••••••••• 317
5.2 Comparison of all CBM Disk Drives •••••••••••••••••••• 319

Anatomy of the 1541 Disk Drive
Chapter 1: programming the VIC-154l

1.1

Getting Started

There it sits, your new Commodore VIC-154l disk drive. It's
fast and efficient but also intimidating. But have no fear.
We will instruct you in the ways of disk programming. The
first part of this book gives the beginner an intensive look
at the VIC-l54l. At least one example follows each command,
thereby explaining its functions and capabilities. You will
be surprised how easy the operation of your disk drive can
be, when you understand the "basics".
The beginner probably uses the disk drive mainly to store
programs. perhaps he has not realized that there are many
other ways to use the disk drive. This book attempts to
uncover these other ways.
Experienced programmers should not ignore the first chapter.
There may be some sections that may shed light on disk
usage. This is especially true concerning relative files and
data management.

1.1.1

The Disk Operating System

The disk drive is a rather complicated device which
coordinates mechanical hardware and electronic circuitry to
allow the storage of data on the diskette. When the
Commodore 64 or VIC-20 needs to read from or write to the
disk drive, it sends commands to the disk drive along the
heavy black cable that connects the drive to the computer.
The commands sent by the Commodore 64 or VIC-20 are understood at the disk drive by a by a built in program called
the Disk Operating System (DOS).
The DOS is a lengthy program contained on ROM in the disk
drive and carries out the activities of the disk drive as
commanded by the Commodore 64 or VIC-20. The version of DOS
contained in the VIC-154l carries the designation CBM DOS
V2.6.
The Commodore 64 and VIC-20 contain a version of BASIC
called COMMODORE BASIC 2.0. Other versions of BASIC (e.g.
BASIC 4.0 found of the Commodore 8032) have more advanced
disk commands which the VIC-l54l can also understand. In
order to use these advanced disk commands, you have to
sil11ulate them using BASIC 2.0.
At the end of the chapter is a listing of the BASIC 2.0
1

Anatomy .of the 1541 Disk Drive
commands with corresponding commands of the easier BASIC
4.0, as found on the larger Commodore computers.

1.1.2

The TEST/DEMO Diskette

The VIC-l54l disk drive is packaged with a diskette called
TEST/DEMO. Some of the programs contained on it cannot he
used without adequate knowledge of the way the disk drive
works. For now, lay this diskette aside.
The TEST/DEMO diskette is described in detail later.

1.1.3

Formatting New Diskettes

Brand new diskettes must be prepared before using them to
store data. Preparing them is called formatting.
what does formatting mean? Each disk drive mechanism has its
own special characteristics. A diskette is divided into
tracks and information is written along each track (similar
to the grooves of a phonographic record). The number of
tracks per diskette is varies from one manufacturer to
another. Each track is divided into sectors, whose number
can also vary.
During formatting empty sectors are written to the diskette.
A sector is written to each track and sector location and
each sector receives its own "address". This allows the DOS
to identify its position on the diskette. A sector is also
given a code so that the DOS can recognize if this diskette
was formatted by this type of disk drive. The code for the
VIC-154l disk drive is 2A. The remainder of the sector
(called a block) is used to store data and accommodates
exactly 256 characters.
The final purpose of formatting is to construct the
directory for the diskette. The directory is a "table of
contents· of the files stored on the diskette. There is also
a special data block (called the bit availability map or
BAM) which indicates if a given block on the diskette is
already in use or available for use. The directory and BAM
are kept on track 18 of the diskette.

2

Anatomy of the 1541 Disk Drive
1.1.4

Some Pacts about a 1541 Diskette

Diskette:

35
17 to 21 (depending on track)
256
683
644 (the directory occupies
the remainder)
144 per diskette

Number of Tracks:
Sectors per Track:
Bytes per block:
Total number of blocks:
Number of free blocks
Entries in the directory:
Mechanism:

- intelligent peripheral with its own processor and control
system
- connection to serial bus from CBM 64 or VIC-20, device
number 4-15 (8 standard)

3

Anatomy of the 1541 Disk Drive
1.2

Storing Programs on Diskette

The most common use of the disk drive is for storage of
programs. storing programs with a disk drive is considerably
easier than with a cassette recorder. The greatest advantage
of the disk drive is the speed of data transfer to and from
the computer. Here's a comparison:
Saving a 3 Kbyte program takes:
- 75 seconds with the VIC-1530 Datasette
- 12 seconds with the VIC-154l disk drive
An additional advantage is that a diskette can store more
programs than the cassette.
To load a program, you can
consult the directory to view the selection of programs.
Even though the cassette drive allows you to store more than
one program on a tape, searching for that program is very
time consuming.
Before trying any of the following examples in this chapter,
you should remember that the diskette must be previously
formatted as explained in section 1.3.2 in order to be able
to save programs onto it.

1.2.1

SAVE - Storing BASIC Programs

Perhaps you previously owned a datasette on which you stored
programs. In this case the commands to save programs onto
diskette should be familiar to you. The SAVE command for the
disk drive is essentially the same as for the cassette
drive. You need only tell the computer that the program is
to be saved onto the disk drive and not on cassette. This
is done by adding the device number (usually 8) to the
command SAVE. Normally the drive is preset to respond to
this device number. Now write a small BASIC program and save
it with the command:

type in a the NEW command so the program in the computer's
memory is erased. In the following section you will learn
how the program can be retrieved.

1.2.2

LOAD - Loading BASIC Programs

AS with the SAVE command, this command is similar to the
LOAD command for the datasette with the addition of the
device number. NOW load in the previously saved program
with:
4

Anatomy of the 1541 Disk Drive

You can check the program by using the LIST command. Any
previous program in memory has now been replaced by the
program "TEST". It is possible to load a program into the
memory without replacing the previous program in memory.
Combining two program in memory is called "merging" An
example of merging is presented in a later section.

1.2.3

VERIFY - Checking Stored Programs

When you have saved a program on disk with the SAVE command,
it is often desirable to make sure that the program was
written error-free. You can do this by using the VERIFY
command. It has the following format:

Earlier you saved a program with SAVE -TEST-,8. This program should still be in memory. Using VERIFY, the program 1n
memory is checked against the program stored on diskette. If
both programs are identical, the computer responds with OK.
To try this out, type a few BASIC lines and then give the
following commands:
SAVE
·TEST2-,8
VERIFY ·TEST2·,8
Your computer will respond with OK if it is performing
correctly.

1.2.4

SAVE·@: ••• • - Replacing Programs

If you try to save your small TEST program on the disk
again, the computer will respond with a FILE EXISTS error
and will not complete the SAVE. The operating system of ehe
VIC-154l disk drive does not allow two programs to be saved
under the same name. This is logical because the computer
would not be able to distinguish between two programs with
the same name.
However you may want to update a program on diskette that was
previously saved. There are three ways to accomplish this:
1. Save the program under a different name
2. First erase the old program from the disk and save tte
new one under the old name
5

Anatomy of the 1541 Disk Drive
3. Use the addition @: in front of the file name in the SAVE
command
This is used as follows:
SAVE-@:TEST-,8
If you forget to use the characters @: in front of the
filename, and try to save a program whose name is already
contained on the diskette, you get the FILE EXISTS error.
If you are ieplacing a program on a diskette then the DOS
carries this out as follows:
1. A free block is designated as the first block of the
program and its location is stored in the directory entry
of the old copy.
2. The new copy of the program is stored in a free area of
the diskette.
3. All of the

1.2.5

blocks of the old copy are marked as free.

Loading Machine Language Programs

Machine language programs are handled a little differently
from BASIC programs. A machine language program is transferred to the computer by using a secondary address of 1.
When secondary address 1 is used, the program is loaded
"absolutely", that is, loaded into memory beginning at the
address specified in the first two bytes of the disk file.
An example:

loads the machIne language program at an absolute address.
For example, the program may he set up to load at the
decimal address 49152, and is started by the command: SYS
49152. Should you load a machine language program without
the secondary address, you will most likely see the message
"SYNTAX ERROR IN •••• " if you type RUN.
Likewise, trying to LIST the machine language program will
display nonsense. Unfortunately, machine language programs
are not differentiated from BASIC programs in the directory.
Roth have the file type PRG.
Usually, if typing RUN results in SYNTAX ERROR IN •••• , you
know that the program is not written in BASIC and should be
treated as a machine language program. In this case it must
be loaded with the command LOAD ·program-,8,1. It cannot be
6

Anatomy of the 1541 Disk Drive
started with RUN however!
address of this program.

You must first find the execution

In a later section is a program that lists all the file
parameters of a program. One of the parameters is a load
address. This load address is usually the initial execution
address of the program and can be called with the command
SYS load address. You can find the load address of a program
with the following program:
10
20
30
40
50
60
70
80

OPEN 1,8,2,"programname,S,R"
GET#l,X$:IF X$='"' THEN X$=CHR$(O)
LB=ASC(X$)
GET#l,X$:IF X$="n THEN X$=CHR$(O)
HB=ASC(X$)
CLOSE 1
AD=HB*256+LB
PRINT"LOAD ADDRESS:":AD

The program shows the load address of "programname". Here
the program file is opened as a sequential data file. The
starting address is stored as the first two bytes of the
file and read using the GET command and appropriately constructed. The first byte is the low byte and the second byte
the high byte of the two-byte address. If the function of
this program is unclear, handling sequential files clarified
in the next sections.

1.2.6

Storing Machine Language Programs

Machine language programs are usually written with an assembler or a machine language monitor and saved using this
program. Machine language programs can also be written from
BASIC with the individual bytes of the program written in
decimal values in DATA statements. A machine language program written in BASIC with the help of DATA statements
follows:
10
20
30
40
50
60
80
90

SA=starting address
EA=ending address
FOR I=SA TO EA
READ X
POKE I,PEEK(X)
NEXT I
DATA ••••••••••••••••••••••••••••••••••••
DATA ••••••••••••••••••••••••••••••••••••

In this example, the decimal value of the starting address
is placed in line 10 and the ending address fn line 20. The
decimal values of the individual bytes of the machine
language program are typed into the DATA statements of the
7

Anatomy of the 1541 Disk Drive
program, separated by commas.
Naturally, you can save any machine language program that
you find in this book in the form of a BASIC program. This
is, however, a tedious and complicated process. A more
elegant and time-saving method is to store the machine
language program in true form. This way, you can immediately
execute the program after LOADing without requiring any
complicated conversion.
The following program will save such a program that
already in memory:
10
20
30
40
50
60
70
80
90

is

SA=starting address
EA=ending address
OPEN 1,8,1,"programname"
HB=INT(SA/256):LB=SA-HB*256
PRINT#l,CHR$(LB);CHR$(HB);
FOR I=SA TO EA
PRINT#l,CHR$(PEEK(I»;
NEXT I
CLOSE 1

This routine assumes that the machine language program is
already in the memory of the computer. If a program is
already encoded into DATA statements, the following routine
can be used to produced a pure machine language program:
10 SA=starting address
20 EA=ending address
30 OPEN 1,8,1,"programname"
40 HB=INT(SA/256):LB=SA-HB*256
50 PRINT#l,CHR$(LB);CHR$(HB);
60 FOR I=SA TO EA
70 READ X
80 PRINT#I,CHR$(X);
90 NEXT I
100 CLOSE 1
110 DATA •••••••••••••••••••.••••.•
120 DATA ••••••••••••••••••••••••••
Here the addresses and DATA statements are filled in also.
The above program writes a machine language program to
diskette which can later be loaded with the command LOAD
·programname-,8,1. Then the program can be executed with
the command: SYS (starting address). Machine language programs can also be loaded and executed from a BASIC program.
Such a program might have this form:
10 IF A=O THEN A=l:LOAD"programname" ,8,1
20 SYS (starting address)
The IF command in line 10 is puzzling at first. It must be
present because after performing a LOAD from within a program, the BASIC interpreter begins executing again at the
8

Anatomy of the 1541 Disk Drive

first line of the new BASIC program. Because the machine
language program doesn't usually overlay the BASIC program
in memory, the original BASIC program remains intact and is
therefore is re-executed. If you use the routine:
10 LOAD"programname",8,1
20 SYS (starting address)
the program continues to LOAD "programname" again, and the
SYS command is never executed. If the variable A is present,
the program branches to line 20 at the end of the first
command on line 10. This loader can be placed on the
diskette together with the machine language program. To
execute the machine language program, you need only give the
commands:
LOAD-loader-,8
RUN

This has the advantage that the starting address of the
machine language program need not be known, because it is
included in the SYS of the loader.

9

Anatomy of the 1541 Disk Drive
1.3

Disk System Commands

As already mentioned, the VIC-I54l disk drive is similar to
the the earlier, larger disk drives of the Commodore family
the CBM 4040, 8050, 8250. They are all intelligent peripheral device with their own processor and control system.
The Disk Operating System (DOS) occupies no space in the
memory of the Commodore 64 or VIC-20 and yet offers a flexible set of efficient commands. These commands effectively
expand the builtin commands of your Commodore computer.
Because the disk drive is an intelligent peripheral, the
commands of the DOS can be executed independently of the
computer. But because the commands are not found in the
version of BASIC supplied in the Commodore 64 or VIC-20,
you will have to communicate to the disk using a special
method. When the commands are sent to the disk drive, the
DOS interprets and carries out the desired task.

1.3.1

Transmitting commands to the Disk Drive

Commands intended for the disk drive, are sent over a
channel. You can communicate with the disk drive over any of
the 15 available channels. But channel 15 is reserved as the
command channel. Data transfer over this channel takes place
as follows:
- opening the channel
- data transfer
- close the channel

(OPEN)
(PRINT)
(CLOSE)

In the OPEN command you specify a logical file number
(arbitrary between 1 and 127), a device number of the disk
drive (usually 8) and the secondary address (15 for the
command channel). You can also send a command to the device
as illustrated below:
OPEN Ifn,8,I5,·command·
or
OPEN Ifn,8,I5:PRINT'Ifn,·commandThe number 8 is the device number of the disk drive and the
number 15 is the secondary address or channel number. The
parameter lfn is the logical file number which is used in
subsequent commands (PRINT#, INPUT#, GET#). It can be a
number in the range 1-127. The ·command w can either follow
the OPEN statement directly, or can be transferred with a
PRINT# command following the o~ening. Any number of system
commands can be transmitted untll the channel is closed, but
must be referenced by the logical file number used in the
OPEN command.

10

Anatomy of the 1541 Disk Drive
1.3.2

NEW - Formatting Diskettes

The command to format a diskette is called NEW and can, as
every other command, be abbreviated to its first letter (N).
As already mentioned, the command can follow an OPEN command
or be ~iven in a PRINT# command. The NEW command has the
followIng format:
NEW:diskname,id
The parameter diskname may contain up to 16 characters and
is stored in the header of the diskette directory. The
parameter ID (identification) consists of two arbitrary
characters, so that the DOS can recognize if a different
diskette has been used. Since you can freely choose the id,
this allows you to uniquely identify each diskette. Here is
an example for formatting a disk:

The command can be abbreviated to:
OPEN 1,8,15,-N:ABCDISK.KLYou need only use the command once - when you first use a
brand new diskette. Formatting takes about 80 seconds. Formatting uses the processor of the 1541 drive while the
processor of the computer is not needed; you can continue to
work with the computer.
To use the command with a PRINT# statement, the following
commands must be given:
OPEN 1,8,15
PRINTtl,-N:ABCDISK,KL-

to open the channel

The number 1 in the PRINT# command is the logical file
number corresponding to the OPEN command. Other commands may
also be transmitted over this channel after the PRINT#
statement. When no more commands are to be transmitted, the
channel must be closed. This is accomplished through the use
of the CLOSE statement. Give the following command after
formatting:
CLOSE 1
Now the command channel is closed. The number 1 is again the
logical file number of the corresponding OPEN command.

11

Anatomy of the 1541 Disk Drive
1.3.3

Reading the Error Channel

When the Commodore 64 or VIC-20 is incorrectly programmed,
it responds with an error message. Disk commands are carried
out and verified by the processor of the disk drive.
Therefore the computer cannot directly display error
messages that are detected by the disk drive. Errors are
indicated by the flashing red LED on the disk drive. In
order to determine which error has occurred, the computer
must read the error from channel 15. Therefore channel 15
must be OPENed, if this has not already been done. Then the
error can be read with the INPUT# command. An error is sent
back to the computer in four fields Field
Field
Field
Field

1:
2:
3:
4:

Error number
Description of the error (string)
Track number
Sector number

The track and sector information may indicate where the
error occurred (if these fields are relevant to the
command). These four fields of the error message must be
read into four variables. You can use an INPUT# statement
followed by four variables. An example of reading the errc'r
cha.nnel:
OPEN 1,8,15
(if not already done)
INPUT'l,EN,DE$,TR,SE
CLOSE 1
The INPUT' statement must be entered from within a program.
It is not proper to issue an INPUT# statement from command
mode.
10
20
30
40

OPEN 1,8,15
INPUT#l,EN,DE$,TR,SE
PRINT EN;DE$;TR;SE
CLOSE 1

(to display the error)

To understand the operation of this program, first create
the following error:
OPEN l,8,I5,-NEW ABCDISK,TlCLOSE 1
When you have given these commands, the red LED on the disk
drive begins to blink. Did you spot the error? A colon is
missing from the command NEW. Now type the program to read
the error channel and type RUN. The error will appear on the
screen:
34 SYNTAX ERROR 0

0

The 34 is the number of the error, which is explained later.
The track and sector fields are 0 because this information
12

Anatomy of the 1541 Disk Drive
is not relevant to this error.
If you read the error channel
occurred, the message:

o

OK 0

when an error had not

0

is returned. In any case, if the red LED on the drive
blinks, check the syntax of the command, since most errors
can be easily recognized. otherwise, you can simply read the
error channel to find the error which the DOS has detected.
A detailed description of the error message and their caus~s
follows in section 1.6.

1.3.4

LOAD-$-,8 - Loading the Directory

The directory is a "table of contents" of the diskette. All
the files on the diskette are cataloged here. Be sure to
note that loading the directory has a disadvantage: any
program previously in memory is overlayed by the directory
information. The directory is loaded by typing:
LOAD -$-,8
and can be viewed with the LIST command. Try LOADing the
directory of the TEST/DEMO diskette that accompanies your
disk drive.
Insert this diskette into the disk drive and
enter: LOAD -$-,8 to load the directory. Then display the
directory by using the LIST command. what follows should be
shown on the screen

o
13
5
4
I
4
11

4
4
6
4
14
9
5

13

"1541test/demo

" zx 2a
prg
"how part two"
prg
"vic-20 wedge"
prg
"c-64 wedge"
prg
"dos 5.1"
prg
prg
"copy/all"
"disk addr change" prg
prg
"dir"
"view bam"
prg
prg
"cheek disk"
"display t&s"
prg
"performance test" prg
prg
"sequential file"
"random file"
prg

"how to use"

A lot of information is kept in the directory. Let's look at
the first line, the header of the directory. The number 0 in
this line means that the directory is of the diskette in
drive O. Other disk drives such as the 4040, contain two
disk drives - drive 0 or drive 1. On the 1541 the drive
13

Anatomy of the 1541 Disk Drive
number is always O. Next follows the name and ID of the
diskette as set up by formatting. The characters 2A symbolize the disk format. If this format is not 2A then this
diskette was not formatted with a 1541 drive.
Next are the individual file names, their lengths in blocks
in the first column and the file type in the last column.
This diskette contains three different file types:
PRG

These are PROGRAM files, written in either
BASIC or machine language

SEQ

sequential data files, explained later

REL

This is another form of data storage, also
explained later

The length of the files is given in blocks. Each block
contains 256 bytes. You can
find the approximate size a
program. by subtracting
2 bytes from each 256-byte block
that the file occupies. Finally at the end of the directory
is the number of free blocks remaining on the disk. When you
add the lengths of the files and the number of free blocks,
the result is the total number of available blocks on a
diskette (664).
If you own a printer, this directory can be printed as you
would print a program listing. Use the following commands:
OPEN 1,4
CMD 1
LIST
PRINT#l
CLOSE 1

open the printer
the printer is now linked to the
screen
the directory will be printed
send a RETURN to the printer
dIose the printer again

It is assumed that the directory is already loaded with the
LOAD·S·,8 command before these commands are executed. By
inserting a wildcard when loading the directory, you can
cause only part of the directory to be loaded, such as only
the programs. This is explained in section 1.3.10

1.3.5

SCRATCH - Deleting Files

Sometimes an unneeded file must be removed from the
diskette. The SCRATCH command is provided for doing so.
Before using this command, you must be sure that the name
given in the SCRATCH command corresponds with the file to be
deleted. An unintentionally deleted file can ruin many hours
or even days of work, so he careful before using the SCRATCH
command.

14

Anatomy of the 1541 Disk Drive
To delete a file, the following format should be used:
PRINT'lfn.·SCRATCH: filenamel, filename2 •••• •
More than one file can be deleted by using a single command.
But remember that only 40 characters at a time can be sent
over the transmission channel to the disk drive.
For example, to erase a file
following commands are used:

with

the

name

TEST,

the

OPEN 1.8.l5.·S:TEST·
CLOSE 1
If channel 15 is already open, only the PRINT# command is
required:
PRINTtl.·S:TEST·
It is possible to delete the entire contents of a diskette.
This is discussed in section 1.3.10, the wildcard character
(*) :

PRINT'l.·S:*·
But be very careful! Make sure that you do not need any of
the files on the diskette before using this command. After
completing the operation the error channel transfers the
message:
01 FILES SCRATCHED nn

00

where nn is the number of deleted files. This message can be
read with the routine given in section 1.3.3.

1.3.6

RENAME - Renaming Files

You can also change the name of a file on the diskette. The
command RENAME is provided for this purpose. It has tte
following format:
RENAME:newname=oldname
For example, if you want to change the name of the file from
TEST to PEST you would use the following commands:
OPEN 1.8.l5,·R:PEST=TEST·
CLOSE 1
or

15

Anatomy of the 1541 Disk Drive
OPEN 1,8,15
PRINTfl,-R:PEST=TESTCLOSE I

Note that you cannot rename a file until it is CLOSEd.

1.3.7

COpy - Copying Files

Using this command, a file can by copied on a diskette.
Several different sequential files can be used to create a
new file. If, for example, you have a data record for each
month of your household expenses and they have the names
EXP.Ol, EXP.02, etc. you can combine them into quarters
(EXP.OI for example) with this command. The COpy command has
the format:
COPY:newfile=oldfilel,oldfile2, •••

So, the named data records can be combined as follows:
OPEN 1,8,15,·C:EXP.Ol=EXP.Ol,EXP.02,BXP.03CLOSE I

This method of combining data records cannot be used for
programs. only a single program can be copied on the
diskette. Also the name of the new file must not already
exist on the diskette.
The COpy command is seldom used. This is because copying
files onto the same diskette usually makes no sense. The
only sensible use of the command is to combine several
sequential or user files into a single file.
Copying files from one diskette to another diskette is much
more sensible. This is indispensible for data security. If
you own two disk drives, you can assign the device number 9
to one of them and use the program COPY/ALL to copy files
from one to the other. This program is found on the
TEST/DEMO diskette.
We have also thought of you who have only one disk drive. A
utility program is inclUded in section 4.1 to allow you to
copy individual files and even the entire diskette.

1.3.8

INITIALIZE

Initializing the Diskette

The DOS requires a BAM (Block Allocation Map) to be present
on each disk. The BAM 1S a layout of the usage
of the
blocks on each diskette. It marks each block on the diskette
16

Anatomy of the 1541 Disk Drive
as free for use or allocated (already in use). If you change
diskettes in the drive and the new diskette has the same id
as the old diskette, the DOS will not recognize the fact
that you have changed diskettes. The BAM of the new diskette
will be different, but the DOS will still be working with
the old RAM.
Therefore, each diskette should be given a unique id when
you format it. It is a good practice to give each diskette a
different id. You can force the disk drive to read the BAM
of a new diskette by issuing the INITIALIZE command. This
command has the following format:
PRINT,lfn,"INITIALIZE"
or shortened to
PRINTt1fn,"I"
Example:
OPEN 1,8,15,"1"
CLOSE 1
If you change diskettes and also change data records, then
we strongly recommend that you use the INITIALIZE command
after changing the diskettes, to be safe.

1.3.9

VALIDATE - "Cleaning Up" the Diskette

The command VALIDATE frees all allocated blocks that are not
assigned to normally CLOSEd files. For example, i f you OPIN
a file, and transfer data to that file, but forget to CLOSE
the file, the VALIDATE command can be used to free the data
blocks that were written to. If you use the direct access
commands, be sure to allocate them (using the BLOCK-ALLOCATE
command) or the VALIDATE command will free them again.
The command has an additional function: If a file is deleted
using the SCRATCH command, the file type in the first byte
of the file entry is set to O. It no longer appears in the
directory. If you now change this byte back to its old file
type with the DOS monitor (described later) or other direct
access commands, VALIDATE will restore the file. If it has
not been overwritten, it will be the same as before the
SCRATCH command. The command has the following format:
PRINTt1fn,·VALIDATE"
or the shorter form
PRINTt1fn,·V"
17

Anatomy of the 1541 Disk Drive
An example:
OPEN 1,8,15,-VCLOSE 1
If you have a diskette such that the sum of the file lengtt!s
plus the number of free blocks does not equal the total
number available (664), use the VALIDATE command to restore
it.
Another example: If you want to store a program or data
record that uses more than the number of free blocks, the
DOS will give the error DISK FULL. If the disk had shown
some blocks free before, the number is now zero. The
VALIDATE command will restore the original free blocks.
1.3.10

?

* -

The Wildcards

There are two wildcard characters - the asterisk (*) and the
characters of the first file on the disk that begins with
the characters which precede the asterisk. An example:

This command loads the first program that begins with the
first four letters "TEST". The command:
LOAD-·- ,8
loads the first program on the diskette because there are no
characters in front of the asterisk. The asterisk in the
SCRATCH command has a different effect. If used in the
SCRATCH command, not only the first file will be deleted,
but all files. For instance, the command:
OPEN 1,8,15,-S:TEST·CLOSE 1
erases all files beginning with the the letters "TEST". This
must be taken into account! Loading the directory with an
asterisk can also select certain files. An example:

loads only the directory of the files that begin with the
letter "All.
The DOS offers an additional use of the asterisk that has
not been mentioned yet. It can also select file types if the
asterisk is followed by the first letter of the desired file
type. Here is a summary:

18

Anatomy of the 1541 Disk Drive
*=S
*=p
*=R
*=U

selects
selects
selects
selects

only sequential files
program files .
relative files
user-files

For example, the command:
LOAD ·$*=P·,8
causes only the directory entries of programs to be loaded
and shown when you type LIST. This can also be used with the
SCRATCH command to delete all sequential files, for
instance. Here is the command:
OPEN l,8,15,·S:*=S·
CLOSE 1
With the question mark, certain characters of a file name
can be declared "not relevant". To illustrate the function
of the question mark, here are two examples of shortened
file names and their effects:

A?????
????TEST

-

refers to a six-letter filename of whict
first character is A
- refers to an eight-character filename, the
last four letters of which are TEST

A combination of asterisks and question marks is allowed.
You should notice, however, that an asterisk followed by
question marks has no meaning. Two examples of combinations
of asterisks and question marks:
????*

TEST.??*
TEST-??Ol*=S

-

refers to all file names that have four
characters before a period
- refers to all file names having at least 7
characters, of which the first five are
TEST.
- refers to all sequential files whose names
have at least nine characters, the first
five heing TEST- and the eighth and ninth
being 01

19

Anatomy of the 1541 Disk Drive
1.4

Sequential Data Storage

A disk drive need not be used exclusively for storing programs. If you have written a program that manages a large
quantity of data, you need a fast way of organizing it.
Sequential data storage is not the fastest, but it is the
easiest method of managing data. This method is comparable
to sequential storage on a cassette, which can be maintained
in a program as such:
1. Load the program
2. Read the entire data file into the memory of the computer
3. Work with the data in memory (change, delete, combine)
4. Write the
diskette)

new

file

on an external

medium

(cassette,

5. Exit the program
The maximum number of data items that the program can handle
depends on the size of the computer's memory, because a
single data item cannot be changed or erased directly on the
cassette or diskette. To that end, the entire set of data
items must be read in, changed, and then rewritten again.
Reading and rewriting the data occurs remarkably faster on a
disk drive than on cassette.
It is worth mentioning that programs which work with
sequential data on cassettes can be easily modified to work
with disk. Only the corresponding OPEN commands need be
changed.

1.4.1

The Principle

A sequential data file consists of several data records that
are further divided into fields. The following is a name and
address file and illustrates the principle of sequential
data storage. Individual names and addresses comprise the
data records of this file. A record consists of several
fields (last name, first name, etc.). The structure of the
file looks something like this:
Field 1 : Field 2 : Field 3 : Field 1 : Field 2 : Field 3 :
Data record 1

Data record 2
FILE

20

Anato~y

of the 1541 Disk Drive

Only two records are shown above. The data records of a file
are stored one after another (sequentially) as are the the
fields within each record. The fields and records may be of
any length. For example, field 1 of record 1 may be longer
than field 1 of record 2. This is possible because the
fields are separated from each other by a special character
(the RETURN character), which is generated by the PRINT#
statement. When read back into the computer by the INPUT#
statement, the RETURN character is recognized as a field
separator.
Each field is associated with a variable when written with a
PRINT# statement or read with an INPUT# statement.
How does the computer know, when reading the data, where
each field ends? Each field ends with a RETURN character.
The RETURN character has the decimal ASCII value 13. An
example of a telephone directory file illustrates this. Our
telephone directory file has three fields:
LAST NAME
FIRST NAME
TELEPHONE EXTENSION

FIELD 1
FIELD 2
FIELD 3

Let's look at a section of this previously written file (the
character + symbolizes a RETURN):
position:

1111111111222222222233333333334444444
1234567890123456789012345678901234567890123456

Data:

SMITH+JOHN+236+LONG+TIM+121+HARRIS+SAM+654+ •••

You can see that the fields are of different lengths and are
all separated by a RETURN character. This RETURN character
is automatically written after the data field by a PRINT#
statement, provided the PRINT# statement is not followed by
a semicolon (which suppresses the RETURN character).
These data items are assigned to the variables with an
INPUT# statement. After that, another INPUT# must follow in
order to read the next field, and so on. The following
sections explain the fundamentals of writing programs using
sequential data storage.

1.4.2

Opening a Sequential Data File

To create a sequential data file, you must first OPEN the
file. When opening a file to be written to, the following is
carried out:
1. The diskette is checked to-see if an existing file has
21

Anatomy of the 1541 Disk Drive
the same name. If so, the error message FILE EXISTS is
given by the DOS.
2. The file entry in the directory is written. In the file
type it is noted that this file is not yet CLOSEd. This
appears in a directory listing with an asterisk which
preceeds the file type.
3. A free block is found, into which the first data items
are written. The address (track and sector) of this free
block is stored in the file entry of the directory.
4. The number of blocks in the file is set to 0, because no
blocks of the file have been written yet.
The OPEN command specifies for what purpose (mode) the file
is to be used (reading or writing). The format of the OPEN
command looks like this:
OPEN Ifn.8,sa,-filename.filetype.modeWhen the logical file number is between 1 and 127, a PRINTi
statement sends a RETURN character to the file after each
variable. If the logical file number is greater than 127
(128-255), the PRINT* statement sends an additional linefeed after each RETURN. This is necessary for printers, for
example, that do not provide an automatic line-feed after a
RETURN character.
The secondary address (sa) can bE> a value between 2 and 14.
The secondary address indicates the channel over which the
computer is to transfer data to and from the disk drive.
Secondary addresses 0 and 1 are reserved by the DOS for
saving and loading programs. Secondary address 15 is designated as the command and error channel. Should several files
be open at once, they must all use different secondary
addresses, as only one file can use a channel. If, however,
a file is opened with the secondary address of a previously
opened file, the previous file is closed.
A maximum of 3 channels can be opened with the VIC-1541 at a
time. When utilizing relative data files, the DOS requires 2
channels per file. Therefore, the following maximum
combinations are possible:
or

- 1 relative and 1 sequential file
- 3 sequential files

When specifying the filename to be written to (in the OPEN
command), you must be sure that the fi Ie name does not
already exist on the diskette. If a file that already exists
is to be to opened for writing, an at sign followed by a
colon (@:) must be placed in front of the file name (same as
in the SAVE command). For example:

22

Anatomy of the 1541 Disk Drive
OPEN 1.8,2.-@:ADDRESSES.S.W-

The file type must be given when the file is opened. The
file type may be shortened to one of following:
S
U
P
R

-

sequential file
user file
program
relative file

User files are sequential files that are listed in the
directory with the file type USR. It is not a data file in
the true sense. This file type is usually used when output
that normally goes to the screen (BASIC listing, directory)
is sent to the disk. In section 1.4.6 you find a description
of this technique.
The last parameter (mode) establishes how the channel will
used. There are four possibilities:
W - Write a file (WRITE - section 1.4.3)
R - Read a file (READ - section 1.4.4)
A - Add to a sequential file
(APPEND - section 1.4.4)
M - read a file that has not been closed
("discovered" by us in the DOS listing and
explained in section 1.4.5)
Now open a sequential file with the name SEQU.TEST for
writing:
OPEN 1.8.2.-SEOU.TEST.S.W-

If you now load the directory with LOAD-$-.8 and then LIST
it, you see this file listed with an asterisk before the
file type:

o

SEQU.TEST

*SEO

But you are no longer allowed to close this file! After a
file is OPENed and data written to it, it must be closed
before the directory is loaded!
While a file is open, the command/error channel 15 may be
opened, but when channel 15 is closed, all other channels
are closed as well. You must take note of this.
Now some examples of the OPEN command:
OPEN 1,8,2,"SEOU.TEST,S,R"

- open a sequential file for
reading
- open a user file for writing
- open a program file for
reading

OPEN 2,8,3,"SEOU.TEST,l],W"
OPEN 3,8,4,"TEST,P,R"

23

AnatOItty of the 1541 Disk Drive
OPEN 4,8,5,"SEOU.TEST,S,A"

- open a sequential file for
appending data
- open the unclosed customer
file for reading

OPEN 5,8,6,"CSTMRS.1983,S,M"

1.4.3

Transferring Data Between Disk and Computer

After opening a file for writing, you transfer data to be
stored to the diskette with the PRINTiF statement. This
statement transmits an additional RETURN that is required
for separating data. In the following example, a file is
OPENed, data written to it, and CLOSEd again. PRINT# cen
also be used as a direct command, that is, outside of the
program, so the following commands can be typed one after
the other and executed. Now open a file with the name
"TEST":
OPEN 1,8,2,-TEST,S,WYou should notice that
lit. It signals the fact
write to the file named
name and address record

the red LED on the disk drive was
that a file was OPENed. You can now
TEST. Here is how we would write a
consisting of 4 fields:

PRINT# 1, "SAM"
PRINT#I,"HARRIS"
PRINT#l,"2001 MAIN STREET"
PRINT# 1, "ANYTOWN"
Now these data items have been written to the file so we can
close the file with CLOSE 1. The red LED should go out. In
order to read this data again, you must open the file in the
read mode (R). Because the INPUT# statement cannot be used
directly, a small program must be written:
10 OPEN 1,8,2,"TEST,S,R"
20 INPUT#I,FNS
30 INPUT#!, LN$
40 INPUT#I,ST$
50 INPUT#! ,CTS
60 CLOSE 1
";FN$
70 PRINT"FIRST NAME:
80 PRINT"LAST NAME:
";LNS
90 PRINT"STREET:
";STS
100 PRINT"CITY:
" lCT$
The program is simple to explain:
Line 10

The file TEST is opened for reading

24

Anatomy of the 1541 Disk Drive
Lines 20-50

The data are read in the same order as they
were written. variables are used so that the
data can be printed later.

Line 60

The file is closed.

Lines 70-100

The data are printed out on the screen.

When you enter this program and type RUN, the data will
appear as written earlier, on the screen:
FIRST NAME:
LAST NAME:
STREET:
CITY:

SAM

HAFRIS
2001 MAIN STREET
ANYTOWN

Four INPUTi statements were used to read the data because
the name and address record is composed of four fields. But
when a record is written that has, say, 20 fields, it is
very time-consuming to type out 20 INPUT# statements. A loop
can make this much simpler. This is obvious in this example:
10
20
30
40
50
60
70
80
90

OPEN 1,8,2,"TEST,S,F"
FOR 1=1 TO 4
INPUTU,D$(I)
NEXT I
CLOSE 1
PRINT"FIRST NAME:
", D$ (1)
", D$ (2)
PFINT"LAST NAME:
",D$(3)
PRINT"STREET:
",D$(4)
PRINT"CITY:

Here, instead of four separate string variables, an array
with index 1-4 is used. It should be noted that in BASIC
2.0, if an index higher than 10 is used, the array must be
dimensioned with a DIM statement. Should we want to read in
20 fields, the statement DIM 0$(20) must be given before any
are read.
There are still more ways of shortening input and output of
data. With the INPUT statement for keyboard input, several
variables can be given in one line, separated by commas. For
example:
INPUT FN$.LN$.TE
wi th this statement,
as:

three variables must be entered,

NICHOLAS,MULLER,7465
The read data can be printed on the screen with:
PRINT FN$.LN$.TE

25

such

Anatomy of the 1541 Disk Drive
In this manner, sequential data can be written and later
read back in again. The only difference is that the string
variables containing the data to be written must be
separated by commas enclosed in quotes. For example, if you
wish to write the previous variables to a file, the PRINT#
statement command must changed as follows:

Numeric variables need only be separated with a comma from
the other variables. To read the data, use the command:
INPUTll,FV$,LN$,TE
Because the maximum number of characters read by an INPUT#
statement may not exceed 88, this method of reading is only
marginally useful. If a field in a record is more than 88
characters long, a different statement must be used. This is
the GETI statement, which r.ads each individual character,
one at a time. Suppose you want to read a record of which a
field is 100 characters long. This record can be placed in a
string variable with the following routine:
10
20
30
40
50
60
70
80

OPEN 1,8, ••••••••••••••
D$= ....
FOR 1=1 TO 100
GETll,X$
D$=D$+X$
NEXT I
GETIl,X$
CLOSE 1

At the end of this program, the string variable D$ will
contain the 100 characters of the data field. After opening
a sequential data file, the DOS establishes a pointer that
always points to next character to be read. We assume that
the data was written with a PRINTI statement without a
trailing semicolon, so that a RETURN was written at the end
of the data item. After reading the first 100 characters,
the pointer points to this RETURN. The next GET. in line 70
is necessary to read the RETURN found at the end of the
field. Then the next GET' statement can read the next field
and not the RETURN.
In the above example, we used data records with a constant
length of 100 characters. According to the rules of sequeptial access, the length of data records need not be constant. Since the INPUT. statement can only read a maximum of
88 characters, we will use the GET' statement to recognize
the RETURN as the end of a field. Such a routine looks like
this:
lOOP EN 1, 8 , .•••••••••••••••••••••
20 S$=''''
30 GET#l,X$
40 IF X$=CHRS(13) THEN 80
26

Anatomy of the 1541 Disk Drive
50
60
70
80
90

S$=S$+X$
IF ST<>64 THEN 30
CLOSE l:END
PRINT S$
GOTO 20

Here a file with variable record length is read and printed
on the screen. Naturally, you can use the data in other ways
instead of printing it on the screen.
To avoid the problem of reading data records of more than 88
characters, divide the record into several parts, which you
can combine after reading them.
1.4.4

Adding Data to Sequential Files

If you want to add data to a sequential file, you have to
read the entire file into memory, add the data, and write
the new file back to the diskette again. This is a very
time-consuming process. For this reason, the DOS offers an
easier alternative to add to a sequential data file without
reading the entire file. This is made possible through the
OPEN mode A (Append). If you have a sequential data file, as
in the previous section, you can add data to it by selecting
the A mode in the OPEN command. An example follows.
Give the following commands:
OPEN 1,8,2,"TEST2,S,W"
PRINT#l,"l. DATA RECORD"
CLOSE 1
Now you have a sequential data file containing one data
record. This file can be expanded with tw.o more records as
follows:
OPEN 1,8,2,"TEST2,S,A ft
PRINT#1,"2. DATA RECORD"
PRINT#1,"3. DATA RECORD"
CLOSE 1
Now the file TEST2 has three data records. You can check
this with the following program:
100
110
120
130
140
150

OPEN 1,8,2,"TEST2,S,R"
FOR 1=1 TO 3
INPUTU,DR$
PRINT DR$
NEXT I
CLOSE 1

After the program starts,
printed on the screen.

the data records

27

is read and

Anatomy of the 1541 Disk Drive
You can see that the append A mode makes it quick and easy
to expand a sequential data fileS.

1.4.5

Closing a Sequential File

OPENed data files can be closed with the CLOSE command. This
command has the format:
CLOSE lfn
The parameter Ifn is the
that was used in the OPEN
need to be closed a CLOSE
one. When the last file is
goes out.

logical file number of the file
statement. Should several files
statement must be given for each
closed, the red LED on the drive

As you already know, data is sent to the disk drive over a
channel. This channel uses storage inside the disk (called a
buffer) in which the data transmitted by the computer is
stored. When this buffer is full, its contents are written
to the diskette.
When the file is closed, any data still in the buffer is
written to the diskette. An unclosed file is incomplete and
is also not recognized by the DOS as a properly closed file.
The DOS allows no read access in the R (Read) mode and
responds WRITE FILE OPEN when trying to read an unclosed
file.
This could be a problem if the DOS did not allow read access
to a file. For this reason, the DOS offers the M mode. A
file that is marked as an improperly closed file can be read
in this mode. It is logical to then write these records to a
second file which can then be properly closed. In this way
one can "rescue" a file.
The following program will transfer an improperly closed
file (original file) to a correctly closed file (destination
file) :
100
110
120
130
140
150
160
170
180
190

INPUT"ORIGINAL FILE NAME";S$
INPUT"DESTINATION FILE NAME";D$
OPEN 1,8,2,S$+",S,M"
OPEN 2,8,3,D$+",S,W"
INPUT#I,X$
PRINT#2,X$
IF ST<>64 THEN 140
CLOSE I:CLOSE 2
OPEN l,8,15,"S:"+S$
CLOSE 1

At the completion of the program, the unneeded original file
28

Anatomy of the 1541 Disk Drive
is deleted

1.4.6

(scratched).

Redirecting the Screen Output

Any output appearing on the video screen (PRINT, LIST, etc)
can be redirected to a sequential data file. This is acconplished through the CMD command, which has the following
format:

CMD Ifn
For this to occur, a file of type USR must be opened. To
transfer a BASIC program listing, for instance, as a
sequential file on diskette, use the following commands:
OPEN 1,8,2,"TEST.LIST,U,W"
CMD 1
LIST
CLOSE 1
The command CLOSB 1 causes further output to be sent to the
screen.
Storing a program as a sequential file on disk is very
useful, if, for example, you would like to read a program
with a word processor to edit it. It is assumed that the
word processor in this case reads data stored in ASCII code.
This is how the listings in this book were transferred from
a Commodore 64 to a Commodore 8032.
In order to print this file on the screen again, you need
the following routine:
10
20
30
40
50

OPEN 1,8,2,"TEST.LIST,U,R"
GET#l,X$
PRINT X$
IF ST<>64 THEN 20
CLOSE 1

This routine is a loop that reads every character (byte) of
the file and displays it on the screen. The end of the file
is signalled by the status variable which is set to 64 at
the end. To send a sequential file to the printer, use the
following program:
10
20
30
40
50
60

OPEN 1,8,2,"TEST.LIST,U,R"
OPEN 2,4
GETU,X$
PRINT#2,X$
IF ST<>64 THEN 30
CLOSE 1
29

Anatomy of the 1541 Disk Drive
Here it assumed that the printer is connected as device
address 4.

1.4.7

Sequential Files as Tables in the Computer

Sequential data files must reside completely in the computer
for data management. Most of the time, a two dimensional
table can be used. This table is also called an array or
matrix, because a data element can be addressed through the
input of two coordinates. To this end, you use a two dimensional variable, which must be reserved with a DIM statement. The first dimension corresponds to the data record,
the second dimension to the field inside the record. The
following diagram shows an example of a table:
Field 1
Field 2
Field 3
Record 1
Record 2
Record 3
Record 4
Record 5
Record 6

~-----------------------------------------~

~
DSIl,l)
~
0$11,2)
~
0$(1,3)
~
~-----------------------------------------~
"
0$ ( 2 ,1)
"
0$ ( 2 ,2)
~
0$ (1 ,3)
"
~-----------------------------------------~
~
0$(3,1)
~
0$(3,2)
~
0$(3,3)
~

~-----------------------------------------~
~

0$(4,1)

~

0$(4,2)

~

0$14,3)

~

~-----------------------------------------~

"

oS I 5 , 11

~

DS ( 5 ,2)

"

oS ( 5,3)

"

~-----------------------------------------~

"

D$16,1)

"

D$(6,2)

"

D$16,3)

~

~-----------------------------------------~

This table is a file composed of six records which have
three fields each. The variable 0$ is reserved with DIM
D$(6,3). To read a sequential file as a table, it is
necessary to create such a file with, for example, six
records with three fields each. For this purpose, use the
following program:
100
110
120
130
140
150
160
170
180
190
200
.210

OPEN 1,8,2,"TABFILE,S,W"
FOR X=l TO 6
PRINT CHR$(147)
PRINT"RECORD ";X
PRINT"---------"
FOR Y=l TO 3
PRINT"FIELD ";Y;": ":
INPUT X$
PRINTU,X$
NEXT Y
NEXT X
CLOSE 1

Two nested loops are used here, whose variables are numbered
wi th the record and field. Enter six data records. When the
program is done, these records will be contained on the
30

Anatomy of the 1541 Disk Drive

diskette with the filename of TABFILE. A tip: save this
program with SAVE-TABPROG-,8 so. you can use it later.
This file can now be loaded into the computer as a table.
Two nested loops indexed for the table are necessary:
100
110
120
130
140
150
160
170

OPEN 1,8,2,"TABFILE.SEO,S,R"
DIM 0$(6,3)
FOR X=l TO 6
FOR Y=l TO 3
iNPUTtl,D$(X,Y)
NEXT Y
NEXT X
CLOSE 1

This program places data into the table. You can check this
with a PRINT statements, to see if the data has been stored
in the right place. Because each field can be addressed with
indices, you can give a command like PRINT 0$(1,2) to see
the second field of record one. It is meaningful to be able
to display the fields of a given record. Use the following
routine for this purpose, after you have saved the previous
program:
100
110
120
130
140

INPUT"RECORD NUMBER: ":X
PRINT"------------------"
PRINT"FIELD 1: ":D$(X,l)
PRINT"FIELD 2: ":D$(X,2)
PRINT"FIELD 3: ":D$(X,3)

Notice that the first index (the record number) after the
question is used as the variable in the field output. The
second index (field number) is then constant.
This table can now be altered as desired. Add the following
lines to the preceeding program:
160
170
180
190
200
210
220
230
240

PRINT"------------------"
INPUT"FIELD TO CHANGE:":Y
INPUT"NEW CONTENTS:
":D$(X,y)
PRINT"OK"
PRINT"FURTHER CHANGES (yiN)?"
GET X$:IF X$="" THEN 210
IF X$="Y" THEN 100
IF X$="N" THEN END
GOTO 210

Here the number of the field to be changed is used as the
second index, which is adjacent to the index of the desired
record to input the new table element.
This modified table must now be written to the diskette
again. You can use the following routine. Don't forget to
save the previous edit program first!

31

Anatomy of the 1541 Disk Drive
100
110
120
130
140
150
160

OPEN 1,8,2,"@:TABFILE,S,W"
FOR X=1 TO 6
FOR Y=l TO 3
PRINT#l,D$(X,Y)
NEXT Y
NEXT X
CLOSE 1

This routine also is relatively short because of the use of
nested loops. The @: in line 10 is necessary in order to
overwrite the existing file.
Accessing data through the use of the table is very fast.
The access time is independent of the size of the table. The
size of the table and therefore the quantity of data is
dependent on the memory capacity of the computer, however.
The large storage area of the Commodore 64 is excellent for
table management. If you write a data management program
that occupies 8K bytes, then 30K bytes still remain for
storing data. If you consider that storing a name and
address record of about 80 characters, you can still store
384 records in memory! And this with an access time that
cannot be surpassed by refined data management techniques
(indexed sequential, relative). But with larger quantities
of data, sequential storage is no longer feasible.

1.4.B

Searching Tables

As mentioned in the table processing section, each data
record of a table can be indexed. Because the table is two
dimensional, the first index selects the data record. If a
record of the table is to be changed or accessed, the
operator must know the record number. The record number can
be a part or customer number. There are files, however, for
which there is no suitable method of numbering. In such
files, the number of the record must be found through a
search of all the records. Here is a practical example:
First of all, create a data file with the following program.
Names and telephone numbers are saved in the example:
100
110
120
130
140
150
160
170
180
190

OPEN 1,B,2,"TELEDAT,S,W"
PRINT CHR$(147)
INPUT"LAST NAME
:";LN$
INPUT"FIRST NAME
:";FN$
INPUT" AREA CODE
:"; AC$
INPUT"NUMBER
:";NU$
PRINT"INFORMATION CORRECT (YIN),?"
GETX$:IF X$="" OR X$<>"Y" AND X$<>"N" THEN 170
IF X$="N" THEN 110
PRINT'l,LN$","FN$","AC$","NU$
32

Anatomy of the 1541 Disk Drive

200
210
220
230
240

PRINT"MORE INPUT (yiN)?"
GETX$:IF X$="II OR X$<>'Y' AND X$<>"N" THEN 200
IF X$="N" THEN 240
GOTO llO
CLOSE 1

Program Documentation:
Line 100

The sequential file "TELEDAT" is opened for
writing

Line 110

The screen is cleared

Lines 120-150

The four fields are entered from the keyboard

Lines 160-lBO

If the data are not correct, they can entered
again

Line 190

The four fields are written to disk

Lines 200-220

Here the execution of the program can be
ended

Line 230

Input will be continued

Line 240

The file opened in line 100 is closed

Type this program in, RUN it, and enter some data. Save the
the program on diskette, so you can combine it with other
routines later if you like. In the last section of this
chapter, is a complete program for managing your telephone
numbers.
If you have entered some data, you would probably like to
find a telephone number. To do so, you could print the
entire file on the screen or printer and find it yourself.
This is, however, a wasteful method, especially if you have
entered many records.
The search for the telephone number corresponding to a given
name can be performed by the computer. It runs through the
who~e list, looking for the desired name. Once found,
it
gives you the complete record which contained that name. The
following routine accomplishes this:
100
110
120
130
140
150
160
170
IBO
190

OPEN l,B,2,"TELEDAT,S,R"
DIM D$(100,4):X=1
INPUT*l,D$(X,l),D$(X,2),D$(X,3),D$(X,4)
IF ST<>64 THEN X=X+l:GOTO 120
CLOSE 1
PRINT CHR$(147)
PRINT"DESIRED NAME: n:N$
FOR 1=1 TO X
ID D$(I,l)=N$ THEN 210
NEXT I
33

Anatomy of the 1541 Disk Drive

200
210
220
230
240
250
260
270
280
290
300
310

PRINT"NAME NOT FOUNDI":GOTO 280
PRINT"NAME FOUND:"
PRINT"------~----"

PRINT"LAST NAME:
PRINT"FIRST NAME:
PRINT"AREA CODE:
PRINT"NUMBER:

"lD$(I,l)
"lD$(I,2)
"10$(1,3)
"lD$(I,4)

PRINT"-~---------"

PRINT"MORE (YIN)?"
GETX$:IF X$="" OR X$<>"Y" AND X$<>"N" THEN 290
IF X$="Y" THEN 150
PRINT"PROGRAM DONE":END

program Documentation
Line 100

The sequential file uTELEDAT" is opened for
reading

Line 110

The table is dimensioned for 100 records and
the index is set to one

Line 120

The data records are read into the table

Line 130

The status variable ST is checked for end of
file (indicated by a value of 64). If the
end has not been reached, the index is
incremented and a new record is read.

Line 140

The file opened in line 100 is closed

Line 150

The screen is cleared

Line 160

The last name to be searched for is read from
the keyboard and placed in the variable N$

Lines 170-190

The loop
checking
name. If
branches

Line 200

The name was not found

Lines 210-270

The record containing the desired name is
displayed

Lines 280-310

The possibility to search for a new name is
allowed

searches the table of records,
the name fields against the desired
the position is found, the program
to the output routine

You will notice that this search is quite fast when the data
is already loaded into the computer •. Searching the
computer's memory is faster than searching the diskette. The
program can be easily changed to search for a .desired field
other than the name. You might want to search for an area
code, fOr instance. The first program stops the search when
the first matching data record is found. This is not always
34

Anatomy of the 1541 Disk Drive
desired, however. If, for instance, you wish to search the
table looking for a particular area code and want all
matches to be displayed, a different routine is needed. The
routine must continue the search after the first match is
found. The next program takes care of this:
100
110
120
130
140
150
160
170
180
190
200
210
220
230
240
250
260
270
280
290
300

OPEN 1,8,2,"TELEOAT,S,R"
DIM D$(100,4) :X=l
INPUT#1,D$(X,1),0$(X,2),0$(X,3),0$(X,4)
IFST<>64 THEN X=X+l:GOTO 120
CLOSE 1
PRINT CHR$(147)
PRINT"AREA CODE TO SEARCH FOR: ",AC$
FOR 1=1 TO X
IF D$(I,3)=AC$ THEN 210
NEXT I
PRINT"ENO OF OATA!":GOTO 270
PRINT"----------------n
PRINT"LAST NAME:
",0$ (1,1)
PRINT"FIRST NAME:
",0$(1,2)
PRINT" AREA COOE:
",0$ (1,3)
PRINT"NUMBER:
",0$(1,4)
PRINT"----------------"
PRINT"MORE (Y/N)?U
GETX$:IF X$="" OR X$<>"Y" AND X$<>"N" THEN ;280
IF X$="Y" THEN 190
PRINT"SEARCH OONE!":END

Here the search is continued if a record with the
appropriate area code is found. This happens in line 290,
which branches back to the loop instead of ending the
program. After searching all of the records, the program
responds ENO OF DATA. If you understand the operation of
this program, you can now develop a search for the last
name. with the help of the previous programs, this should
present no difficulty.

1.4.9

Simple Sorting of Tables

In data processing, it is often necessary to sort data into
numeric or alphabetic order. This has always been a time
consuming task, which the programmer has tried to shorten ty
using better sorting methods. Sorting is certainly a time
consuming task when performed with the programming language
BASIC, which is relatively slow.
Why should we sort the data at all? suppose you had a
telephone book in which the names were not ordered. You
would have search the entire book from beginning to end to
find a name. Sorting offers advantages when searching data.
The computer can also search sorted data faster.

35

Anatomy of the 1541 Disk Drive
There are several search methods which differ mainly in
their speed of execution. The simplest method compares each
data item with every other. If a table is supposed to be
sorted in ascending order, the first item in the table is
compared to the second. If the first is greater, it is
exchanged with the second. After that, the first will ce
compared to the third, and SO on, until the last item is
reached. Now the smallest item is at the beginning, in the
right place. The next time through, the first item is no
longer needed. A flowchart of the program logic appears
below.

TA(I)

>

TA(X)?

No

1(----0( X

No

~------< I

> max?

max?

Yes
END

36

Yes

TA(O)=TA(I)
TA(I)=TA(X)
TA( X) =TA( 0)

Anatomy of the 1541 Disk Drive

This sort program starts using an index of 1, which is
stored in the variable I. The second index is the variable
x, which receives a value one greater than I. Then the first
item is compared to the second. If the value of TA(I) is
greater then TA(X), the program must use a temporary
variable, TA(O), to make the exchange between the two. After
this, the value of X is incremented, to three, and TA( I) is
again compared to TA(X), etc. When the last item in the
table is reached, (X > last index), the first item will be
the smallest, and the index I is incremented by one. Now the
second item is compared to every other (starting with the
third), and so on.
This sort method looks quite complicated at first glance.
Comparisons in memory are done relatively quickly, however.
This method is sufficient for small quantities of data.
In order to run this program, a table must be built. This
example uses a table with twelve items containing alphanumeric data (strings). The table is filled by the following
routine:
100
110
120
130

DIM TA$ (12)
FOR 1=1 TO 12
INPUT TA$(!)
NEXT I

This program allows you to enter twelve strings, which are
then sorted with the following program:
140
150
160
170
180
190
200
210
220
230
240

1=1
X=I+l
IF TAS(I) < TA$(X) THEN 180
TA$(O)=TA$(I):TAS(I)=TA$(X):TA$(X)=TA$(O)
X=X+l
IF X <= 12 THEN 160
1=1+1
IF I <> 12 THEN 150
FOR 1=1 TO 12
PRINT TAS(12)
NEXT I

The table is sorted and displayed on the screen. If, instead
of a one dimensional table, you want to sort a two
dimensional table such as our telephone file, exchange the
fields by changing lines 160-170 as below:
160 IF DS(I,l) < D$(X,l) THEN 180
170 DS(O,l)=D$(I,l):D$(I,l)=DS(X,l):
D$(X,l)=DS(O,l)
171 D$(0,2)=D$(I,2):DS(I,2)=D$(X,2):
D$(X,2)=D$(O,2)
172 D$(0,3)=DS(I,3):D$(I,3)=DS(X,3):
D$ (X, 3 ) =DS ( 0 ,3)
173 D$(0,4)=D$(I,4):D$(I,4)=D$(X,4):
DS(X,4)=D$(0,4)
37

Anatomy of the 1541 Disk Drive
It is very time consuming to sort a greater amount of data
with this method. If you have a large amount of data to be
sorted, we recommend that you use the very fast machine
language sort routine from our book Commodore 64 Tips &
Tricks.

1.4.10 MAILING LIST MANAGEMENT with Sequential Data Storage

At the end of this section, is a mailing list management
program that every user will hopefully find easy to use. At
the same time, this program provides insight into the operation of many data processing techniques.
A mailing list record of
following fields:
-

this program consists of

the

NAME 1
NAME 2
STREET
CITY, STATE
ZIP CODE
TELEPHONE NUMBER
NOTES

The use of the fields 'NAME I' and 'NAME 2' are up to the
user. For instance, 'NAME I' can be the first name and 'NAME
2' the last name, or 'NAME I' the company name and "to the
attention oL •• " in 'NAME 2'. The field 'NOTES' can be used
for grouping the addresses (family, business, friends,
etc.).
The program offers the following Main Menu options:
-1-2-3-4-5-6-0-

LOAD DATA
SAVE DATA
INPUT DATA
EDIT DATA
SELECT/PRINT DATA
DELETE DATA
END PROGRAM

-1- LOAD DATA
Use this function to enter the name of the mailing list
file that is to be maintained. If the file exists on the
diskette, it is loaded and ready to be used. The number
of records in the file is displayed. If an error is
encountered while loading, or if the file does not exist,
the message DISK ERROR! is displayed. At the conclusion
of this function, the Main Menu reappears.

38

Anatomy of the 1541 Disk Drive
-2- SAVE DATA
Use this function to write an updated or expanded copy of
the mailing list to the diskette. If
the file name
already exists, then the file is overwritten.
The mailing list should be saved often while using the
program in case a power outage should erase the
computer's memory. After saving, the file can be used
further, without having to reload it in.again.
-3- INPUT DATA
Use this function to add records to the mailing list:
1.

When no data has been previously loaded.
First a file name for the mailing list is entered.
Enter a file name which does not already exist on the
diskette or the old file is overwritten. All records
that are inputted are new to the mailing list.

2.

When data has been previously loaded.
All records that are inputted are added to the
existing mailing list.

After entering an mailing list entry, the message CORRECT
(Y/N)? is displayed. Here you may correct the data. If
the entry is not correct, press the N key. If the entry
is correct, press Y. Now the message MORE INPUT (Y/N)? is
displayed. If you want to enter another mailing list
entry, press Y. If you press N, the Main Menu appears
again.
-4- EDIT DATA
Use this function to change existing mailing list records. Both Name 1 and Name 2 must be entered. If both
nawes are not known, the other can be found with the
SELECT/PRINT DATA routine. After entering the names, the
mailing list is searched for matching names. When they
are found, the complete address is displayed with the
fields numbered. Now you must enter the number of the
field which you want to change. The new contents are
requested. The record is once again displayed in its
updated form. If no more changes to this record are
required, press 9. The program asks if another record is
to be changed. This question is to be answered by
pressing Y or N.

39

Anatomy of the 1541 Disk Drive
-5- SELECT/PRINT DATA
Use this function to search for certain records and print
or display them. You must first specify if the selected
records are to be
printed on the screen (S) or the
printer (P). If you have selected the printer, you must
again choose if the data is to be printed with all fields
on normal paper (P), or if fields 1-5 are to be printed
on mailing labels (M). The address labels must be in a
single column and measure 89mm x 36mm.
In order to select the data, enter search criteria.
For
fields which are not relevant, simply press RETURN. If,
for example, you want to find all addresses in Grand
Rapids, press RETURN for the first three fields and type
GRAND RAPIDS, MI for the fourth, and press RETURN for the
next three.
An example:
NAME 1
NAME 2
STREET
CITY, STATE
ZIP CODE
TELEPHONE NUMBER
NOTES

M






FAMILY

All family merobers whose name 1 begins with 'M' will be
displayed.
You can see how versatile this search is. Try it out
yourself.
-6- DELETE DATA
Use this function to delete records. After entering the
first and second names of the record, the record is reed
and the remaining fields are displayed. Then you are
asked to confirm that the record is to be deleted. If you
press Y, the record is deleted.
-0- END PROGRAM
Use this function to leave the prograro. Before the
program is ended, you are reminded that you can restart
the program without losing data by typing GOTO 110. This
is important if you forget to save the data before ending
the program.

40

Anatomy of the 1541 Disk Drive
Here is the program listing:
100
110
120
130
140
150
160
170
180
190
200
210
220
230
240
250
260
270
280
290
300
310
330
340
350
360
370
380
390
400
410
420
430
440
450
460
470
480
490
500
510
520
530
540
550
560
570
580
590
600
610
620

POKE 53280,5:POKE53281,2:PRINTCHR$(158),:DIMD$(100,7)
GOSUB2030
PRINT"SELECT THE DESIRED FUNCTION:"
PRINT"----------------------------":PRINT
PRINT"
-1- LOAD DATA"
PRINT"
-2- SAVE DATA"
PRINT"
-3- INPUT DATA"
PRINT"
-4- EDIT DATA"
PRINT"
-5- SELECT/PRINT DATA"
PRINT"
-6- DELETE DATA":PRINT
PRINT"
-0- END PROGRAM"
PRINT
PRINT"
CHOICE (0-6)?"
GETX$:IFX$<"0"ORX$>"6"THEN230
IF X$<>"0"THEN340
PRINT:PRINT"
ARE YOU SURE (Y/N)?"
GETX$:IFX$<>"N"ANDX$<>"Y"THEN260
IFX$="N"THENI10
GOSUB2030
PRINT"THE PROGRAM CAN BE RESTARTED WITH
PRINT"
'GOTO 110'"
PRINT"
WITHOUT LOSS OF DATA"
END
ONVAL(X$)GOSUB360,540,680,880,1190,1770
GOTO 110
REM *********
REM LOAD DATA
REM *********
GOSUB 2030
INPUT"NAME THE FILE :",FN$
OPEN 15,8,15
OPENl,8,2,FN$+",S,R"
INPUTiI5,FE:IF FE=O THEN 460
PRINT"DISK ERROR!"
GOTO 510
X=l
INPUTil,D$(X,l) ,D$(X,2) ,D$(X,3) ,D$(X,4) ,DS(X,5) ,D$(X,6),
D$(X,7)
IF ST<>64 THEN X=X+l:GOT0470
PRINT"FILE IS LOADED AND CONTAINS",X,"RECORDS."
PRINT
CLOSE:CLOSE15
PRINT"RETURN FOR MORE"
INPUTX$:RETURN
REM *********
REM SAVE DATA
REM *********
IF X>O THEN 590
GOSUB2230:RETURN
GOSUB 2030
OPEN 1,8,2,"@:"+FN$+",S,W"
FORI=lTOX
PRINT#1,D$(I,1)","D$(I,2)","D$(I,3),
41

Anatomy of the 1541 Disk Drive
630 PRINT#1,D$(I,4)","D$(I,5)","D$(I,6)","D$(I,7)
640 NEXT
650 PRINT"DATA IS SAVED":CLOSE1:RETURN
660 PRINT"RETURN FOR MORE"
670 INPUTX$:RETURN
680 REM **********
690 REM INPUT DATA
700 REM **********
710 IFX>OTHEN730
720 GOSUB2030:INPUT"FILENAME ",FN$
730 X=X+l
740 GOSUB2030
750 PRINT"INPUT DATA:"
760 PRINT"-----------":PRINT
770 I=X:GOSUB2110
780 FORI=lT07:PRINTCHR$(145),:NEXT
790 FORI=lT07:PRINTTAB(12);:INPUTD$(X,I):NEXT
800 PRINT:PRINT"CORRECT (YIN)?"
810 GETX$:IFX$<>"N"ANDX$<>"Y"THEN810
820 IFX$=" y"THEN840
830 GOTO 740
840 PRINT"MORE INPUT (YIN)?"
850 GETX$ :IFX$O"N"ANDX.$O"Y"THEN850
860 IFX$="Y"THEN730
870 RETURN
880 RE.M *********
890 REM EDIT DATA
900 REM *********
910 IF X>OTHEN930
920 GOSUB2230:RETURN
930 GOSUB2030
940 INPUT"NAME 1: ",Nl$
950 INPUT"NAME 2:
",N2$
960 FORI=lTOX
970 IF D$(I,1)=N1$ANDD$(I,2)=N2$THEN1010
980 NEXTI
990 PRINT-NAME NOT FOUND!"
1000 PRINT"RETURN FOR MORE":INPUTX$:RETURN
1010 GOSUB2030
.1020 PRINT"-l- NAME 1
:";0$(1,1)
:";D$(I,2)
1030 PRINT"-2- NAME 2
1040 PRINT"-3- STREET
:"; 0$ (1,3)
1050 PRINT"-4- CITY, STATE :",D$(I,4)
:";0$(1,5)
1060 PRINT"-5- ZIP CODE
:"; 0$ (1,6)
1070 PRINT"-6- TELEPHONE
:";D$(I,7)
1080 PRINT D -7- NOTES
1090 PRINT"NO. OF FIELD TO CHANGE: ":PRINT"(9=NO
CHANGES)"
1100 GETX$ :IFVAL(X$) <10RVAL(X$) > 7 AN DVA L( X$) o9THENll00
1110 IFVAL(X$)=9THEN1150
1120 Y=VAL(X$)
1130 INPUT"NEW CONTENTS",D$(I,Y) :PRINT
1140 GOTO 1010
1150 PRINT"MORE CHANGES (YIN)?"
1160 GETX$ :IFX$<>"y"ANDX$<>"N"THEN1160

42

Anatomy of the 1541 Disk Drive
1170
1180
1190
1200
1210
1220
1230
1240
1250
1260
1270
1280
1290
1300
1310
1320
1330
1340
1350
1360
1370
1380
1390
1400
1410
1420
1430
1440
1450
1460
1470
1480
1490
1500
1510
1520
1530
1540
1550
1560
1570
1580
1590
1600
1610
1620
1630
1640
1650
1660
1670
1680
1690
1700

IFX$="Y"THEN880
RETURN
REM *****************
REM SELECT/PRINT DATA
REM *****************
IF X>OTHENI240
GOSUB2230:RETURN
GOSUB2030:PRINT"OUTPUT TO PRINTER (P) OR SCREEN (S)?"
GETX$:IFX$<>"S"ANDX$<>"P"THENI250
O$=X$:IFO$="S"THENI300
PRINT:PRINT"PAPER (P) OR MAILING LABELS (M)?"
GETX$:IFX$<>"P"ANDX$<>"M"THENI280
D$=X$
GOSUB2030
PRINT"ENTER THE SEARCH DATA:"
PRINT"PRESS RETURN BY IRRELEVANT FIELDS."
PRINT"----------------------------------":PRINT
I=O:GOSUB2110
.
FORI=IT07:PRINTCHR$(l45): :S$(I)="":NEXT
FORI=IT07:PRINTTAB(12)::INPUTS$(I):NEXT
IFO$="S"ORD$="M"THENI450
GOSUB2030:PRINT"PRINTER READY (Y)?"
GETX$:IFX$<>"Y"THENI390
OPEN 1,4
PRINTlI 1, "NAME 1": SPC( 8) : "NAME 2": SPC( 8) : "STREET":
SPC(lO) :
PRINT1I1,"CITY, STATE";SPC(4):"ZIP CODE TELEPHONE NOTES"
FORI=IT079:PRINTlIl,"="::NEXT:PRINT#1
CLOSEI
FORI=ITOX
FORY=IT07
IFS$(Y)=LEFT$(D$(I,Y),LEN(S$(Y»)THENZ=Z+I:GOTOI480
NEXTY
IFZ=7THENGOSUB1550
Z=O:NEXTI
PRINT:PRINT"END OF DATA!":PRINT
PRINT"RETURN FOR MORE":PRINT
INPUTX$
RETURN
IFO$="S"THEN1730
IFD$="M"THEN1670
OPENl,4
PRINTil,D$(I,1);SPC(14-LEN(D$(I,1»):
PRINTlIl,D$(I,2):SPC(14-LEN(D$(I,2»):
PRINTi1,D$(I,3);SPC(16-LEN(D$(I,3»);
PRINTlIl,D$(I,4):SPC(15-LEN(D$(I,4»);
PRINT#I,D$(I,5);SPC(8-LEN(D$(I,5»):
PRINTlIl,O$(I,6);SPC(12-LEN(D$(I,6»);
PRINTil,O$(I,7)
PRINTi1:CLOSEI
RETURN
OPEN2,4
PRINTlI 2
FORJ=IT05:PRINTlI2,O$(I,J) lNEXT
PRINT#2:PRINT1I2~PRINT1I2

Anatomy of the 1541 Disk Drive
1710
1720
1730
1740
1750
1760
1770
1780
1790
1800
1810
1820
1830
1840
1850
1860
1870
1880
1890
1900
1910
1920
1930
1940
1950
1960
1970
1980
1990
2000
2010
2020
2030
2040
2050
2060
2070
2080
2090
2100
2110
2120
2130
2140
2150
2160
2170
2180
2190
2200
2220
2230
2240
2250
2260

CLOSE2
RETURN
GOSUB2030:GOSUB2110
PRINT:PRINT"MORE (Y)?"
GETX$: IFX$<>" y"THEN17 50
RETURN
REM ***********
REM DELETE DATA
REM ***********
IFX>OTHEN1820
GOSUB2230:RETURN
GOSUB2030
INPUT"NAME 1 : ";N1$
INPUT"NAME 2 : ";N2$
FORI=lTOX
IFO$(I,1)=Nl$ANOO$(I,2)=N2$THEN1900
NEXTI
PRINT"NAME NOT FOUND!":PRINT
PRINT"RETURN FOR MORER:INPUTX$:RETURN
GOSUB2030:GOSUB2110
PRINT:PRINT"OELETE RECORD (yiN)?"
GETX$:IFX$<>"Y"ANOX$<>"N"THEN1920
IFX$=RN"THENRETURN
FORY=ITOX-l
FORJ=lT06
D$(Y,J)=D$(Y+l,J)
NEXTJ,Y
FORJ=lT06:0$(X,J)="":NEXTJ
X=X-l
PRINT"RECORD IS DELETED!"
PRINT"RETURN FOR MORE"
INPUTX$:RETURN
REM ***************
REM PROGRAM HEADING
REM ***************
PRINTCHR$ ( 14 7) ;
PRINTTAB(8);"======================="
PRINTTAB(8);"M A I LIN G
LIS T
PRINTTAB(8);"======================="
RETURN
REM ************
REM PRINT RECORD
REM ************
";D$(I,1)
PRINT"NAME 1
";0$(1,2)
PRINT"NAME 2
PRINT"STREET
";0$(1,3)
PRINT"CITY, STATE
";0$(1,4)
PRINT"ZIP CODE
";D$(I,5)
PRINT"TELEPHONE
";0$(1,6)
";0$(1,7)
PRINT"NOTES
RETURN
REM ********
REM NO DATA!
REM ********
GOSUB2030

Anatomy of the 1541 Disk Drive

2270 PRINT"NO DATA IN MEMORY1":PRINT
2280 PRINT"RETURN FOR MORE"
2290 INPUTX$:RETURN

1.4.11 Uses for Sequential storage

The great advantage of sequential storage as compared to
relative and direct access storage, is that a lot of data
can be written to the diskette quickly. Data of varying
lengths can be stored together, without requiring the records to be of a defini te length. It makes sense to make u~e
of th is advantage, where the the file must not be
permanently divided into parts. Examples are:

*

Bookkeeping files
In a bookkeeping journal, all entries are recorded
continuously. Changes should not be made to these
entries. Instead, adjustment entries should be made
to effect changes.

* Analysis files
You analyze a direct access file, looking for, say, all
customers with whom you have done more than 2000
dollars of business in a certain zip code, and write
the found records in a sequential file for later
access.
Naturally, sequential files also offer a substitute for
direct access files, as discussed in this chapter, if the
user does not possess further programming knowledge. we must
certainly recommend that you work through the other methods
of data storage, which offer other advantages.

45

Anatomy of the 1541 Disk Drive
1.5

Relative Data Storage

Relative data storage and its programming is not described
in the VIC-1541 user's manual. The reason may lie in the
fact that the Commodore 64 and the VIC-20 have no commands
to process relative files using BASIC 2.0. Therefore, it is
in principle not possible to use relative data storage on
the Commodore 64 and VIC-20 - but only in principle. We have
developed a few tricks that work within the limitations of
BASIC 2.0 and permit the Commodore 64 and also the VIC-20 to
use relative data storage. The examples may seem to be
somewhat complicated at first. For example, information
about the record lengths will be transmitted to the disk
using CHR$(x) codes. But they provide for a very easy method
of data storage.

1.5.1 The Principle
When using relative record data processing, the data records
are numbered. It is assumed that all records in a relative
file have the same length and that the record number of
every record is known or can be calculated. To find a
record, it is not necessary to search through the entire
file. Only the record number need be given to access the
record. Using the record number, the DOS can find where the
record is "relative" to the beginning of the file on the
diskette and can read it directly. Therefore, you don't have
to read an entire file into the computer, only the desired
records.
Managing a relative file follows this pattern:
Create a relative file:
1. The file is opened. With this the length of a record
is established.
2. The last record is marked.
3. The file is closed.
Writing a record:
1.
2.
3.
4.

The
The
The
The

file is opened.
file is positioned on the record to be written.
record is written.
file is closed.

Reading a record:
1.
2.
3.
4.

The
The
The
The

file is opened.
file is positioned over the record to be read.
record is read.
file is closed.
46

Anatomy of the 1541 Disk Drive

This is only an outline. In the following sections these
processes will be explained in detail.

1.5.2 The Advantage over Sequential Storage
The greatest adVantages of relative storage are:

*

faster access to individual records

* does not require much of the computer's memory

It has already been mentioned that the sequential file must
reside completely in the computer's memory for processing.
Using sequential techniques, it may be necessary to search
the entire file to find a given record. The record must be
read and compared during the search process. But if a
sequential file cannot be entirely loaded into memory, this
method of search is impossible.
Using relative data files, the processing is much simpler.
By using the record number, a desired record can be read
individually. The file size is not limited to the computer's
memory. So, for example, a program that uses all 3.5K bytes
of a standard VIC-20 can manage a file with up to 163
Kbytes!
The advantages of relative over sequential file management
are large enough that many of you, once acquainted with the
techniques will prefer to use them.

1.5.3

Opening a Relative File

Relative files are also opened with the OPEN command. The
command differs only slightly from that for sequential
files. Take a look at the format of the OPEN command:
OPEN Ifn,da.channel. -fi lename,L. -+CHR$ (recordlength)
The first four parameters are identical to those for
sequential files. They are logical file number, device
address (normally 8), channel (2-14), and name of the file.
Next follows an L which informs the DOS that a relative file
should be opened, whose record length follows. This record
length is transmitted with a CHR$ code. The length is
between one and 254. Thus each record of a relative file is
limited to a maximum of 254 characters.
If the record length is smaller than 88, the record can be
read with an INPUT# statement. For this, it is necessary

47

Anatomy of the 1541 Disk Drive
that the PRINT# statement transfers the record with a
tr.ailing RETURN. A PRINT# statement sends a RETURN when it
is not ended with a semicolon. This RETURN is now a part of
the record. When you want to read records with INPUT#, the
record length must be increased by one.

A file composed of 80-character records, to be read by the
INPUT# statement would be opened as follows:
OPEN l,8,2,"FILE.REL,L,"+CHR$(8l)
Here a relative file with the name "FILE.REL" is opened
using channel 2. The record length should total 81
characters. Records comprised of 80 characters should be
sent with a PRINT# statement, with no trailing semicolon.
It is important to note that only
opened at a time. If you want to
files, you must always close the
second. One sequential file may be
relative file.

one relative file can be
work with two relative
first before opening the
opened in addition to one

When a relative file is opened fpr the first time, the DOS
as many "null" or unused records that can fit in a
single 254 byte block. It creates these "null" records by
writing a record with a CHR$(255) at the beginning of each
record. This is called formatting a relative file.

cre~tes

If you want to expand a relative file beyond the initial
number of records that the DOS formatted, then you can
reference the last record number that you want to write (by
positioning to that record number) and the DOS automatically
formats the"records between the current end of file and the
new last record number by writing records containing
CHR$(255). Formatiing takes time to complete.
If you try to read a record whose number greater than that
of the last record, the DOS returns the error RECORD NOT
PRESENT. However, if you write a record which is greater
than the highest current record, all records less than the
new record number are also written with CHR$(255).
Subsequently accessing these record does not result in an
error.
If you want to avoid long delays as relative records are
formatted (as the file is expanded), then you should
reference the last record number immediately after opening
the file. The formatting of the null records takes place at
that time instead of at a more inconvenient time.
To position the DOS for a specific relative record you mUf't
send a position command over the command channel (15), as
shown here:

PRINTllfn,-P-+CHR$(channel)+CHR$(low)+CHR$(higA)+CHR$(bytel
48

Anatomy of the 1541 Disk Drive

If you are positioning to a record which is beyond the
current end of file, the DOS presents the message RECORD
NOT PRESENT appears to the disk error channel. If this
record is to be written, then you can ignore the message.
The following PRINTi statement is carried out in spite of
the error message.
The parameters low and high in the P command designate the
record number. The maximum value that can be given with one
byte is 255, but a relative file contains up to 65535 records. Therefore, the record number must be transmitted in
two bytes. These two bytes are calculated with the following
formula:
HB=INT(RN/256)
LB=RN-HB*256
HB
LB
RN

High Byte (parameter high)
Low Byte (parameter low)
Record Number

The last parameter (byte) serves to position to a specific
location within the given record. An example:
PRINTI2,-P-+CHR$(2)+CHR$(10)+CHR$(I)+CHR$(5)

Here the file is positioned to the fifth byte of the 266th
record. This 266 is coded as a low byte of 10 and a high
byte of 1 (high byte * 256 + low byte = record number).
To read or write a complete record, the file is positioned
to the first byte of the record. If the last parameter is
not given, the trailing RETURN (CHR$(13» is taken as the
character location.
The corresponding BASIC program to establish a file of 100
80-character records looks like this:
100
110
120
130
140
150
160
170

RN=100
HB=INT(RN/256)
LB=RN-HB* 256
OPENl,8,2,"FILE.REL,L,"+CHR$(80)
OPEN2,8,15
PRINTi2,"P"+CHR$(2)+CHR$(LB)+CHR$(HB)+CHR$(1)
PRINT#1,CHR$(255)
CLOSE l:CLOSE 15

Freeing 100 records takes some time. The creation of this
file takes about ten minutes. Notice that of the 80 characters ina record, only 79 can be used to hold data,
because transferring data with a PRINTi command adds a
trailing RETURN.

49

Anatomy of the 1541 Disk Drive
1.5.4

Preparing Data for Relative Storage

As already mentioned, you cannot change the record length of
a relative file.
If a record consists of several fields,
these fields must be combined. It is important that these
fields always be in the same position so that they can be
separated later. Let's work through a problem:
We want to manage an inventory using relative storage
techniques. To that end, the following fields are necessary:
PART NUMBER
DESCRIPTION
QUANTITY
COST
PRICE

4
15
5
6
6

CHARACTERS
CHARACTERS
CHARACTERS
CHARACTERS
CHARACTERS

Record length 36 bytes
The inventory contains approximately 200 items with a record
length of 36 bytes. This inventory file can now be created:
100
110
120
130
140
150
160

RN=200:REM NUMBER OF INVENTORY ITEMS
RL=36 :REM RECORD LENGTH
OPEN 1,8,2,"INVEN,L,"+CHR$(36)
OPEN 2,8,15
PRINT#2,"P"+CHR$(2)+CHR$(200)+CHR$(0)+CHR$(1)
PRINT#1,CHR$(255)
CLOSE l:CLOSE 2

Now the file is created and all records are written. Let's
suppose that the inventory is present as a sequential file.
It consists of 200 records, the fields of which are ordered
one after the other. These fields must be written to the
relative file. This is not simple, however, because many of
the descriptions are not the full fifteen characters in
length, for example. The structure of the relative file
looks as follows:
111111111122222222223333333
Position : 123456789012345678901234567890123456
Field
Contents

: PN$-DE$------------Q$---C$----P$---1

2
3

1/8 in. sheet
No. 10 screw
Valve A3A4

1344 11.40 20.30
1231 4.00 7.00
1243 11.45 16.40

200 1/2 in. tubing 2321

3.35

4.10

The fields will be read from the sequential file into the
following variables:
50

Anatomy of the 1541 Disk Drive

Part number
Description
Ouantity
Cost
Price

PN$
DES
0$
C$
p$

The following command chains these fields together:
RC$ = PN$ + DE$ + 0$ + C$ + P$
The record variable Re$ does not have the deSired structure.
The reason is that the quantity immediately follows the
description. Because the quantity must begin at position 20
and the description is not always fifteen characters, we
have a problem. In order to read the records from the relative file, the structure must be observed. Therefore, all
fields that are shorter than the planned length must be
padded with blanks. Taking this into account, the chaining
goes like this:
BL$=n
RC$=PN$+LEFT$(BL$,4-LEN(PN$»
RC$=RC$+DE$+LEFT$(BL$,15-LEN(DE$»
RC$=RC$+O$+LEFT$(BL$,5-LEN(OS»
RC$=RC$+C$+LEFT$(BL$,6-LEN(C$»
RC$=RC$+P$+LEFT$(BL$,6-LEN(P$»
This concatenation looks more complicated than it really is.
Each field must be filled with enough blanks to bring it to
its appropriate length. The blanks are added to the
individual fields from the string BL$, defined at the
beginning. T
Let's go through an example:
Suppose the first part number is 8. The
string, LEN(PN$), is then one. The maximum
field (4) minus the actual length (1) is 3.
must therefore be padded with three blanks,

length of this
length of this
The string PN$
LEFT$(BL$,3).

Each record of the old sequential file must be prepared in
this manner before it can be transferred to the relative
file.
Naturally, the above is true for all input values to be used
in a relative file. Therefore, you must always remember to
use a routine to fill each field with blanks to its full
length when working with relative data processing.

51

Anatomy of the 1541 Dis.k Drive

1.5.5

Transferring Data

In principle, transferring data to and from a relative file
does not differ from sequential storage. Records are written
with PRINT# and read with INPUT# or GET#. The only
difference is that before a record is be written or read,
the file must be positioned to that record. This is accomplished with the P command. This example program illustrates
what we have discussed:
100
105
110
120
130
140
150
160
170
180
190
200
210
220
230
240
250
260
270
280
290
300
310
320
330
340
350
360
370
380
390

BL$="
OPEN 1,8,2, "TEST .REL, L, "+CHR$ (41)
OPEN 2,8,15
PRINT#2,"P"+CHR$(2)+CHR$(100)+CHR$(0)+CHR$(1)
PRINT#1,CHR$(255)
PRINT CHR$(147)
PRINT"INPUT RECORD:"
PRINT"-------------"
INPUT"RECORD NUMBER (1-100)
: "lRN
IF RNlOO THEN PRINTCHR$(145)1:GOT0160
INPUT"FIELD 1 (MAX.lO CHAR.) : "lFl$
IF LEN(Fl$»lO THEN PRINTCHR$(145)nGOT0190
INPUT"FIELD 2 (MAX. 5 CHAR.) : "lF2$
IF LEN(F2$»S THEN PRINTCHR$(14S)::GOT0210
INPUT"FIELD 3 (MAX.lO CHAR.): "lF3$
IF LEN(F3$»10 THEN PRINTCHR$(145)1:GOT0230
INPUT"FIELD 4 (MAX.15 CHAR.) : "lF4$
IF LEN(F4$»15 THEN PRINTCHR$(145)::GOT0250
PRINT"COHRECT (YIN)?"
GETX$:IF X$<>"Y' AND X$<>"N" THEN 280
IF X$="N" THEN 140
RC$=Fl$+LEFT$(BL$,lO-LEN(Fl$»
RC$=RC$+F2$+LEFT$(BL$,5-LEN(F2$»
RC$=RC$+F3$+LEFT$(BL$,10-LEN(F3$»
RC$=RC$+F4$+LEFT$(BL$,15-LEN(F4$»
PRINT#2,"P"+CHR$(2)+CHR$(RN)+CHR$(0)+CHR$(1)
PRINT# 1, RC$
PRINT"MORE INPUT (YIN)?"
GETX$:IF X$<>"Y" AND X$<>"N" THEN 370
IF X$="Y" THEN 140
CLOSE l:CLOSE 2:END

The following line-oriented documentation explains
operation of the program:
100
105
110
120
130
140

the

A blank-character string with 15 blanks is
defined.
The relative file is opened with a length of 15.
The command channel 15 is opened.
To initialize the relative file, the head is
positioned over the first byte of the last (lOOth)
record.
The last record is freed and the initialization
begun.
The screen is erased.
52

Anatomy of the 1541 Disk Drive
150-260
270-290
300-330
340
350
360-380
390

The record no. and fields 1-4 are entered and
checked for correct length.
The entered data can be corrected.
The record is prepared.
The head is positioned over the first byte of the
record.
The record is written to the disk.
New data can be entered.
The program ends.

Now write some records with this program, but don't forget
to save in case you need it later.
Certainly, it also necessary to read and change e~isting
records. To do this, the relative file is opened, the file
is positioned to the appropriate record, and the record is
read. This record must then be divided into its fields.
Let's read a record that was recorded with the previous
program. The following routine reads the record:
100
110
115
120
130
140
160

OPEN 1,8,2,"TEST.REL,L,"+CHR$(4l)
OPEN 2,8,15
PRINT CHR$(147)
INPUT"RECORD NUMBER :";RN
PRINT# 2, "P"+CHRS (2) +CHR$ (RN) +CHR$ (0) +CHR$ (1)
INPUT# 1 ,RC$
IF ASC(RC$)<>255 THEN PRINT"RECORD NOT FOUND!":
GOT0250
170 PRINT RC$
250 CLOSE l:CLOSE 2
This routine reads a specified record. If this record has
never been written, it is recognized by the value 255 with
which every record was marked at the establishment of the
file.
A record that is found is displayed. You can see that the
four fields are in the same positions. If you want to divide
the record into its individual parts, you must use the
function MIDS. For example, in order to extract field 1 of
the record, give the following statements in the direct mode
after the record is found and read:
Fl$=MIDS(RC$,l,lO)
PRINT Fl$
Now the variable Fl$ contains the first field, as written by
the first program. The division of records into individual
fields is accomplished by building on the previous program.
Add or change the following lines:
170
180
190
200

FlS=MID$(RC$,l,lO)
F2$=MID$(RCS,11,5)
F3$=MID$(RC$,16,10)
F4$=MID$(RC$,26,15)

53

Anatomy of the 1541 Disk Drive
210
220
230
240
250
260
270
280

PRINT"FIELD 1: H Fl$
PRINT"FIELD 2: " F2$
PRINT"FIELD 3: " F3$
PRINT"FIELD 4: " F4$
PRINT"MORE (YIN) "
GETX$:IF X$<>"yn AND X$<>"N" THEN 260
IF X$"'''Y" THEN 115
CLOSE l:CLOSE 2

Here the record is separated into the individual fields and
the fields are displayed. It is important for the MID$
function that the exact positions of the fields within the
record be maintained. The first parameter within the parentheses is the string variable containing the record. The
second parameter is the position at which the number of
characters represented by the parameter will be taken out.
Further work may done with the selected fields inside the
program.
So far, we have read the records with the INPUTi statement.
If the record is longer than 88 characters, it can no longer
be read with the INPUT# statement. The way to get around the
limited INPUT# statement is with the GET# statement. The
bytes of a record are read one at a time with this command
and assembled into a single string. Suppose you have a
relative file with l28-character records. Now you want to
read the tenth record of this file and place it in the
variable RC$. The example of the following routine
illustrates reading this with GET#:
100
110
120
130
140
150
160
170

OPEN 1,8,2, "TEST .GET ,L, "+CHR$ (128)
OPEN 2,8,15
PRINT#2,"P"+CHR$(2)+CHR$(10)+CHR$(0)+CHR$(1)
RC$"'""
FOR 1"'1 TO 128
GET#! ,X$
RC$"'RC$+X$
NEXT I

After running this routine, the record is contained in the
variable RC$. If this record had been written with a PRI'NT#
statement without a trailing semicolon, the last character
in the string will be a RETURN. To ignore this RETURN, allow
the loop in line 140 to run only to 127. The last character
of the record RETURN is not read.
AS already mentioned, the last parameter of the P command
specifies at which character the transfer of data should
begin. If, for instance, in the l27-character record of the
previous example, you want to read positions 40-60 into a
54

Anatomy of the 1541 Disk Drive
field, the head must be positioned over the 40th charact~r
and the next 21 bytes read. The following routine clarifies
this:
100
110
120
130
140
150
160
170

OPEN 1,8,2,"TEST.GET,L,"+CHR$(128)
OPEN 2,8,15
PRINTI2,"P"+CHR$(2)+CHR$(10)+CHR$(0)+CHR$(40)
F$=""
FOR 1=1 TO 21
GETll,X$
F$=F$+X$
NEXT I

In line 120, the head is positioned over the the 40th byte
of the tenth record in line 120 and the loop in lines 140170 reads the following 21 bytes (bytes 40-60 of the record)
into F$.
You see then that the entire record need not be read if you
only want to work with part of it.

1.5.6

Closing a Relative File

There is no difference between closing a relative file and
sequential file. Because the command channel must always be
open to send the position command when working with relative
storage, it must also be closed.

1.5.7

Searching Records with the Binary Method

Normally each record is accessed by record number. But
if you want to search for a specific name in a relative
and the record number is not known. It is possible to
each record and compare each for the desired name. But
is very time consuming if the file has many records.

what
file
read
this

If the file is kept in name order, the records can be
searched using an alternative method. This method is called
a binary search. In order to use a binary search, the
relative file must be arranged in sorted order. USing the
above example, relative record 1 must contain a name with
the lowest collating sequence while the last relative record
must contain a name with the highest collating sequence.
Thus the name AARON might be contained in relative record 1
and ZYPHER might be contained in the last relative record of
55

Anatomy of the 1541 Disk Drive

the file and all other names would be ordered throughout.
When records are added to the file, then the records must
be reordered. Similarly if a name is changed, then the
records must be reordered.
The binary search can be explained using a simple example.
When you want to find a name in the telephone book, you
don't search through it sequentially. You open the book in
the middle and compare the first letter of the desired name
with the first letter of names on the page. If the desired
name comes before these, you turn halfway into the first
section of the book, and so on. You go through it
systematically.
The binary search is not a sequential search. It identifies
.a record halfway through the remaining number of records.
The following example will clarify this:
There exists the following
ascending order:
Record number
1
2

3
4

5
6
7
8
9

10
11

12
13
14
15

relative

file,

sorted

in

Contents
1985
1999
2005
2230
2465
2897
3490
3539
4123
5000
5210
6450
6500
6550
6999

out of these fifteen records we will search for a contents
of 3490. It is not known which record it is stored in.
We must first know how many records are in the file. In this
case, there are fifteen. We divide this by two. The middle
of the file is record eight with the contents 3539. We
determine if the contents of this record equal to the target
value, and if not, whether it is larger or smaller. In this
case, it (3539) is larger. This means the record we are
looking for is in the first half of the file. So we divide
eight by two and examine the contents of record four, 2230.
Since 2230 is less than 3490, it lies between four and
eight. We again divide by two and add this to record 4 which
and results in record 6 whose contents is 2897. 2897 is less
than 3490, so our target lies between records six and eight.
Record seven is indeed the record we are looking for.
56

Ana~amy

of the 1541 Disk Drive

The principle of the binary search is to determine by the
result of each comparison whether to search upwards or
downwards until the search data is found. The maximum number
of comparisons can be found using the following formula:
S=INT(LOG(N)!LOG(2)+1)
S is the
number of
file with
necessary

number of comparisons (searches) and N is the
records in the file. In a sorted relative data
1000 records, no more than ten comparisons will be
to find the desired record!

Let's create a relative data file with fifteen records to
test the binary search:
100
110
120
130
140
150
160
170

OPENl,8,2,"BINARY.REL,L,"+CHR$(5)
FORI=l T015
READ RC$
PRINTU ,RC$
NEXT I
CLOSE l:CLOSE 2:END
DATA 1985,1999,2005,2230,2465,2897,3490,3539
DATA 4123,5000,5210,6450,6500,6550,6999

This program puts the fifteen records in a file called
BINARY.REL using the values given in lines 160-170. The
position command is not necessary because the data will be
written straight through from first to last record. After
opening the file the pointer points to the first record.
This file is designed to be searched with the binary method.
The following program is based on the logic of the binary
search:
100
110
120
140
150
160
170
180
190
210
220
230
240
250
260
270
280
290
300
310
320

OPENl,8, 2, "BINARY .REL, L, "+CHR$ (5)
OPEN2,8,15
PRINTCHR$(147)
N=15: REM NUMBER OF RECORDS
I=LOG(N)!LOG(2)
IF I-INT(I)<>O THEN I=INT(I)+l
M=I-1
1=2"1
X=I/2
INPUT"RECORD TO FIND (* TO END): ";SR$
IF SR$="*" THEN 320
IF MI THEN PRINT"END OF FILE EXCEEDED!"
GOTO 230
CLOSE l:CLOSE 2
57

Anatomy Of the 1541 Disk Drive
330
340
350
360

END
PRINT"RECORD FOUND!"
PRINT"CONTENTS : ":RCS
GOTO 140

Program Documentation:
100

110
120
140
150-190

210-220
230
240
250-260
2.70
280-310

320-330
340-360

The relative file "BINARY.REL" is opened.
The command channel is opened.
The screen is erased.
The number of records is assigned to the variable
N.
If the maximum number of records does not
represent a power of two, the next higher power
of two is formed. The file will be expanqed, but
no records are lost. The exponent of this power of
two is used as the index. X is the value of 1/2.
1/2 indicates the exact middI'e of the (expanded)
file. After that, the variable M receives the
value of 1-1.
The record to be found is read. To end the
program, enter a '*'.
If MlOO THEN PRINTCHR$(145);:GOT0200
PRINT"---------------------------"
PRINT*2, "P"+CHR$ (2) +CHR$ (RN)+CHR$ (0 )+CHR$ (1)
INPUTU,RC$
IF ASC(RC$)<>255 THEN 270
PRINT "RECORD NOT WRITTEN"
GOTO 630
REM ======================
REM
PREPARE RECORD
REM ======================
F$(l)=MID$(RC$,l,lO)
F$(2)=MID$(RC$,11,5)
F$(3)=MID$(RC$,16,10)
F$(4)=MID$(RC$,26,15)
61

Anatomy of the 1541 Disk Drive

340
350
360
370
380
390
400
410
420
430
440
450
460
470
480
490
500
510
520
530
540
550
560
570
580
590
600
610
620
630
640
650
660
670
680
690

REM ======================
REM
DISPLAY FIELDS
REM ======================
PRINT CHR$(147)
FOR 1=1 TO 4
PRINT"FIELD";I;": ";F$(I)
NEXT I

PRINT"-------------------------"
REM ======================
REM
CHANGE FIELDS
REM ======================
PRINT"CHANGE WHICH FIELD (l-4)?"
GETX$:IFX$<"l" OR X$>"4" THEN 460
INPUT"NEW CONTENTS: ";F$(VAL(X$»
PRINT"RECORD IS CHANGED"
PRINT"MORE CHANGES IN THIS RECORD (YIN)?"
GETX$:IF X$<>"Y" AND X$<>"N" THEN 500
IF X$="Y" THEN 340
REM ====================
REM
CHAIN FIELDS
REM ====================
RC$=F$(l)+LEFT$(BL$,lO-LEN(F$(l»)
RC$=RC$+F$(2)+LEFT$(BL$,5-LEN(F$(2»)
RC$=RC$+F$(3)+LEFT$(BL$,10-LEN(F$(3»)
RC$=RC$+F$(4)+LEFT$(BL$,15-LEN(F$(4»)
REM =========================
REM
WRITE RECORD BACK
REM =========================
PRINT#! ,RC$
REM ====================
REM
END PROGRAM?
REM ====================
PRINT"MORE CHANGES TO FILE (YIN)?"
GETX$:IF X$<>"Y" AND X$<>"N" THEN 670
IF X$="Y" THEN 160
CLOSE l:CLOSE 2:END

After this program is RUN you can change any desired record.
This record must have been written with the program in
section 1.5.5.
This editing program does not check the new field data for
correct length.
The important commands in this program have already
explained in the corresponding sections.

b~en

1.5.10 Expanding a Relative File

Every relative file has a user-determined number of records
that ranges from 1 to 65538. This number is the record with
the highest record number and is written to the file with a

62

Anatomy o£ the 1541 Disk Drive
value of CHR$(255).
Writing this last record also formats
all records in the file that precede this record number with
CHR$(255).
You can expand the size of a relative file at a later tiroe.
For example, consider a relative file that is initially
created with three records. After the file is OPENed, you
position the file at record number 3 and write the record
with CHR$(255). Here's an example of how you might do this:
10
20
30
40

OPEN 1,8,2, "RELFILE, L, "+CHR$ (50)
OPEN 15,8,15
PRINTU5, "P"+CHR$ (2) +CHR$ (3)+CHR$ (O)+CHR$ (1)
PRINTil,CHR$(255)

When statement 40 is performed, not only is record 3
written, but records 1 and 2 are also formatted by the DOS.
Subsequently, if you position and write a 90th record, the
DOS formats records 4 through 89 (see lines 150 and 160
below). Each time the file is expanded, the DOS formats
records between the current high record number and the new
high record number.
150 PRINTi15,"P"+ CHR$(2)+CHR$(90)+CHRS(0)+CHR$(1)
160 PRINTil,CHR$(255)
500 PRINTi15,"P"+CHR$(2)+CHR$(175)+CHR$(0)+CHR$(1)
510 PRINTil,CHR$(255)

An existing relative file can be expanded at any time,
provided there is sufficient room on the disk. To do so, the
new last record is written with CHR$(255). At the same time,
all records between the old and new end of file are also
formatted.
When writing a record to a relative file whose record number
is higher than the current high record number, a DOS error
is not returned. If there is room on the diskette for the
new records (current high record number through the new high
record number) the file is simply expanded. If there is a
lack of space on the diskette for the new records, the DOS
error FILE TOO LARGE is returned. When reading a record from
a relative file whose record number is higher than the
current high record number, the DOS error RECORD NOT PRESENT
is returned to the error channel.-

63

Anatomy of the 1541 Disk Drive
1.5.11· Home Accounting with Relative ·Data Storage

A complete example of problem solving using relative files
offers you a good insight into the organization of relative
file processing. It can be used by most readers of this
book. Few examples of relative file usage have been
explained elsewhere, so here is such a program.
In this application, individual accounts are numbered. This
account number is used as a key to the corresponding
records.
This provides that each account contain a clear text
description. The first field of each record is this account
name. Twenty characters are allowed for the name.
since information is needed for each month, twelve fields
are necessary for each record. These summary fields are each
ten characters long. The account summaries are stored as
strings which are converted to numbers with .the help of the
VAL function. The record consists of 141 characters (twenty
for the name, 12*10 for the month summaries and one for
RETURI'/) •

The layout of the records follows:
Length

position

Account name
January summary
February summary

20
10
10

1-20
21-30
31-40

November summary
December summary

10
10

121-130
131-140

Field

The maximum number of accounts per year is set to twenty.
Therefore, a year's file consists of twenty records of 141
bytes each.
We also specified the functions that this program is to
perform.

* Create accounts

*

Post to accounts

* Display summary by Account
* Display account names
* Display Monthly summary
64

Anatomy of the 1541 Disk Drive

* Display Year-end summary
Create accounts:
This function creates the file for a year. It asks for the
number and names of the accounts. The records are then
written with the account name and the summary fields are set
to zero. Should a data file already exist with the sane
name, the old file is deleted.
Post to accounts:
This function asks for the account number to be posted and
whether the posting is an income or expense. For example,
the category "SALARY" is an income account and the category
"RENT" is an expense account.
After this, the current contents of the account are
displayed. When you post the appropriate amount, which is
always positive. If you are making a correction entry, use a
negative amount.
Now the updated contents are displayed.
new entry.

You may then make a

Producing account summary:
After entering the account number, the summary of the twelve
months and the year's total are displayed for that account.
Display account names:
Each account is determined by its number. Should you forget
a number, this function lists all accounts by name and
corresponding number.
Display monthly summary:
Here the income or expenses of all accounts are displayed.
The monthly balance of all accounts is also displayed.
Display year-end summary:
This function shows the summary of all accounts and the
year-end balance. This display takes some time, since all
monthly fields of each record must be read and totaled. It
accesses the entire file.
Here's the program listing:

65

Anatomy of the 1541 Disk Drive

100 POKE 53280,2:POKE5328l,2:PRINTCHR$(158)::
BL$="
":DIMS(12)
110 GOSUB 2050
120 INPUT"CURRENT YEAR: ":Y$
130 IF Y$<"1984"ORY$>"1999"THENPRINTCHR$(145);:GOT0120
140 GOSUB 2050
150 PRINT"SELECT A FUNCTION:
160 PRINT"------------------":PRINT
170 PRINT"
-1- CREATE ACCOUNTS"
180 PRINT"
-2- POST TO ACCOUNTS"
190 PRINT"
-3- ACCOUNT SUMMARY"
200 PRINT"
-4- DISPLAY ACCOUNT NAMES"
210 PRINT"
-5- MONTHLY SUMMARY"
220 PRINT"
-6- YEAR SUMMARY":PRINT
230 PRINT"
-0- END PROGRAM"
240 GETX$:IFX$<"0"ORX$>"9"THEN240
250 IFX$<>"0"THEN270
260 END
270 ONVAL(X$)GOSUB 290,560,920,1160,1370,1720
280 GOTO 140
290 REM ================-=======
300 REM
CREATE ACCOUNTS
310 REM ========================
320 GOSUB 2050
330 PRINT"CAUTION! ANY PREVIOUS FILE FOR THIS YEAR"
340 PRINT"WILL BE ERASED!":PRINT
350 PRINT"CONTINUE(Y/N)?"
360 GETX$:IFX$<>"Y"ANDX$<>"N"THEN360
370 IFX$="Y"THEN390
380 CLOSEl:CLOSE2:RETURN
390 OPEN2,8,15,"S:ACCOUNTS"+Y$
400 OPEN1,8,2,"ACCOUNTS"+Y$+",L,"+CHR$(141)
410 GOSUB 2050
420 INPUT"HOW MANY ACCOUNTS (1-20): .. :AN
430 PRINT
440 IFAN<10RAN>20THENPRINTCHR$(145)::GOT0420
450 FORI=ITOAN
460 PRINT"NAME OF ACCOUNT NO.":I;": to;
470 INPUTAN$
480 IFLEN(AN$»20THENPRINTCHRS(145);:GOT0420
490 RC$=AN$+LEFT$(BL$,20-LEN(AN$»
500 FORX=lT012
510 RC$=RC$+STR$(0)+LEFT$(BL$,8)
520 NEXTX
530 PRINTH,RCS
540 NEXT I
550 CLOSE I:CLOSE 2:RETURN
560 REM =============
570 REM
POSTING
580 REM =============
590 GOSUB2050
600 INPUT"ACCOUNT NmIBER" :AN
610 IFAN<10RAN>20THENPRINTCHR$(145)::GOT0600
620 GOSUB2140
630 PRINT"----------------------------"
66

Anatomy of the 1541 Disk Drive
640 PRINT"NO."lAN1" - "lAN$
650 PRINT"------------------------"
660 PRINT"INCOME OR EXPENSE (I/E)?"
670 PRINT"------------------------"
680 GETX$:IFX$<>"I"ANDX$<>"E"THEN680
690 INPUT"MONTH (1-12)
: "1M
700 IFM<10RM>12THENPRINTCHR$(145)1:GOT0690
710 PRINT"----------------------------"
720 PRINT"OLD CONTENTS
: "lS(M)
730 PRINT"----------------------------"
740 INPUT"POSTING AMOUNT: ";PA
750 PRINT"----------------------------"
760 IFX$="I"THENS(M)=S(M)+PA:GOT0780
770 S(M)=S(M)-PA
780 PRINT"NEW CONTENTS
: "lS(M)
790 PRINT"----------------------------"
800 RC$=AN$+LEFT$(BL$,20-LEN(ANS»
810 FORI=lT012
820 S$=STRS(S(I»
830 RC$=RC$+S$+LEFT$(BL$,10-LEN(S$»
840 NEXT!
850 PRINH 2," P"+CHR$ (2) +CHR$ (AN) +CHR$ (0) +CHR$ (1)
860 PRINT#l,RC$
870 CLOSEl:CLOSE2
880 PRINT"FURTHER POSTING (Y/N)?"
890 GETX$:IFX$<>"Y"ANDX$<>"N"THEN890
900 IFX$<>"Y"THENGOSUB2050:GOT0600
910 RETURN
920 REM ===================
930 REM
ACCOUNT SUMMARY
940 REM ===================
950 GOSUB2050
960 INPUT"ACCOUNT NUMBER: ";AN
970 IFAN<10RAN>20THENPRINTCHR$(145);:GOT0960
980 GOSUB2140
990 GOSUB2050:PRINTCHR$(145);CHR$(145)1
1000 PRINT"-------------------------"
1010 PRINT"NO.";AN;" - "lAN$
1020 PRINT"-------------------------"
1030 PRINT"MONTH TOTAL"
1040 PRINT"-------------------------"
1050 TL=O
1060 FORI=lT012
1070 PRINTI;TAB(8)lS(I)
1080 TL=TL+S(I)
1090 NEXT I
1100 PRINT"-------------------------"
1110 PRINT"TOTAL";TAB(8) ;TL
1120 PRINTTAB(9);"======="
1130 PRINT"RETURN FOR MORE"
1140 INPUTX$
1150 CLOSE1:CLOSE2:RETURN
1160 REM =====================
1170 REM DISPLAY ACCOUNT NAMES
1180 REM =====================
67

Anatomy of the 1541 Disk Drive
1190
1200
1210
1220
1230
1240
1250
1260
1270
1280
1290
1300
1320
1330
1340
1350
1360
1370
1380
1390
1400
1410
l420
1430
1440
1450
1460
1470
1480
1490
1500
1510
1520
1530
1540
1550
1560
1570
1580
1590
1600
1610
16 20
1630
1640
1650
1660
1670
1680
1690
1700
1710
1720
1730
1740

GOSUB2050
OPEN1,8,2,"ACCOUNTS"+Y$+",L,"+CHR$(141)
OPEN2,8,15
1=1
PRINT* 2," P"+CHR$ (2) +CHR$ (I) +CHR$ (0) +CHR$ (1)
RC$=""
FORX=IT020
GETU ,X$
RC$=RC$+X$
NEXTX
INPUT*2,X
IFX=50THENI340
PRINTI:" - ":RC$
I=I+l:GOTOI230
PRINT"RETURN FOR MORE"
INPUTX$
CLOSEl:CLOSE2:RETURN
REM ===============
REM MONTH SUMMARY
REM ===============
GOSUB2050
INPUT"MONTH : ":M
GOSUB2050
PRINT"---------------------------------"
PRINT"NO. NAME
CONTENTS·
PRINT"---------------------------------"
OPENl, 8,2, ,. ACCOUNTS"+Y$+" , L, "+CHR$ ( 141)
OPEN2,8,15
TL=O
FORAN=IT020
AN$="":S$=""
PRINT#2,"P"+CHR$(2)+CHR$(AN)+CHR$(0)+CHR$(I)
FORI=IT020
GET*I,X$
AN$=AN$+X$
NEXTI
INPUT#2,F
IFF<>50THENI590
GOT01670
PRINT#2,"P"+CHR$(2)+CHR$(AN)+CHR$(0)+CHR$(20+(M-l)*10)
FORI=ITOI0
GETU,X$
S$=S$+X$
NEXT I
TL=TL+VAL(S$)
PRINT AN:TAB(6):AN$:TAB(26):S$
NEXT AN
PRINT"---------------------------------"
PRINT"TOTAL BALANCE":TAB(26):STR$(TL)
PRINTTAB(26):"======="
PRINT"RETURN FOR MORE":
INPUTX$:CLOSE1:CLOSE2:RETURN
REM ==============
REM YEAR SUMMARY
REM ==============

68

Anatomy of the 1541 Disk Drive
1750
1760
1770
1780
1790
1800
1810
1820
1830
1840
1850
1860
1870
1880
1890
1900
1910
1920
1930
1940
1950
1960
1970
1980
1990
2000
2010
2020
2030
2040
2050
2060
2070
2080
2090
2100
2110
2120
2130
2140
2150
2160
2170
2180
2190
2200
2210
2220
2230
2240
2250
2260
2270
2280
2290

GOSUB2050
OPENl,8,2,"ACCOUNTS"+Y$+",L,"+CHR$(141)
OPEN2,8,15
PRINT .. ------------------------------------ ..
PRINT"NO. NAME
YEAR BALANCE"
PRINT .. ------------------------------------ ..
TL:O
FOR AN:IT020
PRINT,2,"P"+CHR$(2)+CHR$(AN)+CHR$(0)+CHR$(1)
RC$= ....
FORI=lT0140
GETU,X$
RC$=RC$+X$
NEXTI
INPUT'2,F:IFF=50THEN1980
AN$=LEFT$(RC$,20)
YB=O
FORI:ITOI0
YB:YB+VAL(MID$(RC$,20+(I-l)*10,10»
NEXTI
TL=TL+YB
PRINTAN,TAB(6),AN$,TAB(26);YB
NEXTAN
PRINT .. ---------------------------- ..
CLOSEl:CLOSE2
PRINT"TOTAL BALANCE";TAB(26),TL
PRINTTAB(26),"::=:==="
PRINT"RETURN FOR MORE"
INPUTX$
RETURN
REM =========:=========
REM
PROGRAM HEADING
REM ===================
PRINTCHR$(147),
PRINTTAB(4);"============================"
PRINTTAB(4);"H 0 MEA C C 0 U N TIN G"
PRINTTAB(4);"============================"
PRINT:PRINT
RETURN
REM ================
REM
READ ACCOUNT
REM ================
OPENl,8,2,"ACCOUNTS"+Y$+",L,"+CHR$(141)
OPEN2,8,15
PRINT'2,"P"+CHR$(2)+CHR$(AN)+CHR$(O)+CHR$(l)
RC$= ....
FORI=lT0140
GET'l,X$
RC$=RC$+X$
NEXT I
INPUT'2,F
IFF<>50THEN2300
PRINT"YEAR FILE OR ACCOUNT NOT FOUND!":PRINT
PRINT"RETURN FOR MORE":INPUTX$
CLOSEl:CLOSE2:RETURN

69

Anatomy of the 1541 Disk Drive
2300
2310
2320
2330
2340
2350
2360

AN$=LEFT$(RC$,20)
TL=O
FORI=lT012
S(I)=VAL(MID$(RC$,20+(I-l)*10,10»
TL=TL+S( I)
NEXT I
RETURN

Program Documentation:
Initialization:
100
llO-l30
140-280

Screen and character color set: blank character
string defined: variable for account summaries
dimensioned.
Program heading displayed and current year read.
Program functions displayed and choice read:
corresponding subprogram called.

Establish Accounts:
390-400
480
500-540
530

Any existing files of this year are erased and the
new file is opened.
Account name is placed in positions 1-20 of the
record RC$.
Month summaries are set to zero and placed in the
record as string variables.
The record is transferred with a trailing RETURN.

posting:
590
800
810-840
850-860

The routine "Read Account" is called. This routine
places the month summaries of the account in the
variables S(l) to S(12).
Account name is placed in the record.
Account summary is placed in the record.
Record is transferred.

Account summary:
980

Desired account is read and the month summaries'
are placed in variables S(l) to S(12).
1050-1090 Month summaries are displayed and the total (TL)
is added up.
1110
Total displayed.
Display Account Names:
1220
1230

Account number is initialized.
The head is positioned over the corresponding
70

Anatomy of the 1541 Disk Drive
record.
1240-1280 Account name is read out of the record in RCS.
1290-1300 If RECORD NOT PRESENT is sent over the error
channel (error 50), the routine is broken off.
1320
Account number and name are displayed.
Month Summary:
Loop to read all accounts.
position head over record.
Read account name.
Determine if account existsl stop if all twenty
accounts have been defined.
1590
position over summary field of the desired month.
1600-1630 Read the month summary.
Add month summary to total.
1640
Account number, account name and month summary are
1650
displayed.
1680
Total balance displayed.

1490-1660
1510
1520-1550
1560-1580

Year Summary:
1820-1970
1830
1850-1880
1890
1900
1920-1940
1950
1960
2000

Loop to read all accounts
position head over record.
Complete record read into RC$.
Test if RECORD NOT PRESENT.
Get account name from record.
Read month summary, convert to numerical form and
add to year summary (YS).
Year summary (YS) is added to total (TL).
Account number, account name and year summary
displayed.
Total balance (month balance) displayed.

Read Account:
2190
2210-2240
2250-2260
2300
2320-2350

position over record given in AN.
Read record into RCS.
Test if RECORD NOT PRESENT.
Account name read from record.
Month summaries read from record, converted to
numerical form and placed into the table S(l) to
S(12) •

71

Anatomy of the 1541 Disk Drive
1.6

Disk Error Messages and their Causes

If you cause an error while ,,?orking with the disk drive, the
drive signals this by blinking the red LED. The LED blinks
until you read the error channel of the disk drive or until
you send a new command. First we want to see how to read the
error message from the disk drive.
In order to do this, the error/command channel must be
opened with the secondary address 15:
100 OPEN 15,8,15
110 INPUT#15,A,B$,C,D
120 PRINT A,B$,C,D
If no error has occurred, the following is displayed:

o

OK

o

o

The first number is the error number, in this case zero,
which. means no error has occurred. Next follows the error
message (variable B$). The variables C and D contain the
track and sector numbers, respectively, in which the error
occurred, which is dependent on the type of error (mainly
associated with hardware errors and block-oriented
commands) •
This routine accomplishes the same function:
100 OPEN15,8,15
110 GET#15,A$:PRINTA$;:IFST<>64THENl10
00, OK,OO,OO
Here characters are read from the error channel until the
end is recognized (status = 64). This gives the error message
exactly as the BASIC 4.0 command
PRINT DS$
When using BASIC 4.0, variables DS$ and DS are reserved
variables which contain the complete error message and error
number. Each access of these variables gives the error
status of the last disk operation. Unfortunately, the
Commodore 64 does not use BASIC 4.0, so these variables are
meaningless in Commodore 64 BASIC (BASIC 2.0).
Next follows the list of error messages that the DOS can
recognize:
00. OK.OO.OO
This message occurs when the last disk operation was error
free or if no command or data was sent after the last
error message.
72

Anatomy of the 1541 Disk Drive
01.FILBS SCRATCHBD.XX.OO
This is the message after a SCRATCH command. The number XX
denotes the number of filed that were erased. Since this
is not really an error message, the LED does not blink.

20.READ BRROR.TT.SS
This error means that the 'header' of a block was not
found. It is usually the result of a defective diskette.
TT and SS designate the track and sector in which the
error occurred. Remedy: change defective diskette.
21.RBAD ERROR.TT,SS
This is also a read error. The SYNC (synchronous) marker
of a block was not found. The cause may be an unformatted
disk, or no disk in the drive. This error can also be
caused by a misaligned read/write head. Remedy: Either
insert a diskette, format the disk, or have the read/write
head aligned.
22,READ ERROR.TT.SS
This error message means that a checksum error has
occurred in the header of a data blocK, which can be
caused by the incorrect writing of a block.
23.READ ERROR.TT.SS
The error implies that a data block was read into the DOS
buffer, but a checksum error occurred. One or more data
bytes are incorrect. Remedy: Save as many files as
possible onto another diskette.
24.RBAD ERROR.TT.SS
This error also results from ~ checKsum error in the data
block or in the preceding data header. Incorrect bytes
have been read. Remedy: same as error 23.
25.WRITE ERROR.TT.SS
This error is actually a VERIFY ERROR. After writing every
block the data is read again checked against the data in
the buffer. This error is produced if the data are not
identical. Remedy: Repeat the command that caused the
error. If this doesn't work, the corresponding block must
be locked out from further use with the block-allocate
command.
26.WRITE PROTECT ON.TT.SS
An attempt was made to write to a disK with a write
protect tab on it. Remedy: Remove write protect tab.
27,RBAD ERROR.TT.SS
A checksum error occurred in the header of a data block.
Remedy: Repeat command or rescue block.

73

Anatomy of the 1541 Disk Drive
28,WRITE ERROR,TT,SS
After writing a data block, the SYNC characters of the
next data block were not found. Remedy: Format disk again,
or exchange it.
29,DISK ID MISMATCH,TT,SS
The ID (two character disk identification) in the DOS
memory does not agree with the ID on the diskette. The
diskette was either not initialized or there is an error
in the header of a data block. Remedy: Initialize
diskette.
30,SYNTAX ERROR,OO,OO
A command was sent over the command channel that the DOS
could not understand. Remedy: Check and correct command.
31,SYNTAX ERROR,OO,OO
A command was not recognized by the DOS, for example, the
BACKUP command (Duplicate) on the 1541. Remedy: Do not use
the command.
32,SYNTAX ERROR,OO,OO
The command sent over the command channel was longer than
40 characters. Remedy: Shorten command.
33,SYNTAX ERROR,OO,OO
A wildcard ('*' or '?') was used
command. Remedy: Remove wildcard.

in an OPEN or SAVE

34,SYNTAX ERROR,OO,OO
The DOS cannot find the filename in a command. This may be
because a colon was forgotten after the command word.
Remedy: Check and correct command.
39,FILE NOT FOUND,OO,OO
User program of type 'USR' was not found for automatic
execution. Remedy: Check filename.
50,RECORD NOT PRESENT,OO,OO
A record was addressed in a relative data file that has
not yet been written. When writing a record this is not
really an error. You can avoid this error message if you
write the highest record number of the file with CHR$(255)
when initializing it. This error will no longer occur upon
later access.
51,OVERFLOW IN RECORD,OO,OO
The number of characters sent when writing a record in a
relative file was greater than the record length. The
excess characters are ignored.
52,FILE TOO LARGE,OO,OO
The record number of a relative file is too big:
diskette does not have enough capacity. Remedy:
another diskette or reduce the record number.
74

the
Use

Anatomy of the 1541 Disk Drive
60,WRITE FILE OPEN,OO,OO
An attempt was made to OPEN a file that had not previously
been CLOSEd after writing. Remedy: Use mode 'M' in the
OPEN command to read the file.
6I,FILE NOT OPEN,OO,OO
A file was accessed that had not been OPENed. Remedy: Open
the file or check the filename.
62,FILE NOT ~UND,OO,OO
An attempt was made tp load a program or open a file that
does not exist on the diskette. Remedy: Check the
filename.
63,FILE EXISTS,OO,OO
An attempt was made to establish a new file with the name
of a file already on the diskette. Remedy: Use a different
filename or @: (to replace the old file).
64,FILE TYPE MISMATCH,OO,OO
The file type use in the OPEN command does not agree
with the file type in the directory. Remedy: Correct
file type.
65,NO BLOCK,TT,SS
This error message is given in association with the BLOCKALLOCATE command when the specified block is no longer
free. In this case, the DOS automatically searches for a
free block with a higher sector and/or track number and
gives these values as the track and sector number in the
error message. If no block with a greater number is free,
two zeroes will be given.
66,ILLEGAL TRACK OR SECTOR,TT,SS
If you attempt to use a block with the block commands that
does not exist,
this error is returned.
61,ILLEGAL TRACK OR SECTOR,TT,SS
The track-sector combination of a file produces a nonexistent track or sector.
10,NO CHANNEL,OO,OO
An attempt was made to open more files than channels
available or a direct access channel is already reserved.
11,DIR ERROR,TT,SS
The number of free blocks in "the DOS storage does not
agree with the BAM. Usually this means the disk has not
• been initialized.
12,DISK FULL,OO,OO
Fewer than three blocks are free on the diskette or t~e
maximum number of directory entries have been used (144 on
the VIC 1541).

15

Anatomy of the 1541 Disk Drive
73,CBM DOS V.26 1541.00,00
The message is the power-up message of the VIC 1541. As an
error message, it appears when an attempt is made to write
to a disk that was not formatted with the same DOS
version, for example, the forerunner of the CBM 4040, the
CBM 2040 (DOS version 1.0).

74.DRIVE NOT READY,OO,OO
When one attempts to use the disk without a diskette in
the drive, this error message is returned.
75,FORMAT SPEED ERROR.OO,OO
This error message occurs only on the CBM 8250. It
indicates a deviation from the normal revolutions per
minute while formatting.

76

Anatomy of the 1541 Disk Drive
1.7

Overview of Commands with a Comparison of BASIC 2.0 BASIC 4.0 - DOS 5.1

BASIC 2.0

BASIC 4.0 (abbrev)

OPEN - Mode 'A'

APPEND ( aP)
BACKUP ( bA)
CATALOG (CA)
COLLECT (coL)
CONCAT (conC)
COpy (coP)
DCLOSE (dC)
DLOAD (dL)
DOPEN (dO)
DS$ , DS
DSAVE (dS)
HEADER ( hE)
I( initialize)
RECORD (reC)
RENAME ( reN)
SCRATCH (sC)

LOAD"$",B & LIST
V(alidate)
C(opy)
CLOSE
LOAD" ••• ",B
OPEN .... ,8, .....
OPEN 1,B,15
SAVE" ••• " ,B
N(ew)
I(nitialize)
P
R(ename)
S(cratch)

...

...

DOS 5.1

@$ or >$
@V or >V
@C: •• or >C: ••
©file or /file
@ or >
@N: •• or >N: ••
@I or >1
@R: •• or >R: ••
@S: •• or >S: ••

This table lists the different versions of BASIC. The DOS
5.1 is found on the TEST/DEMO disk and will be described in
section 4.2.1.
The essential difference between BASIC 2.0 and BASIC 4.0 is
that with BASIC 2.0, each command is executed by the disk
control system (DOS) and must be sent over channel 15. The
disk commands of BASIC 4.0 manage this channel themselves
(with the exception of INITIALIZE). For example, the command
HEADER DO,"DISKl",IHJ generates the same sequence of
commands necessary in BASIC 2.0, namely:
OPEN l,B,15,"N:DISKl,HJ"
CLOSE 1
Here are are the specifics of the BASIC 4.0 commands:
Note the following parameters:
Ifn
dn
da

logical file number
drive number - drive 0 (DO) or drive 1 (Dl) with
a double drive, or DO for a single drive
device address of the disk drive (U4 to U31)

Information in parentheses is optional. The standard
parameters DO and UB will be used (meaning Drive 0 and Unit
B) •

77

Anatomy of the 1541 Disk Drive
APPEND:
T'i1iSCommand allows data to be added to a sequential file,
which is accomplished in BASIC 2.0 with the OPEN-command
mode A.
This command has the following format:
APPEND#lfn,"filenamen(,Ddn,Uda)
For example, should the sequential file "SEQU.l" be on drive
0, the following statements are necessary to add a data
record to it:
100 APPEND#l,"SEQU.l",DO
110 PRINT#! ,X$
120 CLOSE 1
BACKUP:
With this command, a complete diskette can be copied. The
BACKUP command can only be used with a dual disk drive (such
as the 4040), however. Notice the format of this command:
BACKUP Ddn TO Ddn(,Uda)
It is important that either DO to Dl or Dl to DO be given.
An example:
The diskette in drive 1 is supposed to be copied onto the
disk in drive O. To this end, give the following command:
BACKUP Dl TO DO
CATALOG:
The CATALOG command of BASIC 4.0 has the advantage that the
program in the computer's memory is not erased, as is true
in BASIC 2.0. The format of the command:
CATALOG (Ddn,Uda)
If no drive number is given for a double drive, the contents
of both drives are given. With a single drive, CATALOG DO is
assumed. An example:
CATALOG DO
The contents of the disk in drive 0 will be displayed.
COLLECT:
This command corresponds with the VALIDATE command of BASIC
2.0. The syntax of this command looks like this:
COLLECT (Ddn)
78

Anatomy of the 1541 Disk Drive
CONCAT:

CON'CAT

concatenates sequential files, in which one file
to be made from the data of two files. The format:
CON CAT (Ddn,)"filel" TO (Ddn,)"file2"

is

(ON Udal

Suppose you want to combine the data of the files "SEOU.2"
in drive 0 and "SEOU.l" in Dl. To accomplish this, issue the
following command:
CON CAT DO,"SEOU.2" TO Dl,"SEOU.l"
COPY:
with this command files can be copied from one drive to the
other (except relative files). The command is useless with a
single drive. The syntax looks like this:
COpy (Ddn,)("filel") TO (Ddn,)("file2")
To copy all files (for example, from drive 0 to drive 1),
use the following command:
COPY DO TO Dl
DCLOSE:

The command DCLOSE has the same function as the simple CLOSE
command, with the following exceptions:
DCLOSE
closes all files
closes file number 1
DCLOSE#l
DCLOSE# 1 ON U9 closes the logical file #l on device
address 9
closes all files on device address 8
DCLOSE U8
The command has the following syntax:
DC LOSE (#lfn) (ON Udal
DLOAD:
The command DLOAD has the advantage that the standard device
address 8 used. The format:
DLOAD "program" (, Ddn) ( , Uda)
For instance, if you want to load the program "PRG.2" from
drive 0 or from a single drive, give the following command:
DLOAD "PRG.2"
Drive 0 (DO) is the default value.

79

Anatomy of the 1541 Disk Drive
OOPEN:

T1iTS command of BASIC 4.0 is very comprehensive. The
following format verifies this:
DOPEN#lfn,"file H ( ,Ddn) (,Uda) (,fileparameter)
The peculiarity of this method of opening is the file
parameter. There are two file parameters, that have the
following function:
: 'L'-parameter : 'W'-parameter : Mode of operation
YES

NO

NO

YES

NO

NO

A relative file is
opened.
A sequential file is
opened for writing.
A file is opened for
reading(REL,SEO,PRG,USR):

In addition to the 'L' parameter the record length must be
given (such as LBO). A DOPEN command of this type looks like
this:
DOPEN#1,"FILE.REL",DO,L80
Here a relative file is opened with a record length of 80
bytes. The declaration of the file parameter is only
necessary once, at the establishment of the file. All later
openings of the file can occur without the parameter
declaration.
DS$ Ii OS:
After a disk error, the complete error message can be
displayed with PRINT DS$ or just the error number with PRINT
DS. of course, the error can be read within a program and
the appropriate branch made. For example:
100 IF DS

=

26 THEN GOTO •••

DSAVE:

A program can be saved on disk
following format is to be noted:

with this command.

Tte

DSAVE (Ddn,)"programname"(,Uda)
BEADER:

x-dISk is formatted with the HEADER command in BASIC 4.0. It
corresponds to the NEW command in BASIC 2.0. The syntax of
the command:

80

Anatomy of the 1541 Disk Drive

or

HEADER "diskname",DO,Iid(U,da)
HEADER Ddn,"diskname" ,lid

Here there are two possibilities to designate the drive. The
id is the diskette identification. If it is not given, the
disk is presumed to be formatted and is merely given a new
name and all files are erased.

RECORD:
This command corresponds to the position command of BASIC
2.0 (DOS 2.6). The read/write head can be positioned over a
record in a relative file, without the need to send the
position over channel 15. The syntax of this command
illustrates how easy this positioning is:
RECORD#lfn,rn(,bp)
The logical file number is obtained from the opened relative
file. 'rn' is the record number (1-65535) and 'bp' is the
position within this record (1-254).
An example: You want to position the head over the twelfth
byte of the 128th record of a relative file opened with the
logical file number 2. The following commaniC accomplishes
this:
RECORD#2,128,12

RENAME:
This RENAME is
similar to the RENAME of BASIC 2.0. The
format of this command:
RENAME (Ddn,)" old name" TO "new name" ( , Uda )
SCRATCH:

This method of erasing files is essentially easier because
files can be erased with one command. The format of this
command:
SCRATCH (Ddn,)"file"(,Uda)
After entering a SCRATCH command the message "ARE YOU SURE?"
which allows the command to be stopped. If the file is
really supposed to be erased, answer 'y' else 'N'. After
erasing the file, the message "FILES SCRATCHED" appears on
the screen.

81

Anatomy of the 1541 Disk Drive
Chapter 2: Advanced Disk Programming

2.1

Direct Access of any Block of the Diskette

When handling files and programs on the
cribed in Chapter 1, we didn't have to
with the organization on the diskette,
operating system (DOS) took care of these

diskette, as desconcern ourselves
because the disk
details for us.

But the DOS offers the capability of accessing each
individual block on the diskette. This gives us a lot of
flexibility - ranging from manipulation of individual files
to creating completely new data structures.
In order to access a block directly, a channel is OPENed to
a data buffer within the 1541 disk drive. It is over this
channel that data is transmitted. The data buffer serves as
an intermediate storage place for the data that is read from
the diskette or written to the diskette. In order to inform
the DOS that we want to work with direct access commands, we
use a special filename in the OPEN command:
OPEN 1,8,2,-'Using this command, logical file number 1 on device 8 (the
disk drive), is associated with a direct access file.
Channel 2 serves to transmit data to and from the disk
drive. The channel number (secondary address in the OPEN
command) may be 2 through 14. Channels 0 and 1 are reserved
for LOAD and SAVE and channel 15 is the command channel. The
choice of a secondary address is arbitrary. You may not use
the same secondary address simultaneously, since the DOS,
upon encountering the second OPEN command with the same
secondary address, closes the previous file using this
channel number. This also occurs
when working with
sequential or relative files.
This form of the OPEN command causes the DOS to search for
a free data buffer and assign it to that channel. By using a
GET# statement immediately after the OPEN we can find the
buffer number that the DOS assigns:
100 OPEN 1,8,2,"#"
110 GET#!, A$
120 PRINT ASC(AS+CHR$(O»
RUN
3

In this case, buffer three was assigned. The buffer numbers
range from 0 to 4. Each buffer can hold 256 characters of
data. The buffers are located in the following memory

82

Anatomy of the 1541 Disk Drive
locations in the VIC 1541:
Buffer number

o
1
2
3
4

Memory location
$300-$3FF, 768-1023
$400-$4FF, 1024-1279
$500-$5FF, 1280-1535
$600-$6FF, 1536-1791
$700-$7FF, 1792-2047

Buffer 4 is normally unavailable, because the BAM is stored
there. If we work with sequential or relative files at the
same time, buffer 3 is also unavailable, because it is used
for the directory. If we want to associate a specific data
buffer for direct access, we can assign it with the OPEN
command.

This associates buffer 3 ($600-$6FF) with channel number 2,
assuming it is still free. Unless you have a pressing reason
to use a specific buffer, you should leave the choice of the
buffer up to the DOS, because the choice of a definite
buffer increases the possibility that it will not be
available.
After opening a channel, you should check the error channel.
130 OPEN 15,8,15
140 GETtIS, A$ : PRINT A$: : IF ST<>64 THEN 140
If the buffer is already in use, you will receive the error
message
70,NO CHANNEL,OO,OO
If no other files are open, you can open up to 4 channels
for direct access. The following example illustrates this:
10
20
30
40
50
60
70
100
110
120
130

OPEN 1,8,15,"10" : 1=2 : REM ERROR CHANNEL
OPEN 2,8,2, "t"
GOSUB 100
OPEN 3,8,3, "i"
GOSUB 100
OPEN 4,8,4, "i"
GOSUB 100
OPEN 5,8,5, nt"
GOSUB 100
OPEN 6,8,6, 't"
GOSUB 100
END
GETtI,A$:PRINT ASC(A$+CHR$(O»
1=1+1 : REM BUFFER NUMBER
GETil,A$ : PRINT A$: : IF ST<>64 THEN 120
RETURN

When RUN, the above program produces the following output:
3
83

Anatomy of the 1541 Disk Drive
00, OK,OO,OO
2
00, OK,OO,OO
1
00, OK,OO,OO

a

00, OK,OO,OO
199
70.NO CHANNEL,OO.OO
As you see, attempting to open a fifth channel for direct
access fai Is.
Transmitting data to and from the buffer usually takes place
using the GET#, INPUT# and PRINT# statements.
If a buffer contains pure text (alphanumeric data) which is
not longer than 88 characters and is separated using CR
(Carriage Return, CHR$(13», it can be read using INPUT#.
However, if the buffer contains control characters or the
text is separated using commas or colons, the INPUT#
statement fails. Then we must use the GET# statement, which
retrieves only one character at a time. GET# does not ailow
null values (CHR$(O»
to be read. In this case, GE1#
receives an empty string and you must check for this
condition as below:
100 GET'2, A$ : IF A$ + •• THEN A$

= CHR$(O)

A simpler alternative to the GET# statement is to use the
statement INPUT*, as is described in section 4.3.1. Here you
can declare how many characters are to be read into a
string. It also handles null values (CHR$(O». You can read
almost the entire buffer (255 characters are possible) with
one command.
In the next section, all commands used for direct access are
described in detail. Keep the following points in mind when
using direct access commands.
When using direct access commands, you must explicitly cause
the blocks on the diskette to be read or written. The direct
access commands are transmitted over command channel 15. The
data that is read from or written to a buffer are
transmitted over a separate channel that is associated with
that buffer. Both channel 15 and the separate channel must
be OPENed before transmission can begin.
1) A PRINT# statement to command channel 15, sends a direct
access command to the DOS.
2) A PRINT# statement to channels 2 thru 14 sends data to a
buffer.
3) An INPUT# or GET# statement to command channel 15 re-

84

Anatomy of the 1541 Disk Drive

turns any error messages detected by the DOS.
4) An INPUT. or GET. statement to channels 2 thru 14, reads
the data from the buffer.

If you are ready to work wi th the block commands and want to
display individual blocks on the screen or change them, you
can use the DOS monitor in section 4.6, which provides a
simple and easy way of doing so.

85

Anatomy of the 1541 Disk Drive
2.2

The Direct Access Commands

2.2.1

The Block-Read Command

B-R

The block-read command instructs the 1541 to read a block
from the diskette into a buffer of a previously opened
direct access file. The block-read command is sent over the
command channel (secondary address 15) to the disk drive.
The block-read command can be shortened to B-R. Because this
command does not read the first byte of the block, you can
substitute the command Ul to read a block. The command has
the following syntax:
Ul channel number drive track sector
You must give the channel number that you used when OPENing
the direct access file. Next follows the drive number, which
is always zero for the VIC 1541, and then the track and
sector numbers of the block you want to read.
10 OPEN 1,8,15
20 OPEN 2,8,2, "#"
30 PRINT#l, ·Ul 2 0 18 0"
This reads the contents of track 18 sector 0 into the buffer
belonging to channel 2. Now you can read the data from this
buffer with GET#2.
40 GET# 2, A$, B$
50 PRINT ASC(AS), ASC(B$)
18

1

Now we have read and displayed the first two bytes in the
buffer. Sector 0 of track 18 contains a pointer to the first
directory block (track and sector) and the BAM for the
diskette.
In the demo program DISPLAY T&S on the TEST/DEMO diskette
(section 4.2.7) this command is used in order to read the
BAM from the disk and to graphically display each record on
the disk.
We can read all 256 bytes of the block from the buffer with
the GET# statement; in our example we will read the diskette
name and ID from position 144.
The blocks which comprise a file are chained to each other.
The first two bytes of each file block contains a pointer to
the track and sector of the following block. Using this
information, you can piece together the usage of disk space
for a file. A track pointer of zero indicates the last
86

Anatomy of the 1541 Disk Drive
block of the file and the pointer which usually contains the
sector number now contains the number of bytes of the last
block which are part of this file. The first sector of a
file can be read with our program in section 4.1.1. The
following small program displays all of the remaining tracks
and sectors that are part of the file.
100
110
120
130
140
150
160
170
180

OPEN 1,8,15
OPEN 2,8,2, ''It''
INPUT "TRACK AND SECTOR ·,T,S
PRINT#l,"Ul 2 O",T,S
GETlt2, T$, S$
T = ASC(T$+CHR$(O»: S = ASC(S$+CHR$(O»
IF T=O THEN CLOSE 2 : CLOSE 1 : END
PRINT "TRACK",T,"SECTOR",S
GOTO 130

Enter 18 and 0 as track and sector to follow the blocks for
the BAM and directory.

2.2.2

The Block-Pointer Command

B-P

The diskette name is located starting at position 144 of
track 18, sector O. using the above example, we have to read
the first 143 bytes of the buffer in order to be positioned
at the diskette name. But the DOS has an easier way to do
this. To access any desired byte of a buffer, you can use
the block-pointer command. using the block-pointer command
the DOS moves to an exact position within the buffer. The
block-pointer command can be shortened to B-P.
The syntax
is the following:
B-P channelnumber position
Now we can read the diskette name directly:
100
110
120
130
140
150
160
170

OPEN 1,8,15
OPEN 2,8,2, ·It''
PRINTltl,"Ul 2 0 18 0"
PRINTlIl,"B-P 2 144"
FOR I = 1 TO 16 : REM MAXIMUM LENGTH
GET#2, A$ : IF A$=CHR$(160) THEN 170
PRINT A$, : NEXT
CLOSE 2 : CLOSE 1

Here we first read the block, set the buffer pointer to
position 144 and then read and print the diskette name which
has a maximum length of 16 characters. A shifted space
(CHR$(160»
indicates the end of the diskette name.
The bytes in the buffer are numbered 0 through 255, the
first byte having the number O. The buffer pointer is auto87

Anatomy of the 1541 Disk Drive
matically set to zero by reading a block with vI. You can,
for example, read byte number 2 after reading the name. You
do this by setting the buffer pointer to this value.
PRINT#l, "B-P 2 2"

2.2.3

The Block-Write Command

B-W

The block-write command allows us to write the contents of a
buffer to a desired block on the diskette. with this, you can
write the block one has sent to the buffer within the disk
drive.
It is possible to read a block into the buffer with the
block-read command, change some bytes, and then write the
block back. The block-write command can be shortened to B-W.
Because this B-W command writes the contents of the buffer
pointer, one usually uses the U2 command which always sets
the buffer pointer to 1. The syntax of the command is
analogous to the B-R command:
V2 channelnumber drive track sector

100
110
120
130
140

OPEN 1,8,15
OPEN 2,8,2, "#"
PRINT#2, "TEST DATA"
PRINT'l, "U2 2 0 1 0"
CLOSE 2 : CLOSE 1

Here the text "TEST DATA" will be written to the buffer
associated to channel 2 and then written to track 1 sector 0
of the diskette. The V2 command does not change the contents
of the buffer.
Here's an example of using the block-write command to change
the diskette name that we read in the last section. For this
we must fill the new name with 16 characters ending with a
shifted spaces CHR$(160), so that we can write it to the
disk. We will again use the block-pointer command to set the
buffer pointer directly to the desired position within the
buffer.
100
110
120
130
140
150
160
170
180
190

OPEN 1,8,15
OPEN 2,8,2, "I"
PRINTl1,"Ul 2 0 18 0"
PRINT,l,"B-P 2 144"
A$="NEW FILE NAME"
IF LEN(A$)<16 THEN A$=A$+CHR$(160)
PRINT#2,A$;
PRINTl1,"U2 2 0 18 0"
CLOSE 2
PRINTI1,"IO" : CLOSE 1
88

GOTO 150

Anatomy of the 1541 Disk Drive
First we read track IB sector 0 into the buffer, set the
buffer pointer to the position of the diskette name and
write a new 16 character name to the buffer. Note that the
diskette name is changed in the buffer only. But in line
170, the buffer contents are written to the same block which
changes the name permanently on the diskette. Next channel 2
is closed. Finally the diskette is initialized so the BAM
and name in the DOS memory are updated. Get the directory
with
LOAD"$",B
LIST
on the screen to verify that the diskette name has changed.

2.2.4

The Block-Allocate Command

B-A

The block-allocate command has the task of indicating in the
BAM (block availability map) is a particular diskette block
is being used. The block allocate command can be shortened
to B-A. For program, sequential or relative files, as
diskette blocks are used, the BAM is updated to note that
the block is no longer available.
But blocks written using
the direct access commands are not automatically allocated.
When blocks used in this manner are not allocated, the
possibility exists that they will be overwritten when other
files are used. The block-allocate command can be used to
prevent this overwriting. The block-allocate command has the
following syntax:
B-A drive track sector
With this the corresponding block in the BAM is marked as
allocated and is protected from being overwritten by other
files. If the block was already allocated, the error channel
returns error message 65,'NO BLOCK'.
lOO
110
120
130
140

OP EN 1, B , 15
INPUT "TRACK, SECTOR ":T,S
PRINT#l, "B-A O":T:S
INPUT#l, A$,B$,C$,D$
PRINT A$","B$","C$","D$

Using this program you can input a track and sector number
of a block that you want to allocate. If the block is still
free, it was allocated and the message 00, 01(,00,00 is
returned. If that block is already allocated, the message
65,NO BLOCK,TT.SS
is returned. In this case TT and SS
contain the next higher numbered free block on the diskette.
This tells you that the requested block is allocated but the
block at TT,SS is still available. If error message 65
returns zeroes as the track and sector numbers, it means
89

Anatomy of the 1541 Disk Drive
that no block with a higher track and/or sector number is
available. The following program automatically allocates the
next free sector:
100
110
120
130
140
150
160
170
180
190

OPEN 1,8,15
INPUT "TRACK, SECTOR ";T,S
PRINT.l, "B-A O";T;S
INPUTll, A$,B$,TT,SS
IF A$ = "00" THEN 190
IF A$<>"6S" THEN PRINT A$","B$","TT","SS
IF TT=O THEN PRINT "NO MORE FREE BLOCKS"
IF TT=18 THEN TT=19 : SS=O
T=TT : S=SS : GOTO 120
PRINT "TRACK" TT "SECTOR" SS "ALLOCATED."

END
END

The test for track 18 in line 180 prevents a block in the
directory from being allocated. An additional error message
in connection with the B-A command is interesting. If one
attempts to allocate a block that does not exist, for
example, track 20 sector 21, one received the error message
66,ILLEGAL TRACK OR SECTOR,20,21
Marking a block as allocated in the BAM prevents it from
being overwritten by other files. The block will be
recognized as allocated until the command VALIDATE (COLLECT
in BASIC 4.0) is issued. The VALIDATE command rebuilds a new
BAM by rechaining the blocks of individual files and marking
each block as belonging to a a new BAM. Unclosed files,
marked in the directory with * are deleted. All blocks
allocated with the B-A command and those not belonging to a
properly closed file are freed.
So, if you allocate blocks
that do not belong to a file that appears in the directorl,
you should not use the VALIDATE command, or the blocks will
be freed, thus destroying your file.

2.2.5

The Block-Free Command

B-F

The block-free command performs the opposite function of the
block-allocate command. It marks a block as not allocated
(free) in the BAM. The block-free command can be shortened
to B-F.The syntax is analogous to the block-allocate
command:
B-F drive track sector
100 OPEN 1,8,15
110 PRINTll, "B-F 0 20 9"
Here the block in track 20 sector 9 is freed in the BAM. If
this block is already free, no error occurs.

90

Anatomy of the 1541 Disk Drive
Allocating and freeing blocks has an effect only on the
blocks used by program, sequential or relative file by the
DOS. The block-write and block-read commands do not check
the BAl4 before overwriting blocks. With these commands you
can write to blocks marked as allocated in the BAM. If, for
example, you have a disk containing only direct access
files, it is in principle unnecessary to allocate written
blocks because no other files will be written on the
diskette. In this case, you can use the directory blocks in
track 18 and have 672 blocks available on the VIC 1541
diskette.

2.2.6 The Block-Execute Command

B-E

The block-execute command allows a block to be read from
diskette into a buffer and then the contents of the buffer
to be executed as a machine language program. You can cen
write routines that the DOS is supposed to execute with the
B-W or U2 command to a sector and later load it into a
buffer with the block-execute program where it will be
executed as a machine language program. Naturally, this
presupposes knowledge of the internal workings of the DOS.
If you want to use the B-E command, you usually give the
buffer number in the OPEN command, in case the machine
language program is not relocatable and is written for a
specific buffer. The block-execute command has the following
syntax:
B-E channelnurnber drive track sector
100 OPEN 1,8,15
110 OPEN 2,8,2, "#3"
120 PRINT#l, "B-E 2 0 17 12"
Here buffer 3 ($600-$6FF) is assigned to channel 2. The
contents of track 17 sector 12 is loaded into this buffer
and there the machine language program is executed.
The block-execute command is a combination of the block-read
and memory-execute commands. Examples of the design of
machine language programs to execute in the DOS are found in
section 2.4 by the memory commands.

91

Anatomy of the 1541 Disk Drive
2.3 Uses of direct access
What do the direct access commands permit us to do?
Here is a sample of their use:
By manipulating individual sectors you can make changes to
the BAM sector (Track 18, Sector 0) such as changing the
diskette name or 10.
You can make changes to the DIRECTORY (beginning at Track
18, sector 1). Each file entry in the directory has unused
space. You can use the unused space to store additional
information.
You can change file names in the directory by using direct
access commands.
You can follow the "chaining" of the blocks in a file to
determine if the file is intact.
You can CLOSE an unclosed file by setting bit 7 of the file
type indicator in the directory. For example, you can change
the file type indicator from $02 to $82. Normally these
files are indicated in the directory with an asterisk: after
the above change the asterisk will disappear.
Each file entry also contains a "lock" which disallows
deletion (SCRATCH command). If you set bit 6 of the file
type then the file is said to be locked and not available
for deletion. These entries have the < symbol after the type
designation in the directory listing. Using this bit of
knowledge, you can protect important programs on your
diskette from accidental erasure. More information on this
topic is found in section 4.1.
If you are interested in making such changes, you may want
to read an entire sector and display it on the screen,
change it, and write it back again. Such a program called
the DISK MONITOR is described in section 4.6. Before you
begin with such experiments, however, you should make a copy
of your diskette. A directory or BAM error can result in the
loss of the entire diskette contents.
Have you ever accidentally scratched a program or file from
a diskette? As long as you haven't written any other
programs or data to the diskette, you can recover this
scratched file. Scratching a file simply sets the file type
to 0 in the directory and frees the allocated blocks. You
need only search the directory entries for the file and
restore the file type: $81 for SEQ, $82 for PRG, $83 for
USR, and $84 for REL. After restoring the file type, you
should use the VALIDATE command to reallocate the blocks
again (for example: OPEN 1,8,15:PRINT#1,"VO").

92

Anatomy of the 1541 Disk Drive
other uses of direct access can provide the means for
creating new data structures that the DOS normally does not
recognize. You can undertake the management of the new file
yourself, and use the direct access commands for reading and
writing. Such a data structure is the ISAM file. ISAM is an
abbreviation for Indexed Sequential Access Method. With an
ISAM file, you can directly access each record, similar to
the relative file. However, access is not by the record
number, however, but by a key or index. This index is a
field within the record. If, for example, a record consists
of 5 fields, last name, first name, street, city/state and
zip code, last name can be defined as the access key. To to
read the record Muller, the command is simply' read record
"Muller"'. We need not concern ourselves with record number
or other ordering criteria and can select which record we
want to read, change, write or erase with clear text. In
such an ISAM file system, the index is usually saved
separately, together with the information where the data
record can be found on the disk. Such an ISAM file
management with very powerful additions as described here,
is found along with other features in the program
development system MASTER 64, also available for the
Commodore 64 from Abacus Software.

93

Anatomy of the 1541 Disk Drive
2.4

Accessing the DOS - The Memory Commands

In section 2.2.6 we saw a way to load a program into DOS
memory and execute it. With the memory commands, we can
access each byte of the DOS and execute programs in RAM and
ROM. For instance, we can access the work space of the DOS
and read the number of free blocks on the disk or get the
disk name from the BAM buffer. By writing into the DOS RAM
we can change constants such as the device number of the
drive or the number of read attempts for a block until an
error message results. Furthermore, we can execute routines
inside the DOS memory. These can be DOS ROM routines or your
own, that are stored in a buffer and executes there. Of
course this presumes knowledge of 6502 machine language and
of the method of operation of the DOS. We hope this book is
be helpful for the latter. Now follows a description of the
commands and examples of their use.

2.4.1

The Memory-Read Command

M-R

Using this command, you can access each byte of the DOS. The
memory-read command can be shortened to M-R. The memory-read
command is transmitted over the command channel. The byte
read is then returned over the command channel where it can
be retrieved with GET#. The syntax of the command looks like
this:
M-R CHR$(LO) CHR$(HI)
LO and HI signify the low and high bytes of the address in
the DOS that should be read. The following program asks for
an address and reads the contents of the address out of the
DOS.
100
110
120
130
140
150
160

INPUT"ADDRESS ";A
HI = INT (A!256)
LO = A-256*HI
OPEN 1,8,15
PRINT#I, "M-R";CHR$(LO);CHR$(HI)
GET#!,AS
PRINT ASC(A$+CHR$(O»

For instance, if we want to know the number of free blocks
on a diskette, we don't have to re~d the entire directory,
rather we can read the appropria~ ~ bytes directly from the
DOS storage. This may be necessary i~ files are to be
established by a program and you don't know if there is
enough space on the disk.
100 OPEN 1,8,15,"10"
110 PRINTll, "M-R" CHR$(250) CHR$(2)
120 GET#!, A$ : IF A$='''' THEN A$=CHR$ (0)
94

Anatomy of the 1541 Disk Drive
130
140
150
160

PRINT#l, "M-R" CHR$(252) CHR$(2)
GET#l, B$ : IF B$="· THEN B$=CHR$(O)
PRINT ASC(A$) + 256 * ASC(B$) "BLOCKS FREE"
CLOSE 1

With this syntax, an M-R command must be given for each byte
that is to be read. As you can gather from the DOS listing
and through checking and verifying, one can read more than
one byte at a time with a M-R command. You need only give
the number of bytes to be read as the third parameter:
M-R CHR$(LO) CHR$(HI) CHR$(NUMBER)
We can use this to read the name of a diskette from the BAM
buffer storage. Before this can be done, the diskette must
be initialized so that the current diskette name is stored
in the buffer at address $700, out of which we will read the
name of the disk with the M-R command.
100
110
120
130

OPEN 1,8,15, "10"
PRINT#l, "M-R" CHR$(144) CHR$(7) CHR$(16)
INPUT#l, A$
PRINT AS

This is a simple way to read the name of the diskette (16
characters padded with shifted spaces (CHR$(160)). With this
you can check if the correct diskette is in the drive.
The disk buffer can also be read using this method. It also
allows parts of the DOS to be manipulated by copying the
contents of the ROM to a buffer where it can be changed and
executed. This is explained in the next two sections.

2.4.2

The Memory-Write Command

M-W

The complement command of memory-read is the command to
write data in the DOS storage memory-write or
M-W. writing
is allowed only to DOS RAM - page zero, stack, and buffers.
It is possible to send several bytes with one command. The
syntax look like this:
M-W CHR$(LO) CHR$(HI) CHR$(NUMBER) CHR$(DATAl) CHR$(DATA2)
The number of bytes as specified by NUMBER can be
transmitted, theoretically 255, but because the input buffer
holds only 40 characters, the number of bytes is limited to
34. A possible use of this command is to change the address
number (see program 'DISK ADDRESS CHANGE', section 4.2.3).
The address is stored in two memory locations in page zero.
The device number plus $20 (32 decimal) is stored in address
$77 (119 decimal) for LISTEN, for receiving data from the
computer. The address immediately following contains the
95

Anatomy of the 1541 Disk Drive
device number plus $40 (64 decimai) for TALK, for sending
data to the computer. Because the addresses are saved
separately. It is possible to use different send and receive
addresses. In the following example, the receive address is
set to 9 and the send address to 10.
100 OPEN 1,8,15
110 PRINTt1, "M-W· CHR$(119) CHR$(O) CHR$(2)
CHR$(9+32) CHR$(10+64)
120 CLOSE 1
140 OPEN 1,9,15
150 OPEN 2,10,15
160 PRINTtl,"IO"
170 INPUT#2,A$,B$,C$,D$
180 PRINT A$",UB$","C$","D$
00, OK,OO,OO
Programs cannot be loaded this way because the DOS will try
to load the program using the same address that the filename
was sent under.
Changing the device number is necessary if you want to use
more than one disk drive with a single computer. To this
end, change the device address of the second drive to 9.
This software change remains in effect only until a reset
(for example, turning the drive off). If the change needs to
be permanent, you can change the with DIP switches or cut
the circuit board jumper inside the drive.
Because many parameters of the DOS are in RAM, you can make
extensive changes to the function of the DOS, such as the
step size, with which the number of sectors per track is
determined (address $69 (105 decimal), normally contains
10). We can also specify the number of attempted reads until
an error results (address $6A (106 decimal), contains 5).
More addresses of parameters can be found in section 3.1.2.

2.4.3

The Memory-Execute Command

M-E

Using this command you can call up and execute machine
language programs in the DOS memory. The memory-execute
command can be shortened to M-E. The programs must end with
RTS (Return from Subroutine, $60). The syntax of the
command:
M-E CHR$(LO) CHR$(HI)
Again, LO and HI are the low and
address of the machine language
call up routines in the DOS ROM
written to a buffer with M-W
96

high bytes of the starting
routine. It is possible to
as well as our own routines
and there executed. As an

Anatomy of the 1541 Disk Drive
example, you can call up a routine that creates an error
message. For example, address $EFC9 is the entry point for
message 72, 'DISK FULL'. The, example looks like this:
100
110
120
130

OPEN 1,8,15
PRINT#l,"M-E" CHR$(20l) CHR$(239)
INPUT#l,A$,B$,C$,D$
PRINT A$ .," B$ ",. C$ .," D$

In line 110, the address $EFC9 is divided into a low byte of
$C9 (201) and high byte of $EF (239) and sent as the
parameters of the M-E command. Then the error channel is
read and the message displayed.
72.DISK FULL,OO,OO
If you want to run your own programs in the 1541 drive, the
program should be w·ritten to a buffer and .there called with
M-E. Should this program be used more often, the contents of
the buffer can be written to a block on the diskette. It can
then be executed with the B-E command, which loads the
contents of the block in the buffer and then automatically
starts the routine. As a suggestion for your own program in
DOS, you can display the directory in a different form, with
additional parameters, similar to the program in section
4.1.1. In addition, you could count the number of files on
the disk and display that. using such a routine you can get
a much clearer understanding of how the directory is created
in the DOS listing. If you are clear on the matter of the
new directory format, you are ready to take the additionel
parameters from the directory entries and assemble them in
the desired format.

2.4.4

The User Commands

U

Using the USER commands there are two possible ways of
executing programs in the drive. The user commands have the
following syntax:
UX
X can be a letter from A to J or a digit from 1 to 9 or 'I'
(which takes the place of 10). When a command is called, a
jump is made to the following addresses in DOS:
UA
UB
UC

Ul
U2
U3
U4

UE

U5
u6
U7

un
UF
UG

$CD5F
$DC97
$0500
$0503
$0506
$0509
$050C

substitute for 'Block-Read'
substitute for 'Block-Write'

97

Anatomy of the 1541 Disk Drive

UH
UI
UJ

U8
U9

U:

$050F
$FFOI
$EAAO

reset

You are already acquainted with the commands Ul and U2 (also
UA and UB)1 they serve as substitutes for BLOCK-READ and
BLOCK-WRITE. The commands U3 to U8 (UC to UH) jump to
addresses within buffer 2 (address $500 (1280) - see section
2.1). If you want to use several commands, a jump table to
individual routines can be placed therel if only one user
command (U3) is used, the program can begin directly at
$500.
The user command UJ jumps to the reset vectorl
drive is then reset.
100
110
120
130

the disk

OPEN 1,8,15
PRINT#I,"UJ"
FOR 1=1 TO 1000 : NEXT
GET#I,A$ : PRINT A$ : IF ST<>64 THEN 130

73,CBM DOS V2.6 1541,00,00
Line 120 waits for the reset to take place. Then the
initialization message is retrieved in line 130.
By using the user commands, parameters can be passed to the
routines. The complete command string is put in the input
buffer at $200 (512). possible parameters are addresses,
command codes, and filenames. This way, the user commands
can be utilized to expand the commands of the disk or to
realize a new data structure. Whole user commands can
replace the M-E command with its corresponding addresses 1
the user-call is shorter and clearer.

98

Anatomy of the 1541 Disk Drive
Chapter 3: Technical Information

3.1

The Construction of the VIC 1541

3.1.1

Block Diagram of the Disk Drive

-

1''03

!

Q

.)

I("

iL
N

<
o-;

C-

:>

:>

N
N

Ltl
II)

!'

0

~

.

0::

'::lO:}OW

.

)(S-':O '

til
0.
al

til
0
al

<
~

Q
Q

....

<

~

<
0-;

:>

[:

)

:t
H

v\

\j

0
N
Q
III
IC

'--

til
0
Q:l

)

IIQ

Jli

:£

<
z
<

....-

til
til

Eo<

~

"'" a:}l.lM-peag §
.IO:}OW
6uldda:}s '

H

K

:}:>a:}o.Id '"
-a:}l.IM "

0::

H

:::>

Il<
U

99

r--N
N

Ltl
IC

....... f1 p
r-

-

I
U

IlQ
H

t-l

<
0-;
0::

IlQ
til

-

Anatomy of the 1541 Disk Drive
3.1.2

DOS Memory Map -

ROM, RAM, I/O

Memory map of the VIC 1541 disk drive

65535

$FFFF
16K
Control system

$eooo

49152

7183

$lCOF
VIA Disk Control

7168

$lCOO

6159

$180F
VIA serial bus

6144

$1800

2047

$07FF
2 K

RAM

o

$0000

100

Anatomy of the 1541 Disk Drive
Layout of the I/O Ports (VIA 6522)
VIA 6522 1, Port for Serial Bus
S1800
S1801
S1802
S1803

Port B
Port A
Direction of Port B
Direction of Port A

S1805

Timer

PB
PB
PB
PB
PB
PB
CB

DATA IN
DATA OUT
CLOCK IN
CLOCK OUT
ATN A
Device address
ATN IN

0:
1:
2:
3:
4:
5,6:
2:

VIA 6522 2, Port for Motor and Read/Write Head Control
SlCOO
SlCOl
SlC02
SlC03

Port B, control port
Port A, data to and from read/write head
Direction of Port A
Direction of Port B

PB
PB
PB
PB
PB

STP I
STP 0
MTR
ACT
WPS

0:
1:
2:
3:
4:

PB 7 :
CA 1:
CA 2:

step motor for head movement
drive motor
LED on drive
Write Protect Switch

SYNC
Byte ready
SOE

101

Anatomy of the 1541 Disk Drive
The Layout of the Important Memory Locations

o

10
12
14
18
20
22
32
48
57

$00
$01
$02
$03
$04
$06-$07
$08-$09
$OA-$OB
SOC-SOD
$OE-$OF
$12-$l3
$14-$15
$16-$17
$20-$21
$30-$31
$39

58
61
63
67

$3A
$3D
$3F
$43

71

$47

1
2
3
4
6
8

73
74
81
105
106
111
119
120
121
122
124
125
127
128
129
l30
131
132
l33
l39
148
153
155
157
159
161
163
165

$49
$4A
$51
$69
$6A
$6F-$70
$77
$78
$79
$7A
$7C
$7D
$7F
$80
$81
$82
$83
$84
$85
S8B-$8D
$94-$95
$99-$9A
$9B-$9C
$9D-$9E
$9F-$AO
$A1-$A2
$A3-$A4
$A5-$A6

Command code for buffer 0
Command code for buffer 1
Command code for buffer 2
Command code for buffer 3
Command code for buffer 4
Track and sector for buffer 0
Track and sector for buffer 1
Track and sector for buffer 2
Track and sector for buffer 3
Track and sector for buffer 4
ID for drive 0
ID for drive 1
ID
Flag for head transport
Buffer pointer for disk controller
Constant 8, mark for beginning of data
block header
Parity for data buffer
Drive number for disk controller
Buffer number for disk controller
Number of sectors per track for
formatting
Constant 7, mark for beginning of data
block header
Stack pointer
step counter for head transport
Actual track number for formatting
Step size for sector division (10)
Number of read attempts (5)
Pointer to address for M & B commands
Device number + $20 for listen
Device number + $40 for talk
Flag for listen (1/0)
Flag for talk (1/0)
Flag for ATN from serial bus receiving
Flag for EOI from serial bus
Drive number
Track number
Sector number
Channel number
Secondary address
Secondary address
Data byte
Work storage for division
Actual buffer pointer
Address of buffer 0 S300
Address of buffer 1 $400
Address of buffer 2 $500
Address of buffer 4 $600
Address of buffer 5 $700
Pointer to input buffer $200
Pointer to buffer for error message $2D5
102

Anatomy of the 1541 Disk Drive
181
187
193
199
212
213
214
215
231
249
256-325
512-552
586
600
601
602
628
632
663
640-644
645-649
725-761
762/764
768-1023
1024-1279
1280-1535
1536-1791
1792-2047

$B5-$BA
$BB-$CO
$Cl-$C6
$C7-$CC
$D4
$D5
$D6
$D7
$E7
$F9
$100-$145
$200-$228
$24A
$258
$259
$25A
$274
$278
$297
$280-$284
$285-$289
$2D5-$2F9
$2FA/$2FC
$300-$3FF
$400-$4FF
$500-$5FF
$600-$6FF
$700-$7FF

**

**

Record
10, block
10
Record
hi, block
hi
Write pointer for reI. file
Record length for reI. files
Pointer in record for reI. file
Side sector number
Pointer to data block in side sector
Pointer to record in reI. file
File type
Buffer number
Stack
Buffer for command string
File type
Record length
Track side-sector
Sector side-sector
Length of input line
Number of file names
File control method
Track of a file
Sector of a file
Buffer for error message
Number of free blocks
Buffer 0
Buffer 1
Buffer 2
Buffer 3
Buffer 4

103

Anatomy of the
3.2

15~1

Disk Drive

Operation of the DOS - An Overview

The VIC-1541 is an intelligent disk drive with its own
microprocessor and control system (Disk Operation System,
DOS). This means that no memory space or processing time is
taken from the computer. The comput1!!r needs only transm it
commands to the disk drive, which it then executes on its
own.
The disk performs three tasks simultaneOUSly: Firstly, it
manages data traffic to and from the computer. secondly, it
interprets the commands and performs the management of files
and the associated communications channels and block buffer.
Thirdly, i t handles the hardware-oriented related functions
of the disk drive - formatting, reading and writing, etc.
These tasks are carried out simultaneously by the 6502
microprocessor in the VIC 1541. This is possible with the
help of the interrupt technique. Only in this way can three
tasks be executed simultaneously.
Most of the DOS is concerned with interpreting and executing
the transmitted commands. The reception of data and commands
from the computer is controlled by interrupts. If the
computer wants to talk to a peripheral device, it sends a
pulse along the ATN line (ATteNtion, see section 5.11. This
generates an interrupt at the disk drive. The DOS stops its
current task and notices that the computer wants to send
data. The DOS then finishes the original task. After that,
the DOS will accept further data and commands from the the
computer. If the command is finished, the DOS stays in a
wait loop until new commands arrive from the disk.
The execution of a command at this level is limited to the
logical processing of the command, the management of the
communications channel to and from the computer and the
preparation and retrieval of data to be written or read,
respectively. The tasks of a disk controller, formatting
diskettes and writing and reading individual blocks, must
, also be performed by the processor.
These tasks are again interrupt controlled. Regular programs
in the disk are interrupted every 14 milliseconds by a
built-in timer, and control branches to a program that
fulfills the tasks of a disk controller. Communications
between the two independent programs is handled through a
common area of memory, in which the main program places
codes for the disk controller program. If the interrupt
program is active, it looks at the memory locations to
determine which activities are demanded, such as formatting
a diskette. if this is the case, the drive and head motors
are set in motion. At the end of the interrupt routine, the
main program examines the memory locations to determine if
the task was carried out by the disk controller, or if it
104

Anatomy of the 1541 Disk Drive
must wait yet. In this way, the main program is informed in
case of an error, such as a read error or if a write protect
tab is present. The main program can then react
appropriately and display the error message, for example.
In the large CBM disks, two 6504 microprocessors are used as
a disk controller. Communication again occurs over a common
area of memory.
An overview of the storage layout of the DOS such as the I/O
primitives for managing the diskette and serial bus can be
found in the previous section.
This overview of the work of the DOS is naturally just a
rough outline. If you want more exact information, refer to
the DOS listing of the VIC 1541 in section 3.5, in which the
complete 16K control system is documented.

105

Anatomy 'of the 1541 Disk Drive
3.3

The Structure of the VIC 1541 Diskette

The diskette of the 1541 is divided into 35 tracks. Each
track contains from 17 to 21 sectors. The total number of
sectors is 683. Because the directory occupies track 18, 664
data are available for use, each containing 256 bytes. The
tracks are layed out as follows:
NUMBER OF SECTORS :

TRACK

:------------------------------:
21
19
18
17

:lT017

:18 TO 24
:25 TO 30
:31 TO 35 •.

The varying number of sectors per track is necessitated by
the shortening of the tracks from the midpoint on.

3.3.1

The BAM of the VIC 1541

BAM is an abbreviation for Block Availability Map. The BAM
indicates whether a block on the diskette is free or
allocated to a file. After every manipulation of blocks
(saving, deleting, etc.) the BAM is updated. When the BAM
indicates that a file to be saved requires more blocks than
are available, an error message is given. When a file is
OEPNed, the BAM in the DOS storage is updated, and is
rewritten to disk when the file is CLOSEd. Commands that
have a write or delete function read the BAM, update it, and
rewrite it to the diskette. The BAM is organized as follows
on track 18 sector 0:
: Track 18, sector 0
: BYTE

: CONTENTS : MEANING

0,1

($OO-$Ol)

$12,$01

2

($02)

$41

($03)
3
4-143 ($04-$8F)

*

1

= block

$00

free; 0

Track and sector of the 1st· :
block of the directory
ASCII character 'A' ;
indicates 1541 format
Zero flag for future use
Bit map of free and
allocated blocks *

= block

allocated

The bit map of the blocks is organized so that 4 bytes
106

Anatomy of the 1541 Disk Drive
represent the sectors on a track. As can be inferred from
the following table, the first of the 4 bytes contain the
number of free blocks in the track. The other 3 bytes (24
bits) indicate which blocks are free and which are allocated
in this track.
Structure of the BAM entry of a track:
: BYTE

o

: CONTENTS
Number of available blocks in this track
Bit map of sectors 0-7
Bit map of sectors 8-15
Bit map of sectors 16-23

1
2
3

4 bytes of a track designation in the BAM:
: Track 18, sector 0, bytes 4-7 (track 1) :
: 00001010
($OA)

00000000 00000011 11111111 :
($00)
($03)
($FF)

: 10 free
: blocks

o = allocated

1

=

free

Using a simple program, you can read the first byte of each
track entry in the bit map, add them up and find the total
number of free blocks on the diskette.

3.3.2

The Directory

The directory is the table of contents of the diskette. It
contains the following information:
-

disk name
disk 10
DOS version number
filenames
file types
blocks per file
free blocks

This directory is loaded into memory with the command LOAD
-$-.8. A program previously in memory will be destroyed! It
can be displayed on the screen with the LIST command.
The directory occupies all of track 18 on the disk. The file
entries follow the directory header. Each block accommodates
107

Anatomy of the 1541 Disk Drive
a maximum of 8 file entries. Because the BAM and the header
occupy one block, 18 blocks are left for file entries. A
total of 144 files may reside on one diskette (18 blocks
with 8 entries each).
Format of the directory header:
: Track 18, sector 0
: BYTE,

: CONTENTS : MEANING

144-161 ($90-$A1)
162,163 ($A2-$A3)
($A4)
164
165,166 ($A5-$A6)

$AO
$32,$41

167-170 ($A7-$AA)
171-255 ($AB-$FF)

$AO
$00

Disk name (padded with
shifted spaces)
Disk 10 marker
Shifted Space
ASCII characters "2A "
(format)
Shifted Space
not used, filled with 0

: *

Bytes 180 to 191 have the contents "BLOCKS FREE" on
: many diskettes

The Diskette Name:
The name of the diskette can be a maximum of 16 characters
in length and is established when the diskette is formatted.
If fewer then 16 characters are given, the rest is filled
with shifted spaces ($AO). The following BASIC routine reaos
the name and saves it in the string variable DN$:
100 OPEN 15,8,15,"10"
110
120
130
140
150
160
170

180
190
200
210

REM COMMAND CHANNEL 15
AND DISK INITIALIZED
OPEN 2,8,2,"#"
REM DATA CHANNEL 2 OPENED
PRINTjl15, "B-R":2; 0; 18; 0
REM TRACK 18, SECTOR 0 READ
AND PLACED IN CHANNEL 2
PRINT#15,"B-P";2;144
REM BUFFER-POINTER TO BYTE
144
DN$=""
REM STRING DN$ IS ERASED
REM LOOP TO READ THE 16 BYTES OF THE NAME
FOR 1=1 TO 16
:.:GET# 2 ,X$
REM READ A BYTE
::IF ASC(X$)=160 THEN 200
REM IGNORE SHIFT SPACE
: :DN$=DN$+X$
REM BYTE ADDED TO DN$
NEXT I
CLOSE 2:CLOSE 15
REM CLOSE CHANNELS

After running the routine, the string DNS contains the disk
name.

108

Anatomy of the 1541 Disk Drive
Diskette ID:

The diskette ID is two characters in length and is specified
when formatting the diskette. The DOS uses this ID to detect
if a diskette in the drive has been replaced. If so, then
the DOS performs an INITIALIZE. Initializing a diskette
loads the BAM into memory in the drive. This way, the actual
BAM is always in memory, provided the ID given when
formatting is always different. Should this not be the case,
a diskette must be initialized explicitly by using the
INITIALIZE command.

3.3.3

The Directory Format

Blocks 1 through 19 on track 18 contain the file entries.
The first two bytes of a block point to the next directory
block with file entries. If no more directory blocks follow,
these bytes contain SOD and SFF, respectively.
: Track 18, sector 1
: Byte

: Contents

0,1

(SOO,SOl)

2-31
34-63
66-95
98-127
130-159
lfi2-191
194-223
226-255

(S02-S1F)
(S22-S3F)
(S42-S5F)
(S62-S7F)
(S82-S9F)
(SA2-SBF)
(SC2-SDF)
(SE2-SFF)

Track and sector number of the
next directory block
Entry of 1st file
Entry of 2nd file
Entry of 3rd file
Entry of 4th file
Entry of 5th file
Entry of 6th file
Entry of 7th file
Entry of 8th file

Format of a Directory Entry:
Each file entry consists of 30 bytes, the functions of which
are described below:

109

Anatomy of the 1541 Disk Drive

: CONTENTS

: BYTE

o
1,2

(SOO)
(SOl,S02)

3-18
19,20

(S03-S12)
(S13,S14)

21

(SIS)

22-25
26,27

(S16-S19 )
(SlA-SIB)

28,29

(SIC-SID)

File type
Track and sector number of the
first data block
Filename (padded with "SHIFT SPACE"
Only used for relative files
(track and sector of the first
side-sector block)
Only used for relative files
(record length)
Not used
Track and sector number of the new
file when overwritten with the @:
Number of blocks in the file (low
byte, high byte)
Fi1e Type Marker:

Byte 0 of the file entry denotes the file type. Bits 0-2 are
used to indicate the 5 file types •. Bit 7 indicates if the
file has been CLOSEd properly. Closing a file sets bit 7. An
unclosed file is denoted with an asterisk in front of the
file type in the directory listing. If, for example, a
sequential file "TEST" is opened and the directory is
listed, this file will be represented like this:
12

"TEST"

*SEO

If the file is CLOSEd again, the asterisk does not appear in
future directory listings. If this file remains unclosed and
later opened, the error message "WRITE FILE OPEN" will
appear.
The File Type:
In order to understand the function of byte 0 in the file
entry, the file type, a table of all file types follows:
:

File type

:

Bit mask opened
HEX

: 7654 3210

:

Bit mask closed
HEX

: 7654 3210

-------------------------------------------------------DELeted
SEOuential
ProGram
USeR
RELative

0000
0000
0000
0000
0000

0000
0001
0010
0011
0100

SOO
SOl
S02
S03
$04

1000
1000
1000
1000
1000

0000
0001
0010
0011
0100

S80
$81
S82
S83
$84

perhaps you have noticed that bits 3-6 have no function. Rut
we verified with help from the DOS listing, bit 6 has a
110

Anatomy of the 1541 Disk Drive
function:
BIT 6 OF THE FILE TYPE DENOTES A PROTECTED FILE!
If you set this bit to I, the corresponding file can no
longer be deleted. This is designated in the directory
listing with a < next to the file type. Because setting this
bit requires some complicated commands, you will find a
program in chapter 4 of this book with which you can
protect, unprotect, and delete files.
Track and sector of the first Data Block
Bytes 1 and 2 of the file entry point to the first data
block of the file. The first byte contains the track and the
second the sector number where the file begins. The first
data block, in turn contains a pointer to the second block
of the file (also contained in the first two bytes of the
block). The last data block of the file is indicated by a
first-byte value of $00. The second byte contains the number
of bytes used in this last sector.
This concatenation can be explained with the help of the Dl'S
MONITOR, contained in this book:
> :BO
> :B8
>:CO
> :C8
> :00
>: D8
):EO
): E8
>:FO
>: F8

AD
00
00
2F
AD
00
00
4B
48
00

AD
00
00
53
AD
00
00
20
41
00

AD
00
81
30
AD
00
82
41
4E
00

AD AD 00
00 00 00
13 09 54
31 AD AD
AD AD 00
00 00 00
10 00 44
44 44 52
47 45 00
00 00 00

00
DB
31
AD
00
06
49
20
00
04

00
00
32
AD
00
00
53
43
00
00

·•.•••
.......
T12
/SOI

·•••..
.......
DIS
K ADDR C
BANGE •••

This is an extract from the directory (track 18, sector 1)
of the TEST/DEMO diskette. You can follow the organization
of the file DISK ADDR CHANGE. The entry of this file begins
at byte $E2 and ends with byte $FF. This is a PRG file,
which can be recognized by the file type $82 in byte $E2.
This file comprises 4 blocks on the disk. This is evident
from bytes $FE and $FF. Bytes SE3 and SE4 of the entry
address the first data block of the file {SID, SOD,
corresponding to track 16, sector OJ.
Let's look at a section of this block:
>:00
>:08
):10
>:18
):20
>: 28

10
97
32
93
49
45

OA 01 04 OF
35 39 34 36
00 39 04 6E
13 11 11 11
56 45 20 41
53 53 20 43

04
38
OD
11
44
48

64
2C
99
44
44
41

00
31
22
52
52
4E
111

• •••.• $ •
.59468,1
2.9 ••.• "
• ••••• DR
IVE ADDR
ESS CHAN

Anatomy of the 1541 Disk Drive
>:30
>:38
>:40
>:48

47
41
99
4F

45
4D
22
46

20
22
11
46

50
00
54
20

52
59
55
41

4F
04
52
4C

47
6F
4E
4C

52
00
20
20

GE PROGR

AM".Y./.
••• TURN
OFF ALL

This block contains the first part of the program. It is
stored on the diskette exactly as it is stored in the
computer's memory. The BASIC commands are converted to one
byte codes called tokens. This is why only the text can be
recognized in the right hand translation of the hexadecimal
codes. The first two bytes of this data block indicate the
second data block ($10 and $OA, track 16, sector 10) from
with this section follows:
>:00
>:08
>:10
>:18
> :20
>:28
>:30
>:38
>:40
>:48

10
00
8F
52
45
36
48
44
B4
20

14
80
20
49
00
30
41
52
00
53

34
20
46
56
39
30
4E
45
99
45

30
33
49
45
05
3A
47
53
22
4C

00
30
4E
20
AA
20
45
53
11
45

ID
30
44
54
00
8F
20
00
54
43

05
3A
20
59
8D
20
41
68
48
54

AO
20
44
50
20
43
44
05
45
45

• .40 •••
•• 300:
• FIND D
DRIVE TYP
E.9.
600: • C
HANGE AD
DRESS.(.
•••• THE
SELECTE

The program is continued in this block. Bytes $00 and $01
point to the third data block of the file ($10, $14, track
16, sector 20):
>:00
>:08
>:10
>:18
>:20
>:28
>:30
>:38
>:40
>:48

10
06
35
31
32
36
43
4D
3A
31

08
54
34
31
30
00
B2
54
20
2E

31
01
20
39
33
45
32
B2
32
32

30
8B
A7
3A
31
06
32
35
30
00

30
20
20
20
20
5E
36
30
34
67

30
43
4D
8F
56
01
20
3Ao
30
06

00
B2
54
3A
32
8B
A7
20
20
68

23
32
B2
20
2E
20
20
8F
56
01

•• 1000.#
.T .. C 2

54
MT
119: .:
2031 V2.
6.E •••
C 226
MT 50: •
: 2040 V
1.2. • ( •

This is the next to the last block of the program. You have
no doubt recognized that the data blocks are in the same
track, but are not contiguously. The first data block is
block O. The next is block 10, 10 blocks from the first
block. 9 blocks are always skipped between data blocks of a
file. The third data block is block number 20. The DOS
begins again with the first block if the calculated block
oversteps the highest blOCk. Because track 16 contains 21
blocks, the last data block is block number 8. The first two
bytes of this third hlock address it:

>
>
>
>

00
08
10
18

00
20
01
31

F8
34
8B
30

SA
34
20
30

42
30
53
30

B2
00
54
00

31
14
20
45

20
07
A7
07

A7
A3
20
B8
112

•

ZB 1

440 •••
•• ST
1000.E.

Anatomy of the 1541 Disk Drive
>:20
>:28
>: 30
>:38
>:40
>:48

01
52
C7
31
43
C7

98
22
28
35
B2
28

31
C7
31
2C
C6
30

35
28
36
5A
28
29

2C
31
29
43
5A
29

22
37
3A
24
43
00

4D
32
Al
3A
24
66

2D
29
23
SA
AA
07

•. 15,"MR" (172)
(16) : #
15,ZC$:Z
C F(ZC$
G(O».&.

Here the end of the program is marked by the value $00 in
byte $00. Byte $01 gives the number of bytes in this last
block that belong to the program. ($F8 corresponds to 248
bytes). Now we can find out the size of the program:
3 blocks with 254 bytes each = 762 bytes
last block
= 248 bytes
Size of the program

llOO bytes

The Filename:
The filename is contained in bytes 3-18 of the file entry.
It consists of a maximum of 16 characters. Should the name
be shorter than 16 characters, the rest of the name is
padded with shifted spaces (SAO).
Track and Sector of the new File for "Overwriting-:
If a file is overwritten by using the @:, the new file is
first completely saved. No filename entry is made in the
directory for this file because the file already exists
under this same name. Instead the address of the first block
of the new file is placed in bytes 26 and 27 of the filename
entry. If the new program is removed, the old one is
deleted, which merely designates the blocks allocated to the
file as free in the BAM. Now the address of the first data
block of the new file is placed into the filename entry in
bytes I and 2 is used and the file is "overwritten".
Number of Blocks in the File:
The length of a file is given in bytes 28 and 29 of its file
entry. A file consists of at least one block and as many as
664 blocks. The first byte is the low byte, and the second
is the high byte. If, for example, you discovered the file
length $IF,SOO with the DISK MONITOR, the file consists of
31 blocks.

113

Anatomy of the 1541 Disk Drive
3.4

The Organization of Relative Piles

Relative files differ from sequential files in that each
data record can be accessed directly by a record number.
The 1541 OOS takes care of most of the tasks required to
support relative records. Let's take a closer look at the
organization of a relative file.
First OPEN a relative file with a record length of 100:
OPEN 2,8,2, "REL-FILE,L,"+CHR$(lOO)
Now write data record number 70:
OPEN 1,8,15
PRINTU,"P"+CHR$(2)+CHR$(70)+CHR$(0)+CHR$(1)
PRINT*2,DDATA FOR RECORD 70"
CLOSE 2 : CLOSE 1
The directory entry then looks like this:
>:00
84
>:08 20 46 49
>:10 AO AO AO
>:18 00 00 00

11
4C
AO
00

00
45
AO
00

52
AO
11
00

45 4C

••• REL

AO AO -FILE

OA 64
10 00

•• $
........

The first byte $84 denotes a relative file. The next two
bytes denote the first track and sector of the data ($11,
$00: track 17 sector 0): exactly as with a sequential file.
As usual, the name of the file follows (16 characters,
padded with shifted spaces, $AO). Following are two fields
not used with sequential files. The first field is a two
byte pointer to the track and sector of the first sidesector block. A side-sector contains the pointers to each
data record and is described more in detail later ($11, $OAI
track 17, sector 10). The second field is a byte w-hich
contains the record length, a value between 1 and 254, in
our case $64 (100).
The convenience of being able to access each record
individually requires a definite length for each record thet
must be defined when establishing a relative file. The rest
of the fields in the directory entry have the usual
significance; the last two bytes contain the number of
blocks in the file (10 and hi byte, $10 and $00 (29».
What does such a side-sector block look like and what is its
function?
The side-sector blocks contain the track and sector pointers
to the individual data records. For example, if we want to
read the 70th record in the relative file, the DOS consults
the side-sector block to determine which track and sector
contains the record and then read this record directly. As

114

Anatomy of the 1541 Disk Drive
a resul t, you can read the 70th record of the file without
having to read the entire file. Now let's take a look at the
exact construction of a side-sector block. This s ide-sectc'r
block is from our previous file.
>:00
>:08
>: 10
>:18
>:20
>:28
>:30
>:38
>:40
>:48
>:50
etc.

00 47 00
00 00 00
11 00 11
11 02 11
11 04 11
11 06 11
11 08 11
10 08 10
10 04 10
00 00 00
00 00 00

64
00
OB
OD
OF
11
13

12
OE
00
00

11 OA 00 00

00 00
11 01
11 03
11 05
11 07
11 09
10 06
10 02
00 00
00 00

00 00
11 OC
11 OE
11 10
11 12
11 14
10 10
10 OC
00 00
00 00

••••
·.G.$
.......
.......
···.......
.......
··.......
.......
·........
.......
··.......
.......

The first two bytes point to the track and sector of the
next side-sector block, as usual. In our case, no further
side-sector blocks exist ($00) and only $47 = 71 bytes of
this sector are used. Byte 2 contains the number of the
side-sector block, 00. A relative file can contain a maximum
of 6 such blocksl the numbering goes from 0 to 5. The record
length, $64 (100), is in byte 3. The next twelve bytes
(bytes 4 through 15) contain the track and sector pointers
(two bytes each) to the 6 side-sector blocks (00,00 means
the block is not yet used). Starting at byte 16 ($10) are
the pointers to the data, and the track and sector pointers
to the first 120 data blocks (in our case, only ~8
pointers). Using the record number and record length, the
DOS can calculate in which block the data lies and at which
position within the block the record begins. Take the
following example, for instance:
To read the 70th record from the file with a record length
of 100 characters, you can perform the following calculations:
(70-1)

*

100 / 254

We get a quotient of 27 and a remainder of 42. The DOS now
knows that the record can be found in the 27th data block at
the 42+2 or 44th position.
Here's an explanation of the calculation. Each block
contains 256 bytes, the first two of which are used as a
pOinter to the next block. 254 bytes are then left over for
data storage. We can calculate the byte number from the
start of the file (which is record 1) from the record number
and record length. If we divide this value by the number of
bytes per block, we get the number of the block containing
the record. The remainder of the division gives the position
within the block (add 2, because the first two bytes serve
as a pointer). If the record overlaps the end of the block,
115

Anatomy of the 1541 Disk Drive

the next block must also be read.
In our example, the 27th data block lies in track $10 = 16
and sector SOC = 12. If we read this block, we get the
following picture:

>:00
>:08
>:10
>:18
>:20
>:28
>:30
>:38
>:40
>:48
>:50
>:58
>:60
> :68
>:70
>:78
>:80
>:88

>:90
>:98

>:AO
>:A8
>:BO

>:B8

>:CO

>:C8
> :00
>:08

9:EO
>: E8
> :FO
> :F8

00
00
00
00
00
00
20
46
00
00
00
00
00
00
00
00
00
00
FF
00
00
00
00
00
00
00
00
00
00
00
00
00

F3
00
00
00
00
00
46
52
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00

00
00
00
00
00
00
4E
44
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00

00
00
00
00
00
00
52
20
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00

00
00
00
00
00
44
20
37
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
FF
00

00
00
00
00
00
41
52
30
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00

00
00
00
00
00
54
45
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00

00
00
00
00
00
41
43
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00

•••• DATA
FOR REC
ORO 70 ••

If we get a block number greater than 120 from the
calculation, the pointer can no longer be found on the first
side-sector block, rather in the next side-sector blocks. In
this case, you divide the block number by 120, the quotient
being the number of the side-sector block. The remainder
gives the location of the pointer within this block. Fer
instance, to find record number 425, divide by 120 and get a
quotient 3, remainder 65. Therefore, you must read sidesector block 3 and get the pointer to the 65th data block.
Between 2 and 4 block accesses are necessary to access a
record of a relative data file.
When creating or expanding a relative file, the following
takes place:
First, a directory entry is created for the relative file,
116

Anatomy of the 1541 Disk Drive
containing the record length. Two channels are reserved for
the relative file,one for the data, the other for the sidesectors. If a record pointer is set to a specific record,
the DOS first checks to see if the record already exists. If
so, the corresponding block is read and the buffer pointer
set so that the contents can be accessed. If not, the record
is created. All records preceding this record number that do
not already exist are also created. The first byte of a new
record is written to contain $FF (255), and the rest of the
record is filled with $00.
If the corresponding record is at the beginning of a block,
the rest of the block is filled with empty records. Each
time a non-existing record is accessed, the error message
50,RECORD NOT PRESENT is returned. When writing a new
record, this is not considered an error, but indicates that
a new record was created.
You can use this method for creating a new file if you know
the maximum number of data records. You simply set the
record pointer to this record and write $FF (CHR$(255» to
this record. By allocating a file like this, the error
message 50 no longer appears. You also know if there is
sufficient space on the diskette. If not, the error message
52, FILE TOO LARGE is returned.
With a maximum of 6 side sectors, a relative file can
contain 6 * 120 * 254 = 182,880 bytes. In the case of the
VIC 1541, this is more than the capacity of the whole
diskette. With the bigger 8050 drive, which contains more
than 500K of storage, this may present a limitation. But DOS
version 2.7 has an expansion of the side-sector procedure
('super side-sector'), with which a relative file mey
contain up to 23 MB. DOS 2.7 is contained in the CBM 8250
and the Commodore hard drives as well as the newer 8050
drives (see section 5.2).
Because a relative file requires two data channels, and the
VIC 1541 has only 3 channels available, only one relative
file can be open at a time. The third channel can still be
used for a sequential file open at the same time. With the
larger CBM drives, more channels are available (3 relative
files open simultaneously, see also section 5.2).

117

Anatomy of the 1541 Disk Drive

3.5

DOS 2.6 ROM LISTINGS

******************************
78
CIOO
SEI
CIOI
A9 F7
LDA II$F7
2D 00 IC
ANO $ICOO
CI03
CI06
48
PHA
CI07
AS 7F
LOA $7F
CI09
FO 05
BEO $CllO
CIOB
68
PLA
CIOC
09 00
ORA #$00
BNE $C1l3
ClOE
DO 03
ClIO
68
PLA
09 08
ORA #$08
Clli
C1l3
STA $lCOO
8D 00 IC
C1l6
58
CLI
60
C1l7
RTS
******************************
C1l8
78
SEI
C119
A9 08
LDA #$08
CllB
00 00 IC
ORA $ICOO
STA $ICOO
CllE
8D 00 IC
58
CLI
C12I
CI22
60
RTS
******************************
A9 00
Cl23
LDA #$00
STA $026C
Cl25
80 6C 02
Cl28
8D 60 02
STA $026D
Cl2B
60
RTS
******************************
Cl2C
78
SEI
8A
TXA
Cl20
48
PHA
Cl2E
LDA #$50
Cl2F
A9 50
Cl31
8D 6C 02
STA $026C
Cl34
A2 00
LDX #$00
BD CA FE
LOA SFECA,X
Cl36
8D 6D 02
STA $0260
Cl39
Cl3C
00 00 IC
ORA SICOO
STA SICOO
Cl3F
80 00 IC
68
PLA
Cl42
TAX
CI43
AA
Cl44
58
CLI
RTS
C145
60
******************************

Cl46
Cl48
Cl4B

A9 00
80 F9 02
AD 8E 02

LOA #SOO
STA S02F9
LOA S028E

turn LEO on
erase LED bit
drive number
O?
not drive 0, turn LED off
turn LED on

turn LED on
LED on

erase error flags

save X register

8
turn LEO on
get x register back

interpret command from
computer
last drive number

118

Anatomy of the 1541 Disk Drive
Cl4E
C150
C153
C155
C157
C159
C15B
C15D
C160

85
20
A5
10
29
C9
FO
4C
20

7F
BC E6
84
09
OF
OF
03
B4 D7
B3 C2

STA
JSR
LDA
BPL
AND
CMP
BEQ
JMP
JSR

$7F
$E6BC
$84
$C160
#$OF
#$OF
$C160
$07B4
$C2B3

C163
C165
C168
C16A
C16D
C170
C172
C173
Cl75
Cl77
C17A
C17D
Cl7F
C181
C184
C187
C18A
Cl8C
Cl8F
C191

Bl
80
A2
BO
CD
FO
CA
10
A9
4C
8E
EO
90
20
AE
BO
85
BO
85
6C

A3
75 02
OB
89 FE
75 02
08

LDA
STA
LDX
LDA
CMP
BEQ
OEX
BPL
LDA
JMP
STX
CPX
BCC
JSR
LDX
LDA
STA
LOA
STA
JMP

($A3),Y
$0275
#$OB
$FE89,x
$0275
$C17A

F5
31
C8
2A
09
03
EE
2A
95
6F
Al
70
6F

Cl
02
Cl
02
FE
FE
00

drive number
prepare 'ok l message
secondary address

$CI6A
#S31
$CIC8
$022A
#$09
$C184
$ClEE
$022A
$FE95,X
$6F
$FEAl,X
$70
($006F)

******************************

C194
C196
C199
C19C
Cl9E
CIAO
CIAI
CIA3
CIA5
CIA7
ClAA
ClAD
CIAF
CIB2
CIB3
CIB5
CIB7
CIBA

A9
80
AO
DO
AO
98
84
84
84
20
20
A5
80
AA
A9
95
20
4C

00
F9 02
6C 02
2A
00
80
81
A3
C7 E6
23 Cl
7F
8E 02
00
FF
BD CI
DA 04

LOA
STA
LDA
BNE
LOY
TYA
STY
STY
STY
JSR
JSR
LOA
STA
TAX
LOA
STA
JSR
JMO

#$00
$02F9
$026C
$CIC8
#$00

15, command channel
yes
to OPEN command
determine line length and
erase flags
get first character
and store
11
commands
compare to first character
found?
not found
31, 'syntax error'
number of command words
command nUlllber < 9?
test for 'R' , IS' , and
command number
jump address 10

'N'

jump address hi
jump to command
prepare error message after
executing command
flag set?
yes, then set error message
error number 0
track number 0
sector number 0

$80
$81
$A3
$E6C7
$C123
$7F
$028E

prepare 'ok' message
erase error flag
drive number
save as last drive number

#$00
$FF,X
$CIBO
$D40A

erase input buffer
close internal channel

******************************
CIBO
AO 28
LOY #$28
CIBF
A9 00
LOA #$00

119

erase input buffer
erase 41 characters

Anatomy of the 1541 Disk Drive
CICI
CIC4
CIC5
CIC7

99 00 02
88
10 FA
60

STA $0200,Y
DEY
BPL $CICl
RTS

******************************

CIC8
CICA
CICC
CICE

AO
84
84
4C

00
80
81
45 E6

LDY
STY
STY
JMP

#$00
$80
$81
$£645

4C 68 C3

give error message
(track & sector)
track = 0
sector = 0
error number ace, generate
error message

******************************
CIDl
A2 00
LDX #$00
CID3
8E 7A 02
STX $027A
CID6
A9 3A
LDA #$3A
CID8
20 68 C2
JSR $C268
CIDB
FO 05
BEO $CIE2
88
CIDD
DEY
88
CIDE
DEY
CIDF
STY $027A
8C 7A 02

C1E2

$200 to $228

JMP $C368

check input line

..

pointer to drive number
:

test line to I :
no colon found?

I

or to end

point to drive number
(before colon)
get drive # and turn LED on

******************************
AO 00
LDY #$00
C1£5
CIE7
A2 00
LDX #SOO
CIE9
A9 3A
LDA #S3A
ClEB
JMP $C268
4C 68 C2

check input line
pointer to input buffer
counter for commas

******************************
20 E5 Cl
CIEE
JSR $CIE5
CIFI
DO 05
BNE $CIF8
LDA #S34
CIF3
A9 34
CIF5
4C C8 Cl
JMP SCIC8
88
CIF8
DEY
88
CIF9
DEY
CIFA
8C 7A 02
STY S027A
CIFD
8A
TXA
DO F3
BNE $CIF3
C!FE
C200
A9 3D
LDA #S3D
C202
20 68 C2
JSR $C268
C205
8A
TXA
FO 02
C206
BEO SC20A
C208
A9 40
LDA #S40
C20A
09 21
ORA #S21
C20C
8D 8B 02
STA S028B
C20F
INX
E8
C210
8E 77 02
STX $0277
8E 78 02
STX $0278
C213
C216
AD 8A 02
LDA $028A
C219
FO OD
BEO SC228
C2lB
A9 80
LOA #$80
C2lD
OD 8B 02
ORA $028B
C220
8D 8B 02
STA $028B

check input line
test line to 1: ' or end
colon found?

120

I:

t

test line to colon or to end

34, , syntax error'
set pointer to colon
position of the drive no.
comma before the colon
yes, then 'syntax error'
'='
check input to '='
comma found?
no
bit 6
and set bit 0 and 5
flag for syntax check

wildcard found?
no
set bit 7

Anatomy of the 1541 Disk Drive
C223
C225
C228
C229
C22B
C22E
C231
C234
C236
C239
C23A
C23D
C23E
C24A
C243
C245
C248
C24A
C24C
C24E
C251
C254
C257
C25A
C25D
C25F
C260
C263
C265

A9
8D
98
FO
9D
AD
8D

00
8A 02

29
7A 02
77 02
79 02
A9 8D
20 68 C2
E8
8E 78 02
CA
AD 8A 02
FO 02
A9 08
EC 77 02
FO 02
09 04
09 03
4D 8B 02
8D 8B 02
AD 8B 02
AE 2A 02
3D AS FE
DO 01
60
8D 6C 02
A9 30
4C C8 Cl

LDA
STA
TYA
BEO
STA
LDA
STA
LDA
JSR
INX
STX
DEX
LDA
REO
LDA
CPX
BEO
ORA
ORA
EOR
STA
LDA
LDX
AND
BNE
RTS
STA
LDA
JMP

#$00
$028A
$C254
$027A,X
$0277
$0279
#S8D
$C268
$0278
$028A
$C245
#$08
$0277
$C24C
#$04
#$03
$028B
$028B
$028B
$022A
$FEA5,X
$C260
S026C
#$30
$CIC8

8D
CC
BO
Bl
C8
CD
FO
C9
FO
C9
DO
EE
C9
DO
98
9D
AD
29
FO
A9
95
8D
E8

75 02
74 02
2E
A3
75 02
28
2A
04
3F
03
8A 02
2C
E4
7B 02
8A 02
7F
07
80
E7
8A 02

STA
CPY
BCS
LDA
INY
CMP
BEO
CMP
BEO
CMP
BNE
INC
CMP
BNE
TYA
STA
LDA
AND
BEO
LDA
STA
STA
INX

number of commas before '='
shift CR
check line to end
increment comma counter
store # of commas
wildcard found?
no
set bit 3
comma after '=' ?
no
set bit 2
set bits 0 and 1
as flag for syntax check
syntax flag
command number
combine with check byte
set error flag
30, 'syntax error'

******************************

C268
C26B
C26E
C270
C272
C273
C276
C278
C27A
C27C
C27E
C280
C283
C285
C287
C288
C28B
C28E
C290
C292
C294
C296
C299

reset wildcard flag
'=' found?
no

S0275
$0274
$C29E
(SA3) ,Y

search characters in input
buffer
save character
already done?
yes
get char from buffer

$0275
$C2AO
#S2A
$C280
#$ 3F
SC283
S028A
#S2C
$C26B

compared with char
found

$027B,X
$028A
#S7F
$C299
#$80
$E7,X
$028A

note comm", position
wildcard flag

,* ,
'? '

set
, , wildcard flag

,

121

no wildcard
note flag
and save as wildcard flag
inc comma counter

Anatomy of the 1541 Disk Drive

C29A
C29C
C29E
C2AO
C2A3
C2A6
C2A9
C2AB
C2AD
C2AF
C2Bl
C2B2

EO
90
AO
AD
9D
AD
29
FO
A9
95
98
60

04
CD
00
74 02
7B 02
8A 02
7F
04
80
E7

CPX
BCC
LDY
LDA
STA
LDA
AND
BEO
LDA
STA
TYA
RTS

#$04
SC26B
#SOO
$0274
S027B,X
$028A
#S7F
$C2Bl
#S80
$E7,X

******************************
C2B3
A4 A3
LDY SA3
FO 14
C2B5
BEO SC2CB
DEY
C2B7
88
C2B8
FO 10
BEO SC2CA
C2BA
B9 00 02
LDA S0200,Y
C2BD
CMP #SOD
C9 OD
C2BF
FO OA
BEO $C2CB
C2Cl
88
DEY
C2C2
B9 00 02
LDA S0200, Y
C2C5
C9 OD
CMP #SOD
C2C7
FO 02
BEO SC2CB
C2C9
C8
INY
C8
INY
C2CA
STY S0274
C2CB
8C 74 02
C2CE
CO 2A
CPY #S2A
C2DO
AO FF
LDY #$FF
C2D2
BCC SC2DC
90 08
8C 2A 02
C2D4
STY S022A
C2D7
A9 32
LDA #S32
JMP SClC8
C2D9
4C C8 Cl
******************************
C2DC
LDY #SOO
AO 00
C20E
98
TYA
C20F
85 A3
STA SA3
C2El
8D 58 02
STA S0258
C2E4
8D 4A 02
STA S024A
C2E7
8D 96 02
STA S0296
C2EA
85 D3
STA SD3
C2EC
8D 79 02
STA $0279
C2P.F
STA $0277
8D 77 02
C2F2
8D 78 02
STA $0278
C2F5
8D 8A 02
STA $028A
C2F8
80 6C 02
STA $026C
C2FB
A2 05
LDX #$05
C2FD
9D 79 02
STA S0279,X
C300
95 D7
STA $D7,X
C302
95 DC
STA SDC,X
C304
95 El
STA SEl,X
C306
95 E6
STA $E6,X
122

4 commas already?
no, continue
set flag for line end
wildcard flag
no wildcard
set flag

check line length
ptr to command input buffer
zero?
one?
pointer to input buffer
'CR'
yes, line end
preceding character
'CR'
yes
pointer to old value again
same line length
compare with 42 characters
smaller, ok
32, 'syntax error' line too
long
erase flag for input command
pointer to input buffer 10
record length
file type
comma counter
wildcard flag
error flag
flags for line analysis
directory sectors
buffer pointer
drive number
wildcard flag

Anatomy of the 1541 Disk Drive
C308
C30B
C30E
C30F
C311

9D 7F 02
9D 84 02
CA
DO EC
60

STA $027F,X
STA $0284,X
DEX
BNE $C2~'D
RTS

******************************

C312
C315
C318
C31A
C31D
C320
C323
C325
C327
C32A
C32D
C32F
C332
C333
C335
C336
C339
C33B

AD
8D
A9
8D
8D
AC
A2
86
BD
20
A6
9D
98
95
E8
EC
90
60

78
77
01
78
79
8E
00
D3
7A
3C
D3
7A

02
02
02
02
02
02
C3
02

E2
78 02
EA

LDA
STA
LDA
STA
STA
LDY
LDX
STX
LDA
JSR
LDX
STA
TYA
STA
INX
CPX
BCC
RTS

$0278
$0277
i$Ol
$0278
$0279
$028E
i$OO
$D3
$027A,X
$C33C
$D3
$027A

AA

AO
A9
DD
FO
DD
DO
E8
98
29
A8
8A
60

00
3A
01 02
OC
00 02
16

C352
C355
C356
C357
C359
C35B
C35D
C35F
C361
C362
C364
C366

BD
E8
E8
C9
FO
C9
FO
DO
98
09
29
DO

00 02

01

30
F2
31
EE
EB
80
81
E7

TAX
LDY
LDA
CMP
BEO
CMP
BNE
INX
TYA
AND
TAY
TXA
RTS
LDA
INX
INX
CMP
BEO
CMP
BEO
BNE
TYA
ORA
AND
BNE

preserve drive number
number of commas
save
number of drive numbers
last drive number
position of the colon
get drive no. before colon
save exact position

$E2,X

drive number in table

$0278
$C325

got all drive numbers?
no, continue

******************************

C33C
C33D
C33F
C341
C344
C346
C349
C34B
C34C
C34D
C34F
C350
C351

track number
sector number

search for drive number
note position

#$00
i$3A
$0201,X
$C352
$0200,X
$C361

colon behind it?
yes
colon here?
no

#$01

drive number

$0200,X

get drive number

1:1

'0 I?

i$30
$C34D
i$31
$C34D
$C34C

yes
111 ?

yes
no, use last drive number
last drive number
set bit 7, uncertain drive #
erase remaining bits

#$80
#$81
$C34F

******************************

123

get drive number

Anatomy of the 1541 Disk Drive
C368
C36A
C36D
C370
C372
C375
C377
C378
C37B
C37D
C380
C38l
C383
C386
C388
C38A
C38C

A9
8D
AC
Bl
20
10
C8
CC
BO
AC
88
DO
CE
A9
29
85
4C

00
RB 02
7A 02
A3
BD C3
11

74 02
06
74 02
ED
8B 02
00
01
7F
00 Cl

LDA
STA
LDY
LDA
JSR
BPL
INY
CPY
BCS
LDY
DEY
BNE
DEC
LDA
AND
STA
JMP

#$00
$028B
$027A
($A3},Y
$C3BD
$C388
$0274
$C383
$0274
$C370
$0288
#$00
#$01
$7F
SClOO

search line for drive no.

drive number
turn LED on

******************************

C38F
C391
C393
C395
C397

A5
49
29
85
60

7F
01
01
7F

LDA
EOR
AND
STA
RTS

$7F
#$01
#$01
$7F

******************************
C398
AD 00
LDY #$00
C39A
AD 77 02
LDA $0277
C39D
CD 78 02
CMP $0278
C3AO
FO 16
BEO SC3B8
C3A2
CE 78 02
DEC $0278
C3AS
AC 78 02
LDY $0278
C3A8
B9 7A 02
LDA S027A,Y

C3AB
C3AC
C3AE

A8
Bl A3
AO 04

TAY
LDA (SA3) ,Y
LDY #$04

C3BO
C3B3
C3S5
C3B6
C3B8
C3B9
C3BC

D9
FO
88
DO
98
8D
60

CMP
REO
DEY
RNE
TYA
STA
RTS

BB FE
03
F8
96 02

SFEBB,Y
SC3B8

C9
FO
C9
FO
09
29
60

30
06
31
02
80
81

C~1P

BEO
CMP
BEO
ORA
AND
RTS

reverse drive number
drive number
switch bit 0

establish file type

'=1 found?
no
get pointer
set pointer to character
behind '=1
pointer to buffer
compare with marker for
file type
lSI, • pI I I U· I 'R'
agreement

SC3BO
$0296

note file type (1-4)

******************************

C3BD
C3BF
C3C1
C3C3
C3C5
C3C7
C3C9

erase syntax flag
position in command line
get chars from command buffer
get drive number
certain number?
increment pointer
line end?
yes

#$ 30
SC3C7
#S31
SC3C7
#S80
#S81

check drive number
'0 '
' l'
no zero or one, then set bit 7

124

Anatomy of the 1541 Disk Drive
******************************

C3CA
C3CC
C3CE
C3Dl
C3D2
C3D5
C3D6
C3D8
C3D9
C3DB
C3DD
C3DE
C3EO
C3E2
C3E4
C3E6
C3E8
C3E9
C3EB
C3ED
C3EE'
C3FO
C3Fl
C3F4
C3F5
C3F7
C3FA
C3FB
C3FC
C3FE
C400
C402
C404
C407
C409
C40C
C40E
C411
C413
C416
C419
C41B
C41D
C420

A9
85
8D
48
AE
68
05
48
A9
85
CA
30
B5
10
06
06
4A
90
06
DO
68
AA
BD
48
29
8D
68
OA
10
A5
29
85
AD
FO
20
FO
20
A9
8D
20
FO
A9
20
20

00
6F
8D 02

C423
C426
C427
C42A
C42B
C42D
C42F
C432
C434

20
08
20
28
FO
A9
8D
FO
20

3D C6

78 02
6F
01
6F
OF
E2
04
6F
6F
EA
6F
E6
3F C4
03
8C 02
3E
E2
01
7~'

8C
28
3D
12
8F
00
8C
3D
IE
74
C8
8F

02
C6
C3
02
C6
Cl
C3

8F C3
OC
00

ac 02
05
3D C6

verify drive number

LDA
STA
STA
PHA
LDX
PLA
ORA
PHA
LDA
STA
DEX
BMI
LDA
BPL
ASL
ASL
LSR
BCC
ASL
BNE
PLA
TAX
LDA
PHA
AND
STA
PLA
ASL
BPL
LDA
AND
STA
LDA
BEO
JSR
BEO
JSR
LDA
STA
JSR
BEO
LDA
JSR
JSR

#$00
$6F
$028D

A
SC43C
$E2
#SOl
S7F
S028C
SC434
$C63D
$C420
$C38E'
#$00
$028C
$C63D
SC439
#$74
SClC8
SC38F

initialze drive
error?
switch to other drive

JSR
PHP
JSR
PLP
BEO
LDA
STA
BEO
JSR

$C63D

initialize drive

$C38F

switch to other drive

$C439
#$00
$028C
$C439
$C63D

no error?

$0278

number of drive numbers

$6F
#$01
$6F
$C3EF
SE2,X
$C3E8
$6F
$6F
A
$C3D5
$6F
$C3D5
SC43F,X

get syntax flag

#$03
S028C

isolate drive number

init ial ize drive
no error?
74, 'drive not ready'

number of drives
initialize drive

125

Anatomy of the 1541 Disk Drive
C437
C439
C43C
C43D

DO E2
4C 00 Cl
2A
4C 00 C4

BNE
JMP
ROL
JMP

error?
Turn LED on
drive # from carry after bit a

$C41B
$CI00
A
$C400

******************************
C440
00 80 41 01 01 01 01 81
C448
81 81 81 42 42 42 42

flags for drive check

******************************

search for file in directory
initialize drive

C44F
C452
C454
C457
C45A
C45C
C45F
C461

20
A9
80
20
DO
CE
10
60

CA
00
92
AC
19
BC
01

JSR
LOA
STA
JSR
BNE
DEC
BPL
RTS

$C3CA
#$00
$0292
$C5AC
$C475
$028C
$C462

C462
C464
C467
C46A
C46D

A9
80
20
20
4C

01
80
8F
00
52

LOA
STA
JSR
JSR
JMP

#$01
$0280
$C38F
$CI00
$C452

C470
C473
C475
C47B
C47B
C470

20
Fa
20
AD
FO
60

17 C6
10
08 C4
BF 02
01

JSR
BEO
JSR
LOA
BEO
RTS

$C617
$C4B5
$C408
$02BF
$C47E

C47E
C481
C483
C485
C488
C48A

AD
30
10
AD
FO
60

53 02
ED
F'O
8F 02
02

LOA
BMI
BPL
LOA
BEO
RTS

$0253
$C470
$C475
$028F
$C45C

C48B
C48E
C490

20 04 C6
FO lA
DO 28

JSR $C604
BEO $C4AA
BNE $C4BA

C492
C494
C497
C49A
C490
C49F
C4A2
C4A5
C4A7
C4AA
C4AD
C4AF

A9
BD
20
20
A9
80
20
DO
80
AD
DO
CE

LOA
STA
JSR
JSR
LOA
STA
JSR
BNE
STA
LOA
BNE
DEC

01
80
8F
00
00
92
AC
13
8F
8F
28
8C

C3
02
C5
02

02
C3
Cl
C4

02
C3
Cl
02
C5
02
02
02

pointer
read first directory block
entry present?
drive number clear?
no

change drive
Turn LED on
and search
search next file in directory
not found?
verify directory entry
more files?

fi Ie not found?
yes

search next directory block
not found?

#$01
$0280
$C38F
$CI00
#$00
$0292
$C5AC
$C4BA
$028F
$028F
$C4D7
$028C

change drive
turn LED on
read directory block
found?

126

Anatomy of the 1541 Disk Drive
C4B2
C4B4

10 DE
60

C4B5
C4B8
C4BA
C4BD
C4CO
C4C2
C4C5
C4C7

20
FO
20
AE
10
AD
FO
DO

17
FO
D8
53
07
8F
EE
DE

C4C9
C4CC
C4CE
C4DO
C4D2
C4D5
C4D7

AD
FO
B5
29
CD
00
60

C4D8
C4DA
C4DO
C4DE
C4El
C4E4
C4E6

A2
8E
E8
8E
20
FO
60

C4E7
C4EA
C4EC
C4EE
C4FO
C4F1
C4F3
C4F5
C4F7
C4F9
C4FC
C4FE
C50I
C502
C505
C507

20
DO
A5
55
4A
90
29
FO
A9
CD
FO
ElO
AA
20

C50A
C500
C50F
C511
C513
C5I5
C517
C519
C51B
C51C

BPL $C492
RTS
C6

JSR
BEO
JSR
LOX
BPL
LDA
BEO
BNE

$C617
$C4AA
$C4D8
$0253
$C4C9
$028F
$C4B5
$C4D7

96 02
09
E7
07
96 02
DE

LOA
BEO
LOA
AND
CMP
BNE
RTS

$0296
$C467
$E7,X
#$07
$0296
$C4B5

same as desired file type?
no

FF
53 02

LOX
STX
INX
STX
JSR
BEQ
RTS

#$FF
S0253

flag for data found

C4
02
02

8A 02
89 C5
06

next entry in directory
not found?
check entry
file found?
yes
no, then done

file type

S028A
$C589
SC4EC

set pointer to data

$C594
SC4E6
S7F
$E2,X
A
$C4FE
#S40
$C4E7
#$02
$028C
$C4E7
$027A,X

pointer to next file
end, then done
drive number

A6 C6
03
4C 10 C5

JSR
BNE
LOA
EOR
LSR
BCC
AND
BEQ
LOA
CMP
BEO
LDA
TAX
JSR
LOY
JMP

$C6A6
#$03
SC510

get length of filename

BO 00 02
01 94
~'O
OA
C9 3F'
00 02
Bl 94
C9 AO
FO CC
E8
C8

LDA
CMP
BEQ
CMP
BNE
LOA
CMP
BEQ
INX
INY

$0200,X
(S94),Y
$C51E1
#$3F
$C4E7
($94),Y
#SAO
$C4E7

get chars out of command line
same character in directory?
yes

94 C5
FA
7F
E2
DB
40
FO
02
8C 02
E9
7A 02

AD

127

search both drives?
yes

I? '

no
shift blank, end of name?
yes
increment pointer

Anatomy of the 1541 Disk Drive
C51D
C520
C522
C525
C527
C529

EC
BO
BD
C9
FO
DO

76 02
09
00 02
2A
OC
DF

CPX
BCS
LDA
CMP
BEQ
BNE

$0276
$C52B
$0200,X
#$2A
SC535
$C50A

end of the name in the command?
yes
next character

C52B
C52D
C52F
C531
C533
C535
C538
C53B
C53D
C53F
C542
C545
C547
C549
C54B
C54D
C54F
C550
C55l
C553
C555
C556
C558
C55A
C55C
C55E
C560
C562
C564
C566
C568C56A
C56C
C56E
C570
C572
C574
C577
C578
C57A
C57D
C580
C582
C584
C586
-C589
CS8B
C58E

CO
BO
Bl
C9
DO
AE
8E
B5
29
8D
AD
95
AS
95

13
06
94
AO
B2
79 02
53 02

CPY
BCS
LDA
CMP
BNE
LDX
STX
LDA
AND
STA
LDA
STA
LDA
STA
LDY
LDA
INY
PHA
AND
STA
PLA
AND
BMI
ORA
AND
ORA
STA
LDA
AND
ORA
STA
LDA
AND
ORA
STA
LDA
STA
INY
LDA
STA
LDA
BNE
LDY
LDA
STA
LDA
STA
LDA

#S13
$C535
($94), Y
#SAO
SC4E7
$0279
S0253
SE7,x
#$80
$028A
$0294
SDD,X
S81
SD8,X
#SOO
(S94), Y

19
reached end of name

E7

80
8A 02
94 02
DD
81
D8
AD 00
Bl 94
C8
48
29 40
85 6F
68
29 DF
30 02
09 20
29 27
05 6F
85 6F
A9 80
35 E7
05 6F
95 E7
B5 E2
29 80
05 7F
95 E2
Bl 94
9D 80 02
C8
Bl 94
9D 85 02
AD 58 02
DO 07
AO 15
B1 94
8D 58 02
A9 FF
8D 8F 02
AD 78 02

• *.

yes, file found
continue search

shift blank, end of name
not found

sector number of the directory
enter in table
file type

*$ 40
$6F

isolate scratch-protect bit
( 6) and save

#$DF
$C55C
#$20
#$ 27
$6F
$6F
#$80

erase bit 7

$E7 , X
$6F , X
SE7 , X
$E2 , X

isolate flag for wildcard

set bit 5
erase bits 3 and 4
get bit 6 again

write in table

#$80
$7F
SE2,X

drive number

($94) I Y
$0280 , X
($94) I Y
S0285,X
$0258
$C589
#$15
($94), Y
$0258
#SFI<'
$028F
S0278

128

first track of file
get sector from directory
record length
record length
get from directory

Anatomy of the 1541 Disk Drive
C591
CS94
CS97
CS99

SD 79 02
CE 79 02
10 01
60

STA $0279
DEC $0279
BPL $CS9A
RTS

CS9A
CS9D
CS9F
CSAl
CSA4
CSA6
CSAS
CSAB

AE
BS
30
BD
DO
A9
So
60

79 02
E7
OS
SO 02
EE
00
SF 02

LDX
LDA
BMI
LDA
BNE
LOA
STA
RTS

$0279
$E7,X
$CSA6
$ 02S0,X
$CS94
#$00
$02SF

CSAC
CSAE
CSBl
CSB2
CSBS
CSBS
C5BA
C5BC
C4BE
C5C1
C5C4
C5C7
C5C9

AO
SC
SS
SC
An
S5
A9
SS
SD
20
AD
DO
60

00
91 02

LOY
STY
DEY
STY
LDA
STA
LDA
STA
STA
JSR
LDA
BNE
RTS

#$00
$0291

C5CA
CSCC
CSCF
CSDI
C5D4
CSD7
C5DA
CSDO
CSOF
CSEI
CSE3
CSE6
CSE8
CSEB
CSED
CSFO
C5F2
C5F5
C5FS
CSFA

A9
SD
A9
20
So
20
CE
AO
Bl
DO
AO
DO
20
AS
SD
AS
AE
SD
FO
60

07
95
00
F6
93
ES
9S
00
94
18
91
2F
3B
81
91
94
92
92
10

C5FB
C5FD
C600
C602

A2
EC
DO
FO

01
92 02
2D
13

C604

AD S5 FE

S3
SS
SO
01
Sl
93
75
93
01

02
FE

02
D4
02

02
D4
02
D4
02

02
DE
02
02
02

$02S3
$FES5
$SO
#$01
$Sl
$0293
$D475
$0293
$CSCA

wildcard flag set?
yes
track number already set
yes

IS, directory track
sector 1
read sector

LDA
STA
LDA
JSR
STA
JSR
DEC
LDY
LDA
BNE
LOA
BNE
JSR
LDA
STA
LDA
LDX
STA
BEO
RTS

#$07
$0295
#$00
$D4r'6
$0293
$D4ES
$029S
#$00
($94),Y
$CSFB
$0291
$C617
$DE3B
$Sl
$0291
$94
$0292
$0292
$C617

LDX
CPX
BNE
BEO

#$01
$0292
$C62F
$C617

number of directory entries (-1)
get pointer from buffer
save as track number
set buffer pointer
decrement counter
first byte from directory

get track and sector number
sector number
buffer pointer

buffer pointer to one?

LDA $FESS

IS, track number of BAM

129

Anatomy of the 1541 Oisk Orive
C607
C609
C60C
C60E
C611
C614
C617
C619
C61C
C61F
C621
C623
C626

85
AO
85
20
AO
20
AO
80
AO
30
A9
20
4C

80
90
81
75
94
C8
FF
53
95
08
20
C6
07

C629
C62C

20 40 04
4C C4 C5

JSR $0440
JMP $C5C4

set buffer pointer
read next block

C62F
C631
C634
C637
C639
C63C

A5
80
20
AS
80
60

LOA
STA
JSR
LOA
STA
RTS

get track & sector no. from buffe

02
04
02
04
02
02
01
C5

94
94 02
3B OE
81
90 02

STA
LOA
STA
JSR
LOA
JSR
LOA
STA
LOA
BMI
LOA
JSR
JMP

$80
$0290
$81
$0475
$0294
$04C8
#$FF
$0253
$0295
$C629
#$20
$01C6
$C567

track number
sector number
read block
set buffer pointer
erase-file found flag
all directory entries checked?
inc buffer ptr by 32, next entry
and continue

$94
$0294
$OE3B
$81
$0290

save sector number

******************************
C630
LOA $68
A5 68
C63F
00 28
BNE $C669
C64l
LOX $7F
A6 7F
C643
56 lC
LSR $lC,X
C645
90 22
BCC $C669
C647
A9 FF
LOA $FF
C649
80 98 02
STA $0298
C64C
JSR $OOOE
20 OE 00
C64F
AO FF
LOY #$FF
C651
CMP #$02
C9 02
C653
BEQ $C65F
FO OA
CMP #$03
C655
C9 03
C657
FO 06
BEQ $C65F
C659
C9 OF
CMP #$OF
C65B
BEQ $C65F
FO 02
C650
AO 00
LOY #$00
C65F
A6 7F
LOX $7F
C661
98
TYA
C662
95 FF
STA $FF,X
C664
00 03
BNE $C669
C666
20 42 DO
JSR $0042
C669
A6 7F
LOX $7F
C66B
LOA $FF.X
B5 FF
C660
60
RTS
******************************
C66E
48
PHA
C66F
20 A6 C6
JSR $C6A6
C672
20 88 C6
JSR $C688
C675
68
PLA
130

test and initialize drive
drive number
disk changed?
no, then done
set error flag
read directory track
20, 'read error'?
yes
21, 'read error'?
yes
74, 'drive not ready' ?
yes
drive number
save error flag
error?
load BAM
drive number
transmit error code
name of file in directory buffer
get end of the name
write filename in buffer

Anatomy of the 1541 oisk Orive
C676
C677
C67A
C67B
C670
C67F
C68l
C683
C684
C685
C687

38
EO
AA
FO
90
A9
91
C8
CA
00
60

4B 02

SEC
SBC $024B

compare len with max length

TAX

OA
08
AO
94
FA

BEQ
BCC
LOA
STA
INY
OEX
BNE
RTS

$C687
$C687
lI$AO
($94),Y
$C68l

******************************
C688
98
TYA
OA
C689
ASL A
C68A
A8
TAY
B9 99 00
LOA $0099,Y
C68B
85 94
STA $94
C68E
C690
B9 9A 00
LOA $009A
C693
85 95
STA $95
C695
AO 00
LOY #$00
BO 00 02
LOA $0200,X
C697
C69A
91 94
STA ($94),Y
C69C
C8
INY
C690
FO 06
BEQ $C6A5
INX
C69F
E8
C6AO
EC 76 02
CPX $0276
C6A3
90 F2
BCC $C697
60
C6A5
RTS

******************************
C6A6
C6A8
C6AB
C6AC
C6AO
C6BO
C6B2
C6B4
C6B6
C6B8
C6BB
C6BC
C6BE
C6Cl
C6C3
C6C6
C6C8
C6CB
C6CC
C6CO

A9
80
8A
48
BO
C9
FO
C9
FO
EE
E8
A9
CO
90
EC
90
8E
68

00
4B 02

pad with 'Shift blank'

buffer number
times 2 as pointer
buffer pointer after $94/$95
transmit characters in buffer
buffer already full?

search for end of name in command

LOA #$00
STA $024B
TXA

00 02
2C
14
30
10
4B 02
OF
4B 02
05
74 02
E5
76 02

PHA
LOA
CMP
BEQ
CMP
BEQ
INC
INX
LOA
CMP
BCC
CPX
BCC
STX
PLA

AA

TAX

60

RTS

$0200,X
#$2C
$C6C8
#$30
$C6C8
$024B

get
, , characters out of buffer

#$OF
$024B
$C6C8
$0274
$C6AO
$0276

15

,

'='
increment length of name

greater?
end of input line?

pointer to end of name

******************************
C6CE
LOA $83
A5 83
C600
48
PHA

131

secondary address and channel no.

Anatomy of the 1541 Disk Drive
C601
C603
C604
C607
C608
C60A
C60B
C600

AS
48
20
68
85
68
85
60

82
DE C6
82
83

LOA
PHA
JSR
PLA
STA
PLA
STA
RTS

$82
$C60E

create file entry for directory

$82
get data back
$83

******************************
C60E
LOA #$11
A9 11
C6EO
85 83
STA $83
C6E2
20 EB DO
JSR $OOEB
C6E5
JSR $04E8
20 E8 04
C6E8
LOA $0253
AO 53 02
10 OA
BPL $C6F7
C6EB
LOA $0280
C6EO
AD 80 02
BNE $C6FC
C6FO
DO OA
20 06 C8
JSR $C806
C6F2
C6F5
18
CLC
C6F6
60
RTS
LOA $0280
C6F7
AD 80 02
C6FA
FO IF
BEO $C7lB
C6FC
DEC $0280
CE 80 02
C6FF
ENE $C70E
DO 00
C701
DEC $028D
CE 80 02
JSR $C38F
C704
20 8F C3
C707
JSR $C806
20 06 C8
C70A
38
SEC
C708
4C 8F C3
JMP $C38F
C70E
C7l0
C713
C7l6
C7l9
C7lA

A9
80
80
20
38
60

00
73 02
80 02
B7 C7

LOA
STA
STA
JSR
SEC
RTS

#$00
$0273
$0280
$C7B7

C71B
C7l0
C71F
C721
C724
C726
C728
C729
C72B
C72E
C730
C732
C734
C736
C737
C739
C73B

A2 18
AO 10
Bl 94
80 73 02
FO 02
A2 16
88
Bl 94
80 72 02
EO 16
FO OA
C9 OA
90 06
CA
C9 64
90 01
CA

LOX
LOY
LOA
STA
BEO
LOX
DEY
LDA
STA
CPX
BEO
CMP
BCC
DEX
CMP
BCe
OEX

#$18
#$10
($94), Y
$0273
$C728
11$16

17
secondary address
open channel to read
set buffer pointer
not yet last entry?
write 'blocks free.

,

change drive
write 'blocks free.

,

change drive
drive no. for header, hi-byte
write header

($94), Y
S0272
#$16
$C73C
II$OA
$C73C
IIS64
SC73C

number of blocks hi
in buffer
zero?
number of blocks 10
in buffer
10
100

132

Anatomy of the 1541 Disk Orive

C73C
C73F
C741
C742
C743
C745
C747
C74A
C74B
C740
C74E
C751
C754
C755
C758
C75B
C75C
C75F
C762
C763
C764
C766
C768
C76B
6760
C770
C771
C773
C775
C778
C779
C77A
C77C
C77E
C780
C783
C784
C786
C788
C78B
C780
C7BF
C791
C793
C795
C798
C799
C89B
C790
C79F
C7A2
C7A5
C7A7
C7AA
C7AB

20
Bl
48
OA
10
A9
90
68
29
A8
B9
90
CA
B9
90
CA
B9
90
CA
CA
80
A9
90
A9
90
CA
AO
Bl
90
CA
88
CO
BO
A9
90
E8
EO
BO
BO
C9
FO
C9
00
A9
90
E8
EO
BO
A9
30
90
10
20
38
60

AC C7
94
05
3C
B2 02
OF
C5 FE
Bl 02
CO ~'E
Bl 02
BB FE
Bl 02
05
2A
82 02
AO
Bl 02
12
94
Bl 02
03
F5
22
Bl 02
20
OB
Bl 02
22
04
AO
FO
22
Bl 02
20
OA
7F
Bl 02
Bl 02
Fl
B5 C4

JSR
LDA
PHA
ASL
BPL
LOA
STA
PLA
ANO
TAY
LOA
STA
OEX
LOA
STA
OEX
LOA
.STA
OEX
OEX
BCS
LOA
STA
LOA
STA
OEX
LOY
LOA
STA
OEX
OEY
CPY
BCS
LOA
STA
INX
CPX
BCS
LOA
CMP
BEQ
CMP
BNE
LOA
STA
INX
CPX
BCS
LOA
ANO
STA
BPL
JSR
SEC
RTS

($94), Y

erase buffer
file type

A
$C74A
#$3C
$02B2,X

bit 7 in carry
bit 6 not set?
,< ' for protected file
write behind file type

#$OF
$FEC5,Y
$02Bl,X

isolate bits 0-3
as file type marker
3rd letter of the file type
in buffer

$FECO,y
$02Bl,X

2nd letter of file type
in buffer

$FEBB,Y
$02Bl,X

1st letter of file type
in buffer

$C76B
#$2A
$02B2,X
#$AO
$02Bl,X

file not closed?
before file type in buffer
pad with 'shift blank'
in buffer

i$12
($94) ,Y
$02Bl,X

filenames
write in buffer

i$03
$C773
i$22
$02Bl,X

write before fi Ie type

$CnC

i$20
$C793
$02Bl,X
#$22
$C793
i$AO
$C783
#$22
$02Bl,X
i$20
$C7A7
#$7F
$02Bl,X
$02Bl,X
$C798
$C4B5

133

,* ,

'='

character from buffer
'='?
'shift blank' at end of name
fill through '='

bit 7
erase in the remaining chars
search for next directory entry

Anatomy of the 1541 Disk Drive

******************************
LDY #$lB
C7AC
AO IB
LDA #$20
C7AE
A9 20
STA $02BO,Y
C7BO
99 BO 02
88
DEY
C7B3
DO FA
BNE $C7BO
C7B4
C7B6
60
RTS

erase directory buffer

******************************
C7B7
20 19 Fl
JSR SF1l9
C7BA
20 DF FO
JSR $FODF
20 AC C7
C7BD
JSR SC7Ae
C7CO
A9 FF
LDA #SFF
C7C2
85 6F
STA $6F
LDX $7F
A6 7fo'
C7C4
8E 72 02
STX $0272
C7C6
A9 00
LDA #$00
C7C9
C7CB
8D 73 02
STA S0273
LDX $F9
C7CE
A6 F9
LOA $FEEO,X
BD EO ~'E
C7DO
C7D3
85 95
STA $95
AD 88 FE
C7D5
LDA $FE88
C7D8
85 94
STA $94
C7DA
AO 16
LOY #S16
Bl 94
LOA ($94),Y
C7DC
C7DE
C9 AO
CMP #$AO
C7EO
DO OB
BNE $C7EO
C7E2
A9 31
LOA #$31
,BYTE $2C
C7E4
2C
C7E5
Bl 94
LOA ($94),Y
C7E7
C9 AO
CMP #$AO
C7E9
DO 02
BNE $C7EO
C7EB
A9 20
LDA #$20
C7ED
99 B3 02
STA $02B3
C7FO
88
OEY
C7Fl
10 F2
BPL $C7E5
C7F3
A9 12
LDA #$12
C7F5
80 Bl 02
STA $02Bl
C7F8
A9 22
LOA #$22
C7FA
SD B2 02
STA $02B2
C7FD
8D C3 02
STA $02C3
C800
A9 20
LDA #$20
8D C4 02
C802
STA $02C4
C805
60
RTS

create header with disk name
initialize if needed
read disk name
erase buffer

******************************

$C7AC
#$OB
$Ca17,Y
$02Bl,Y

create last line
erase buffer
12 characters
'blocks free.'
write in buffer

$C80B
$EF40

number of free blocks in front

C806
C809
caOB
C80E
CBll
C8l2
CB14

20
AO
B9
99
88
10
4C

AC C7
OB
17 C8
Bl 02
F7
4D EF

JSR
LOY
LOA
STA
DEY
BPL
JMP

134

, , blank
write in buffer

drive number
as block no, 10 in buffer
block number 10
buffer number
hi-byte of the buffer address
$90, position of disk name
save
pad buffer with 'shift blank'
, l'

character from buffer
compare with 'shift blank'
, , blank
in buffer
'RVS ON'
in buffer
write before
and after disk name
, , blank
behind i t

Anatomy of the
******************************
C8l7
42 4C 4F 43 4B 53 20 46
C8lF
52 45 45 2E
*********~********************

C823
C826
C829
C82C
C82E
C830
C833
C835
C838
C83A
C83C
C83E
C840
C842
C845
C847
C849
C84B
C840
C84E
C850
C852
C855
C858
C85A
C85C
C85E
C861
C863
C866
C868
C86B
C860
0870
C872
C874
C876
C878
C87A

20
20
20
A9
85
20
30'
20
90
AO
B1
29
00
20
AO
Bl

98
20
CA
00
86
90
30
B7
33
00
94
40
2B
B6
13
94

C3
C3
C3
C4
00

C8

FO OA
85
C8
B1
85
20
AE
A9
35
00
BD
85
BD
85
20
E6
20
10
AS
85
A9
AO
4C

80
94
81
70
53
20
E7
00
80
80
85
81
70
86
8B
C3
86
80
01
00
A3

C8
02

02
02
C8
C4

Cl

JSR
JSR
JSR
LOA
STA
JSR
BMI
JSR
BCC
LOY
LOA
ANO
BNE
JSR
LOY
LOA
BEQ
STA
INY
LOA
STA
JSR
LOX
LDA
ANO
BNE
LOA
STA
LOA
STA
JSR
INC
JSR
BPL
LOA
STA
LOA
LOY
JMP

$C398
$C320
$C3CA
#$00
$86
$C490
$C872
$ODB7
$C860
#$00
($94),Y
1$40
$C860
$C8B6
11$13
($94),Y
$C855
$80
($94),Y
$81
$C870
$0253
11$20
$E7,X
$C86B
$0280,X
$80
$0285,X
$81
$C870
$86
$C48B
$C835
$86
$80
*$01
#$00
$CIA3

******************************
C870
20 SF EF
JSR $EF5F
C880
20 75 D4
JSR $0475
C883
20 19 Fl
JSR $F119
C886
B5 A7
LOA $A7,X
C888
C9 FF
CMP #$FF
CB8A
FO 08
BEQ $C894
C88C
AO F9 02
LOA $02F9
09 40
C88F
ORA #$40
C891
80 F9 02
STA $02F9
135

15~1

Oisk Orive

'blocks f'
'ree.'
S command
'scratch'
ascertain file type
get drive number
initialize drive if needed
counter for erased files
search for file in directory
not found?
is file open
yes
file type
scratch protect
yes
erase file and note in directory
track no. of the first side-sector
none present?
note track number
and sector number
erase side-sector
file number
bit 5 set?
yes, file not closed
get track
and sector
erase file
increment number of erased files
search for next file
if present, erase
number of erased files
save as 'track'
1 as disk status
o as 'sector'
message 'files scratched'
erase file
free block in BAM
get buffer number in BAM

Anatomy of the 1541 Disk Drive
C894
C896
C899
C89C
C89E
C8A1
C8A3
C8A5
C8A7
C8AA

A9 00

C8AD
C8BO
C8B3

20 5F EF
20 4D 04
4C 94 C8

20
20
85
20
85
A5
DO
20
4C

C8
56
80
56
81
80
06
F4
27

04
01
D1

EE
D2

#$00
$04C8
$D156
$80
$D156
$81
$80
$C8AO
$EEF4
$0227

track number
not equal to zero
write BAM
close channel

JSR $EF5F
JSR $D440
JMP $C894

free block in BAM
read next block
and continue

LOA
JSR
JSR
STA
JSR
STA
LOA
RNE
JSR
JMP

buffer pointer to zero
get track
get sector

******************************
C8B6
AO 00
LDY #$00
98
C8B8
TYA
C8B9
STA ($94) ,Y
91 94
C8BR
20 5E DE
JSR $DE5E
C8SE
JMP $0599
4C 99 05

erase directory entry
set file type to zero
write block
and check

**k***************************
C8C1
A9 31
LDA #$31
C8C3
4C C8 C1
JMP $C1C8

O-command

******************************
A9 4C
C8C6
LOA #$4C
C8C8
80 00 06
STA $0600
C8CB
A9 C7
LOA #$C7
C8CD
8D 01 06
STA $0601
C8DO
A9 FA
LOA #$FA
C802
8D 02 06
STA $0602
C8D5
A9 03
LOA #$03
C807
20 03 D6
JSR $0603
LOA $7F
C80A
AS 7F
C80C
09 EO
ORA #$EO
C80E
85 03
STA $03
LOA $03
C8EO
AS 03
C8E2
30 FC
BMI $C8EO
C8E4
C9 02
CMP #$02
90 07
BCC $C8EF
C8E6
C8ES
A9 03
LOA #$03
C8EA
A2 00
LOX #$00
4C OA E6
C8EC
JMP $E60A
60
C8EF
RTS

format diskette
JMP-command

******************************
C8FO
A9 EO
LOA #$EO
C8F2
8D 4F 02
STA $024F
C8F5
20 01 FO
JSR $F001
C8FS
20 19 Fl
JSR SF1l9
C8FB
A9 FF
LOA #$FF
C8FD
95 A7
STA $A7,X
C8FF
A9 OF
LOA #$OF

C-command

136

' backup'

31, 'syntax error'

JMP $FAC7 in $600 to $602

set track and sector number
drive number
command code for formatting
transmit
wait until formatting done
smaller than two, then ok
21, , read error'
'copy'

get buffer number of BAM

Anatomy of the 1541 Disk Drive
C90l
C904
C907
C909

8D
20
DO
4C

56 02
E5 Cl
03
Cl C8

C90C
C90F
C9l2
C915
C917
C919
C91C
C9H'
C921
C923
C925

20
20
AD
29
DO
AE
BO
C9
DO

F8
20
8B
55
OF
7A
00
2A
05
A9 30
4C C8

Cl
C3
02

C928
C92B
C920
C92F
C932
C934
C937
C93A
C93D
C940
C942
C944
C946
C948
C94B
C94E
C951

AD
29
DO
4C
A9
80
80
80
80

8B
09
F4
52
00
58
8C
80
81
E3
01
7F
01
91
7B
7A

02

C952
C955
C958
C95A
C95C
C95E
C960
C962
C964
C966
C968
C96A
C96C
C96E
C971
C973
C976
C979
C97C
C97E

20
AD
C9
90
A5
C5
DO
AS
C5
DO
AS
C5
DO
20
A9
80
20
20
FO
C9

4F
78
03
45
E2
E3
3F
DD
OE
39
08
09
33
CC
01
79
FA
25
04
02

C4
02

A4

29
85
09
80
AD
8D
60

02
02

Cl

C9
02
02
02
02

02
02
02

CA
02
C9
Dl

STA
JSR
BNE
JMP

$0256
$ClE5
$C90C
$C8Cl

JSR
JSR
LOA
AND
BNE
LOX
LOA
CMP
BNE
LOA
JMP

$ClF8
SC320
S028B
#$55
SC928
S027A
S0200,X
#S2A
SC928
#S30
SClC8

LOA
AND
BNE
JMP
LOA
STA
STA
STA
STA
LDA
AND
STA
ORA
STA
LOA
STA
RTS

S028B
#$D9
SC923
$C952
#$00
$0258
$028C
S0280
$0281
$E3
#$01
$7F
#SOI
$0291
S027B
S027A

JSR
LOA
CMP
BCC
LDA
CMP
BNE
LOA
CMP
BNE
LDA
CMP
BNE
JSR
LOA
STA
JSR
JSR
REO
CMP

$C44F
S0278
#$03
$C9Al
SE2
SE3
SC9Al
$OD
SOE
SC9Al
SD8
S09
SC9Al
SCACC
#S01
$0279

check input line
31, 'syntax errorcheck input
test drive number
flag for syntax check

character of the command

,* ,

30, 'syntax error'
syntax flag
30, 'syntax error l

number of drives
track number in directory

drive number

search for file in directolY
number of filenames in command
smaller than three?
yes
first drive number
second drive number
not on same drive?
directory block of the 1st file
same dir block as second file?
no
directory sector of first file
same dir sector as second file?
no
is file present

SC9~'A

S0125
SC982
#$02

get data type
reI-file?
prg-file
137

Anatomy of the 1541 Disk Drive
C980
C982
C984
C987
C989
C9SB
C9SE
C991
C993
C996
C999
C99B
C99E

DO
A9
20
A9
85
AD
SD
A9
8D
20
A2
20
4C

$C987
#$64
$CIC8
#$12
$83
$023C
$023D
#$fo'F
$023C
$DA2A
#$02
$C9B9
SC194

copy file
done

C9Al
C9A4

20 A7 C9
4C 94 Cl

JSR SC9A7
JMP SC194

copy file
done

C9A7
C9AA
C9AC
C9AE
C9BO
C9B3
C9B6
C9B9
C9BC
C9BF
C9Cl
C9C3

E7
E2
01
7f
86
E4
77
79
FA
11
83
EB
25
03
53
OS
F8
DS

CA

C9C9
C9CB
C9CE
C9DO
C9D2

20
A4
29
85
20
20
AE
8E
20
A9
85
20
20
DO
20
A9
85
4C

JSR
LDA
AND
STA
JSR
JSR
LOX
STX
JSR
LDA
STA
JSR
JSR
BNE
JSR
LDA
STA
JMP

SCAE7
SE2
#SOl
$7f
$0486
S06E4
$0277
$0279
$C9FA
#Sl1
S83
$OOEB
$0125
$C9CE
$CA53
#$OS
$fS
SC9D8

C9D5
C9D8
C90B
C9DO
C9EO
C9E2
C9E5
C9E7
C9EA
C9EO
C9EE
C9Fl
C9F3
C9F5
C9F7

20
20
A9
20
FO
20
FO
20
AE
E8
EC
90
A9
85
4C

9B
35
80
A6
F3
25
03
9B
79

CF
CA

JSR
JSR
LOA
JSR
BEO
JSR
BEO
JSR
LOX
INX
CPX
BCC
LDA
STA
JMP

$CF9B
$CA35
#$80
SODA6
$C9D5
$0125
$C9EA
$CF9B
$0279

C9FA
C9FO
C9FF

AE 79 02
B5 E2
29 01

C9C6

05
64
C8
12
S3
3C
3D
ff
3C
2A
02
B9
94

Cl
02
02
02
DA
C9
Cl

D4
D6
02
02
C9
DO
Dl
CA
C9

OD
01
CF
02

7S 02
C6
12
83
02 DB

BNE
LDA
JSR
LDA
STA
LDA
STA
LDA
STA
JSR
LDX
JSR
JMP

no
64, 'file type mismatch'
IS
secondary address

prepare append

drive no. of first file
drive number
enter file in directory

17
get data type
no reI-file?

write byte in buffer
and get byte
test bit 7
not set?
check file type
reI-file?
get data byte in buffer

$027S
$C9B9
#$12
$83
$DB02

18
close channel

LOX $0279
LDA $E2,X
ANO #$01

drive number

138

Anatomy of the 1541 Disk Drive
CAOI
CA03
CA06
CA08
CAOA
CAOC
CAOF
CAl2
CAl4
CAl7
CAIA
CAlC
CAIE
CA2l
CA23
CA26
CA29
CA2B
CA2E
CA30
CA3l
CA32
CA35
CA37
CA39
CA3C
CA3E
CA40
CA42
CA44
CA46
CM8
CA4B
CA40
CA4F
CA52

85
AO
85
B5
85
20
AE
B5
20
AE
B5
29
8D
A9
80
20
AO
20
FO
C8
98
4C
A9
85
20
85
A6
85
29
85
00
20
FO
A9
20
60

CA53
CA56
CA59
CA5B
CA5C
CASE
CA5F
CA61
CA63
CA66
CA69
CA6C
CA6F
CA71
CA73
CA75
CA77
CA79

20
20
AS
48
AS
48
A9
85
20
20
20
20
A5
85
AS
85
A9
85

7F
85
80
08
81
75
79
DO
C8
79
E7
07
4A
00
58
AO
01
25
01
C8
11
83
9B
85
82
F2
08
F8
OA
25
05
80
97

FE

04
02
04
02
02
02
09
01

04
03

Dl

00

03 01
CB El
06
05
12
83
07
03
CB
9C
06
87
05
86
00
88

01
01
EI
E2

STA
LOA
STA
LOA
STA
JSR
LOX
LOA
JSR
LOX
LOA
ANO
STA
LOA
STA
JSR
LOY
JSR
BEO
INY
TYA

$7F
$FE85
$80
SD8,X
$81
$0475
S0279
SDO,X
S04C8
S0279
$E7,X
#$07
S024A
#$00
$0258
$09AO
#SOI
$0125
$CA31

save
18, directory track
save
directory sector

J~1P

$04C8
#$11
$83
$039B
$85
$82
$F2,X
#$08
$F8
$CA52
$0125
$CA52
#$80
$D097

set buffer pointer
17

LOA
STA
JSR
STA
LOX
LOA
ANO
STA
BNE
JSR
BEO
LOA
JSR
RTS
JSR
JSR
LOA
PHA
LOA
PHA
LOA
STA
JSR
JSR
JSR
JSR
LOA
STA
LOA
STA
LOA
STA

read block
pointer in block
set buffer pointer
file type
isolate
and save
get parameters for reI-file
get file type
reI-file?

open channel and get byte
channel number
isolate end marker
not set?
get data type
reI-file?
set bit 7

$0103
$EICB
$06

set drive number

$05
#$12
$83
$0107
$0103
$EICB
$E29C
$06
$87
$05
$86
#$00
$88

18
open write channel
set drive number

139

Anatomy of the 1541 Disk Drive
CA7B
CA7D
CA7F
CA80
CA82
CA83
CA8S

85
85
68
85
68
85
4C

D4
D7
D5
D6
3B E3

STA
STA
PLA
STA
PLA
STA
JMP

$D4
$D7
$D5
$D6
$E33B

******************************

CA88
CA8R
CA8D
CA8F
CA91
CA93
CA9S
CA97
CA99
CA9C
CA9F'
CAAI
CAA3
CAA5
CAA7
CAA9
CAAC
CAAF
CABI
CAB2
CAB4
CAB7
CABA
CARB
CABE
CACO
CAC3
CAC6
CAC9

20
A5
29
85
C5
FO
09
85
20
20
A5
29
85
A5
85
20
20
A5
18
69
20
20
A8
AE
A9
20
20
20
4C

20
E3
01
E3
F.2
02
80
E2
4F
E7
E3
01
7F
D9
81
57
99
DE

C3

C4
CA

DE
DS

03
C8 D4
93 Dr'
7A
10
6E
5E
99
94

02
C6
DE
D5
Cl

JSR
LDA
AND
STA
CMP
BEO
ORA
STA
JSR
JSR
LDA
AND
STA
LDA
STA
JSR
JSR
LDA
CLC
ADC
JSR
JSR
TAY
LDX
LDA
JSR
JSR
JSR
JMP

$C320
$E3
#$01
$E3
$E2
$CA97
#$80
$E2
$C44F'
$CAE7
$E3
#$01
$7F
$09
$81
$OES7
$0599
$DE

2nd drive number
compare with 1st drive number
same?
search for file in directory
does name exist?
drive number
sector number
read block from directory
ok?
pointer to directory entry

#$03
$D4C8
$DF93

pointer plus 3 to file name
set buffer pointer
get buffer number

S027A
#$10
$C66E
$DE5E
$D599
$C194

16 characters
write name in buffer
write block to directory
ok?
done, prepare disk status

******************************

CACC
CACE
CADO
CAD3
CAD6
CAD?
CADA
CADC
CADF
CAEl
CAE3
CAE6

AS
29
8D
AE
CA
EC
90
BD
DO
A9
4C
60

E8
07
4A 02
78 02

CAE7
CAEA

20 CC CA
80 80 02

77 02
OA
80 02
FS
62
C8 Cl

LDA
AND
STA
LDX
DEX
CPX
BCC
LOA
BNE
LOA
JMP
RTS

R-command,
'rename'
get drive no. from command line

$E8
#$07
$024A
S0278

check i f file present
file type
save

$0277
$CAE6
$0280,X
$CAD6
#$62
$ClC8

JSR $CACC
LDA $0280,X
140

track number
not zero?
62,

I

file not found

I

does file exist with old n, me?
track number of new file

Anatomy of the 1541 Disk Drive
CAED
CAEF
CAFl
CAF4
CAF5
CAF7

FO
A9
4C
CA
10
60

05
63
C8 Cl
F3

BEO
LDA
JMP
DEX
BPL
RTS

SCAF4
#$63
$ClC8

file erased?
63, 'fi Ie exists'

SCAEA

******************************

CAF8
CAFB
CAFD
CAFF
CB02
CB04
CB07
CB09
CBOR
CROE
CBIO
CB12
CB15
CBl7
CB19
CBIR
CBID

AD
C9
DO
AD
85
AD
85
AO
AD
C9
FO
20
C9
FO
C9
DO
6C

01
2D
4C
03
6F
04
70
00
02
52
OE
58
57
37
45
2E
6F

02
02
02
02
F2

00

LDA
CMP
BNE
LDA
STA
LDA
STA
LDY
LDA
CMP
BEQ
JSR
CMP
BEO
CMP
BNE
JMP

S0201
#S2D
$CB4B
$0203
$6F
$0204
$70
#$00
S0202
#S52
SCB20
$F258
#S57
$CB50
#S45
$CB4B
(S006F)

******************************

6F
85
74 02
06
1A
05 02

'-'
address in $6F/S70

3rd character from buffer
' R'
to memory read
( RTS)

'w'
to memory write
' E'
memory-execute
'Memory-Read'
M-R,
read byte

CB20
CB22
CB24
CB27
CB29
CB2B
CB2E
CB2F
CB31
CB32
CB33
CB35
CB37
CB3A
CB3C
CB3E
CB40
CB42

Bl
85
AD
C9
90
AE
CA
FO
8A
18
65
E6
8D
A5
85
A5
85
4C

6F
6F
49 02
6F
A5
70
A6
43 D4

LDA
STA
LDA
CMP
RCC
LDX
DEX
BEO
TXA
CLC
ADC
INC
STA
LDA
STA
LDA
STA
JMP

CB45
CB48

20 EB DO
4C 3A D4

J~IP

JSR SDDEB
$D43A

open read channel
byte out

CB4B
CB4D

A9 31
4C C8 C1

LDA #$31
JMP $C1C8

31, 'syntax error'

14

($6F),Y
S85
$0274
#S06
$CR45
S0205

M-command,
'memory'
2nd character from buffer

SCR45

only one byte?
number of bytes

$6F
$6F
$0249
$6F
$A5
S70
SA6
SD443

plus start address
end pointer
buffer pointer for error mEssage
set to start address for ' r1-R'
byte out

******************************

CB50
CB53

B9 06 02
91 6F

length of command line
less than 6?
yes
number

LDA S0206,Y
STA (S6F), Y
141

M-W,
'memory-write'
read character
and save

Anatomy of the 1541 Disk Drive
CB55
CBS6
CBS9
CBSB

C8
CC OS 02
90 FS
60

INY
CPY $0205
BCC $CBSO
RTS

number of characters
all characters?

******************************

CBSC
CBSF
CB61
CB63
CR6S
CB67
CB69
CR6B

AC
CO
DO
A9
85
A9
85
60

01 02
30
09
EA
6R
FF
6C

CB6C
CR6F

20 72 CB
4C 94 Cl

JSR $CB72
JMP $C194

CB72
CB73
CB74
CB76
CB77
CB78
CB7A
C87C
CB70
Cll7F
CB81

88
98
29
OA
A8
Bl
85
C8
Bl
85
6C

OEY
TYA
AND
ASL
TAY
LOA
STA
INY
LOA
STA
JMP

OF
6B
75
6B
76
75 00

LOY
CPY
BNE
LOA
STA
LOA
STA
RTS

$0201
#$30
$CB6C
#$EA
$6B
#$FF
$6C

U-command,
second char
'0 '
no

'user'

ptr to table of user-addresses
$FFEA

done, prepare error message

#$OF
A

number
times 2

($6B), Y
$75

as pointer in table
address at $75/$76

($6B),Y
$76
($0075)

execute function

$028E
$7F
$83

open direct access channel, , #'
last drive number
drive number
channel number

$C630

check drive and initialize

$83
$0274

length of filename

OD
01
E2 01
Fl CB

LOA
STA
LOA
PHA
JSR
PLA
STA
LOX
DEX
BNE
LOA
,]SR
JMP

70
C8 Cl
01
7C CC
85 02
05
EF
00
6F
70

LOA
JMP
LOY
JSR
LOX
CPX
BCS
LDA
STA
STA

#$70
$CIC8
#$01
$CC7C
$0285
#$05
$CBAO
lI$OO
S6!"
S70

******************************

CB84
CB87
CB89
CB8B
CB8C
CB8F
CB90
CB92
CB95
CB96
CB98
CB9A
CB90

AO
85
AS
48
20
68
85
AE
CA
00
A9
20
4C

8E 02

CBAO
CBA2
CBAS
CBA7
CBAA
CBAD
CBAF
CBBI
CBB3
CBBS

A9
4C
AO
20
AE
EO
BO
A9
85
85

7F

83
30 C6
83
74 02

$CBAS
#$01
$01E2
$CBFl

greater than one?
layout buffer and channel
set flags, done
70, 'no channel'
get buffer number
buffer number
bigger than 5?
70, 'no channel'

142

Anatomy of the 1541 Disk Drive
CBB7
CBB8
CBBA
CBBC
CBBO
CBBF
CBCl
CBC4
CBC6
CBC8
CBCB
CBCO
CBCF
CB02
CBD5
CB07
CBOA
CBOO
CBOF
CBE2
CBE4
CBE7
CBE9
CBEA
CBEC
CBEE
CBn
CBF3
CBF6
CBF8
CBFB
CBFO
CBFF
CC02
CC04
CC07
CCOA
CCOD
CCOE
CCOF
CCll
CC13
CC15
CC18

38
26
26
CA
10
A5
20
DO
A5
20
DO
A5
00
8D
A5
00
8D
A9
20
A6
AD
95
AA
AS
95
9D
A6

BD
09
9D
A4
A9
99
A9
99
89
99
01'1
AA
A9
95
A9
99
4C

6F
70
F9
6F
4F
OA
70
50
D3
6F
4F
4F
70
50
50
00
E2
82
85
A7
7F
00
5B
83
28
40
2B
82
FF
44
89
F2
A7
3E

02
02
02
02
02
02
Dl
02

02
02
02
02
00
00
02

01
99
OE
EC 00
94 Cl

SEC
ROL
ROL
OEX
BPL
LOA
AND
BNE
LOA
AND
BNE
LOA
ORA
STA
LDA
ORA
STA
LOA
JSR
LDX
LOA
STA
TAX
LOA
STA
STA
LOX
LOA
ORA
STJ>.
LOY
LOA
STA
LOA
STA
LOA
STA
ASL
TAX
LOA
STA
LOA
STA
JMP

$6F
$70
$CBB8
$6F
$024F
$CBAO
$70
$0250
$CBAO
$6F
$024F
$024F
$70
$0250
$0250
lIS 00
$01E2
$82
$0285
$A7,X

search channel
channel number
buffer number

$7F
$OO,X
$025B,X
$83
$022B,X
#$40
$022B,X
$82
lI$FF
$0244,Y
#$89
$OOF2,Y
$00A7,Y
$023E,Y

drive number

A

times 2

#$01
$99,X
t$OE
$OOEC,Y
$C194

******************************
CClB
AD 00
LOY #$00
CClO
AO 00
LOX #$00
CClF
A9 20
LOA #$20
CC2l
20 68 C2
JSR $C268
CC24
DO OA
BNE $CC30
CC26
A9 31
LOA #$31
CC28
4C C8 Cl
JMP $CIC8

143

secondary address
set READ and WRITE flags
channel number
end pointer
set READ and WRITE flags
buffer number

buffer pointer to one
flag for direct access
done
B-command,

'Block'

'-'

search for minus sign
found?
31, 'syntax error'

Anatomy of the 1541

Dis~

Drive

CC2B
CC2D

A9 30
4C C8 Cl

LDA *$30
JMP $C1C8

CC30
CC3l
CC33
CC35
CC38
CC3B
CC3D
CC3E
CC40
CC42
CC43
CC45
CC48
CC46
CC4E
CC4F
CC50
CC53
CC55
CC58
CC5A

8A
DO
A2
B9
DO
FO
CA
10
30
8A
09
8D
20
AD
OA

TXA
BNE
LDX
LDA
CMP
BEQ
OEX
BPL
BMI
TXA
ORA
STA
JSR
LDA
ASL

F8
05
00 02
5D CC
05
F8
E4
80
2A 02
6F CC
2A 02

AA

BO
85
BD
85
6C

30, 'syntax error'

$CC2B
#$05
$0200,Y
$CC5D,X
$CC42

char from buffer
compare with 'AFRWEP'
found?

$CC38
$CC26

compare with all characters
not found, error

*$80
$022A
$CC6F
$022A

command number, set bit 7
get parameters

A

TAX

64 CC
70
63 CC
6F
6F 00

LDA
STA
LOA
STA
JMP

comma, then error

$CC64,X
$70
$CC63,X
$6F
($006F)

number times 2
as index
address of command hi
address 10
jump to command

******************************
CC5D
41 46 52 57 45 50

names of the various block cmds
'AFRWEP'

******************************
CC63
03 CD
F5 CC
CC65
CC67
56 CD
73 CD
CC69
CC6B
A3 CD
BO CD
CC60

addresses of block commands
$CD03, B-A
$CCF5, B-F
$CD56, B-R
$CD73, B-W
$CDA3, B-E
$CDBO, B-P

******************************

get parameters for block command I

CC6F
CC71
CC73
CC75
CC78
CC7A
CC7C
CC7F
CC8l
CC83
CC85
CC87
CC89
CC8B
CC8C
CCBF
CC9l

AO
A2
A9
20
DO
AO
B9
C9
FO
C9
FO
C9
DO
C8
CC
90
60

00
00
3A
68 C2
02
03
00 02
20
08
lD
04
2C
07
74 02
EB

LOY
LDX
LDA
JSR
BNE
LDY
LOA
CMP
BEO
CMP
BEQ
CMP
BNE
INY
CPY
BCC
RTS

41$00
*$00
*$3A
$C268
$CC7C
*$03
$0200,Y
i$20
$CC8B
#$10
$CC8B
#$2C
$CC92
$0274
$CC7C

I:'

test line to colon
found?
no, begin at 4th character
search for separating char
, , blank
cursor right

',I comma
line end?

144

Anatomy of the 1541 Disk Drive
CC92
CC95
CC98
CC9B
CC9D
CC9F
CCAI
CCA3
CCA5
CCA7
CCA9
CCAB
CCAE
CCBO
CCB2
CCB4
CCB6
CCB8
CCB9
CCBB
CCBD
CCBF
CCCI
CCC2
CCC4
CCC5
CCC7
CCCA
CCCD
CCCE
CCDO
CCDI
CCD3
CCD5
CCD7
CCD8
CCDA
CCDD
CCDF
CCEO
CCE2
CCE4
CCE5
CCE8
CCEA
CCED
CCEE
CCFl

20
EE
AC
EO
90
BO
A9
85
85
85
A2
B9
C9
BO
C9
90
29
48
A5
85
A4
85
68
85
C8
CC
90
8C
18
A9
E8
EO
BO
B4
88
30
7D
90
18
E6
DO
48
AE
A5
9D
68
9D
60

Al
77
79
04
EC
8A
00
6F
70
72
FF
00
40
18
30
14
OF

CC
02
02

02

70
71
6F
70
6F
74 02
El
79 02
00
03
OF
6F
F6
F2 CC
F8
72
F3
77 02
72
80 02
85 02

JSR
INC
LOY
CPX
BCC
BCS
LDA
STA
STA
STA
LOX
LDA
CMP
BCS
CMP
BCC
AND
PHA
LDA
STA
LDA
STA
PLA
STA
INY
CPY
BCC
STY
CLC
LDA
INX
CPX
BCS
LDY
DEY
BMI
ADC
BCC
CLC
INC
BNE
PHA
LDX
LDA
STA
PLA
STA
RTS

$CCAI
$0277
$0279
*$04
$CC8B
$CC2B
*$00
$6F
$70
$72
*$FF
$0200,Y
*$40
$CCCA
#$30
$CCCA
#$OF
$70
$71
$6F
$70

compare with maximum number
30, 'syntax error'
erase storage area for decimal *s
get characters from input buffer
no digits?
'0 '
no digits?
convert ASCII digits to hex
and save
move digits one further

$6F

note read number
increment pointer in input buffer
line end reached
no
save pointer

$0274
$CCAB
$0279
#$00
lI$03
$CCE4
$6F,X

convert hex digits to one byte

$CCDO
$CCF2,X
$CCD7

add decimal value

$72
$CCD7
$0277
$72
$0280,X

counter for parameters

$0285,X

10-byte

******************************

CCF2

preserve next parameter
increment parameter counter

01 OA 64

******************************
CCF5
20 F5 CD
JSR $CDF5
CCF8
20 SF EF
JSR $EF5F

145

hi-byte

decimal values
1, 10, 100
B-F command,
'Block-Free'
get track, sector and drive no.
free block

Anatomy of the 1541 Disk Drive
CCFB

4C 94 Cl

done, prepare error message

JMP $C194

******************************
LDA 11$01
CCFE
A9 01
80 F9 02
STA $02F9
COOO
******************************
20 F5 CD
JSR $CDF5
C003
A5 81
LDA $81
C006
PHA
48
C008
C009
20 FA Fl
JSR $FlFA
FO OB
BEQ $CDl9
CDOC
COOE
PLA
68
COOF
C5 81
CMP $81
BNE $CD2C
COll
00 19
COl3
20 90 EF
JSR $EF90
4C 94 Cl
JMP $C194
C016

COl9
COlA
COIC
COlE
C020
C022
CD25
CD27
CD2A
C02C
CD2E
CD31
CD33

68
A9
85
E6
A5
CD
BO
20
FO
A9
20
A9
20

00
81
80
80
07
OA
FA
EE
65
45
65
C8

FE
Fl

E6
Cl

PLA
LDA
STA
INC
LDA
CMP
BCS
JSR
BEQ
LDA
JSR
LDA
JSR

11$00
$81
$80
$80
$FED7
$CD31
$FIFA
SCOlA
11$65
$E645
11$65
$CIC8

B-A command,
'Block-Allocate'
get track, sector and drive no.
sector
save
find block in BAM
block allocated?
desired sector
= next free sector?
no
allocate block in BAM
done

sector 0
next track
track number
36, last track number + 1
>=, then 'no block'
find free block in next track
not found, check next track
65, 'no block' next free block
65,'no block' no more free blocks

******************************
JSR $CDF2
CD36
20 F2 CD
4C 60 D4
JMP $D460
CD39

open channel, set parameters
read block from disk

******************************
CD3C
JSR $D12F
20 2F 01
CD3F
Al 99
LDA ($99,X)
RTS
60
CD41

get byte from buffer
set pointer to buffer
get byte

******************************
CD42
JSR $C036
20 36 CD
CD45
A9 00
LOA 11$00
CD47
20 C8 D4
JSR $04C8
JSR
$CD3C
CD4A
20 3C CD
99 44 02
STA $0244,Y
CD4D
A9 89
LDA $89
CD50
99 F2 00
STA $00F2,Y
CD52
60
RTS
CD55

read block from disk
open channel, read block
set buffer pointer to zero
get a byte from the buffer

******************************
CD56
20 42 CO
JSR $C042
20 EC D3
JSR $D3EC
CD59
CD5C
4C 94 Cl
JMP $C194

B-R command,
'Block-Read'
read block from disk
prepare byte from buffer
prepare error message

146

set read and write flag

Anatomy of the 1541 Disk Drive

******************************
20 6F CC
JSR $CC6F
CD5F
20 42 CD
JSR $CD42
CD62
B9 44 02
LDA $0244,Y
CD65
99 3E 02
STA $023E,Y
CD68
CD6B
A9 FF
LDA #$FF
CD6D
99 44 02
STA $0244,Y
CD70
4C 94 Cl
JMP $C194

Ul command, sub. for 'Block-Read'
get parameters of the command
read block from disk
end pointer
save as data byte

******************************
CD73
20 F2 CD
JSR $CDF2
CD76
20 E8 D4
JSR $D4E8
CD79
A8
TAY
CD7A
88
DEY
CD7B
C9 02
CMP #$02
CD7D
BO 02
BCS $CD81
CD7F
LDY #$01
AO 01
CD81
A9 00
LDA #$00
CD83
20 C8 D4
JSR $D4C8
CD86
98
TYA
CD87
20 Fl CF
JSR $CFFI
CD8A
8A
TXA
CD8B
48
PHA
20 64 D4
JSR $D464
CD8C
CD8F
68
PLA
CD90
AA
TAX
CD91
20 EE D3
JSR $D3EE
CD94
4C 94 Cl
JMP $C194

R-W command,
'Block-Write'
open channel
set bUffer pointer

******************************
CD97
20 6F CC
JSR $CC6F
CD9A
20 F2 CD
JSR $Cm'2
20 64 D4
JSR $D464
CD9D
CDAO
4C 94 Cl
JMP $C194

U2, sub for 'Block-Write'
get command parameters
open channel
and write block to disk
done

******************************
20 58 F2
CDA3
JSR $F258
CDM
20 36 CD
JSR $CD36
CDA9
A9 00
LDA #$00
CDAB
85 6F
STA $6F
CDAD
LDX $F9
A6 F9
CDAF
BD EO FE
LDA $FEEO,X
STA $70
CDB2
85 70
CDB4
20 BA CD
JSR $CDBA
CDB7
4C 94 Cl
JMP $C194
CDBA
6C 6F 00
JMP ($006F)

'B-E' command,
'Block-Execute'
(RTS)
open channel and read block

******************************
CDBD
20 D2 CD
,ISR $CDD2
CDCO
A5 F9
LDA $F9
CDC2
OA
ASL A
CDC3
AA
TAX
AD 86 02
CDC4
LDA $0286
CDC7
95 99
STA $99,X

'B-P' command,
'Block-Pointer'
open channel, get buffer number
buffer number

147

end pointer to $FF
done, prepare error message

buffer pointer 10 less than 2?
no
buffer pointer to zero
write byte in buffer
write block to disk
get byte from buffer
done, error message

address low
buffer number
buffer address high
execute routine
done
jump to routine

*

2

as index
pointer value
save as buffer pointer

Anatomy of the 1541 Disk Drive
CDC9
CDCC
CDCF

20 2F Dl
20 EE D3
4C 94 Cl

prepare a byte in buffer
for output
done

JSR SD12F
JSR SD3EE
JMP SC194

******************************

CDD2
CDD4
CDD6
CDD9
CODA
CDDB
CDDC
CDDE
CDEO
CDE2

A6
E6
BD
A8
88
88
CO
90
A9
4C

D3
D3
85 02

CDE5
CDE7
CDEA
COEC
COEF
COFI

85
20
BO
20
85
60

83
EB DO
F4
93 OF
F9

OC
05
70
C8 Cl

open channel

LOX
INC
LOA
TAY
DEY
DEY
CPY
BCC
LDA
JMP

$D3
S03
S0285,X

#$OC
$COE5
#$70
$ClC8

buffer number smaller than 14?
yes

STA
JSR
BCS
JSR
STA
RTS

$83
$OOEB
SCOEO
$OF93
$F9

secondary address
open channel
already allocated,70 'no channel
buffer number
set

buffer number

70, 'no channel'

******************************
20 02 CO
JSR $C002
COF2
LOX $D3
A6 03
COF5
BO 85 02
LOA $028S,X
COF7
COFA
29 01
AND #$01
85 7F
STA $7F
COFC
BO 87 02
LOA $0287,X
COFE
CEOI
85 81
STA $81
BO 86 02
LOA $0286,X
CE03
85 80
STA S80
CE06
CE08
20 SF 05
JSR $055F
CEOB
4C 00 Cl
JMP SCI00
******************************
.]SR $CE2C
CEDE
20 2C CE
CEll
20 6E CE
JSR SCE6E
CE14
A5 90
LDA S90
85 D7
STA S07
CE16
20 71 CE
JSR SCE7l
CE18
E6 07
INC $07
CEIB
E6 D7
CEIO
INC SD7
A5 8B
LDA $8B
CEIF
CE2l
85 D5
STA $D5
A5 90
CE23
LOA S90
OA
ASL A
CE25
CLC
CE26
18
CE27
69 10
AOC #SlO
CE29
85 D6
STA $06
60
CE2B
RTS

check buffer no. and open channe
channel number
buffer address
drive number
sector
track
track and sector ok?
turn LED on
set pointer for reI-file
record number * record length
divide by 254
remainder = pointer in data bloc)
data pointer
divide by 120 = side-sector #
data ptr + 2 (track/sector ptr!)
result of division
equals side-sector number
remainder
times 2
plus 16
=ptr in side-sector to data

******************************

CE2C

20 D9 CE

JSR SCE09

erase work storage

148

bloc~

Anatomy of the 1541 Disk Drive
CE2F
CE31
CE33
CE35
CE37
CE39
CE3B
CE30
CE3F
CE41
CE43
CE44
CE46
CE48
CE4A
CE4C
CE4E
CE50
CE52
CE54
CE57
CE5A
CE5C
CE5E
CE60
CE61
CE63
CE65
CE67
CE69
CE6B
CE6D

85
Ali
B5
85
B5
85
00
A5
FO
A5
38
E9
85
BO
C6
B5
85
46
90
20
20
A5
00
A5
18
65
85
90
E6
DO
E6
60

92
82
B5
90
BB
91
04
90
OB
90
01
90
02
91
C7
6F
6F
03
ED CE
E5 CE
6F
F2
04

8B
8B
06
8C
02
80

STA
LOX
LOA
STA
LOA
STA
BNE
LOA
BEO
LDA
SEC
SBC
STA
BCS
DEC
LDA
STA
LSR
BCC
JSR
JSR
LOA
BNE
LOA
CLC
ASC
STA
BCC
INC
BNE
INC
RTS

$92
$82
$B5,X
$90
$BB,X
$91
$CE41
$90
$CE4C
$90

channel number
record number 10
record number hi

record number not zero?

#$01
$90
SCE4C
$91
$C7,X
$6F
$6F
$CE57
$CEED
$CEE5
$6F
$CE50
$04

then subtract one

record length

record number * record length
shift reg ister left

$8B
$8B
$CE6D
$8C
$DE6D
$80

result in $8B/$8C/$8D

******************************

CE6E
CE70

A9 FE
2C

LDA #$FE
.BYTE $2C

******************************

CE7l
CE73
CE75
CE77
CE79
CE7A
CE7C
CE7E
CE7F
CE8l
CE82
CE84
CE87
CE89
CE8B
CE80
CE8E

A9
85
A2
B5
48
85
95
68
95
CA
DO
20
A2
85
95
E8

78
6F
03
8F
8A
8F
8A
F3
D9 CE
00
90
8F

EO 04

LOA
STA
LOX
LOA
PHA
LDA
STA
PLA
STA
OEX
BNE
JSF
LOX
LOA
STA
INX
CPX

#$78
S6F
#$03
$8F,X

divide by 254, calculate block #
254
divide by 120, calculate
side-sector number
divisor

$8A,X
$8F,X
S8A,X
SCE77
$CE09
#$00
$90,X
S8F,X

erase work storage

#$04
149

Anatomy of the 1541 Disk Drive
CE90
CE92
CE94
CE96
CE98
CE9A
CE9C
CE9D
CE9F
CEAO
CEA3
CEA6
CEM
CEAB
CEAD
CEBO
CEB2
CEB3
CEB5
CEB7
CEB9
CEBB
CEBD
CEBF
CEC1
CEC3
CEC5
CEC7
CEC8
CECA
CECC
CECE
CEDO
CED2
CED4
CED8

90
A9
85
24
30
06
08
46
28
20
20
20
24
30
20
AS
18
65
85
90
E6
DO
E6
AS
05
DO
AS
38
E5
90
E6
DO
E6
DO
85
60

F7
00
92
6F
09
8F
8F
E6
ED
E5
6F
03
E2
8F
90
90
06
91
02
92
92
91
C2
90
6F
OC
8B
06
8C
02
90

CE
CE
CE
CE

BCC
LDA
STA
BIT
BMI
ASL
PHP
LSR
PLP
JSR
JSR
JSR
BIT
BMI
JSR
LDA
CLC
ADC
STA
BCC
INC
BNE
INC
LDA
ORA
BNE
LDA
SEC
SBC
BCC
INC
BNE
INC
BNE
STA
RTS

$CE89
#$00
$92
$6F
$CEA3
$8F
$8F
$CEE6
$CEED
$CEE5
$6F
$CEBO
$CEE2
$8F

shift register 1 left
add register 0 to register 1
shift register 1 left
left-shift reg ister 1 twice

$90
$90
$CEBF
$91
$CEBF
$92
$92
$91
$CE87
$90
$6F
$CED8
$8B
$CED6
$8C
$CED6
$90

quotient in $8B/$8C/$8 D

remainder in $90

******************************
CED9
A9 00
LDA #$00
85 8B
CEDB
STA $8B
CEDD
85 8C
STA $8C
CEDF
85 8D
STA $8D
CEEl
60
RTS

erase work storage

******************************
CEE2
20 E5 CE
JSR $CEE5

left-shift 3-byte register twice

******************************
CEE5
18
CLC
CEE6
29 90
ROL $90
CEE8
26 91
ROL $91
CEEA
26 92
ROL $92
CEEC
60
RTS

left-shift 3-byte register once

******************************

150

Anatomy of the 1541 Disk Drive
CEED
CEEE
CEFO
CEF2
CEF4
CEF6
CEF7
CEF9

18
A2
B5
75
95
E8
DO
60

CEFA
CEFC
CEFD
CEFF
0'00
CF02
Cr'04
CF06
Cr'08

A2
8A
95
E8
EO
DO
A9
95
60

CF09
O'OB
CFOD

AO
A6
B9
96
C5
FO
88
30
AA
4C
60

cno

CF12
Cl"l4
CFl6
CF'l7
CF19
CFIA
CFlD
CFIE
0'21
CF24
CF26
CF29
CF2C
CF2E
0'31
0'33
CF34
CF36
CF37
CF39

cnc

CF3E
CF40
CF43
CF45
CF47
CF4A
0'4C
CF4F
0'51
CF54

FD
8E
93
8E
F7
00
FA
04
F8
06
FA
04
82
FA 00
FA
82
07
El
OD CF

20 09 CF
20 B7 OF
DO 46
20 D3 D1
20 8E D2
30 48
20 C2 OF
A5 80
48
A5 81
48
A9 01
20 F6 D4
85 81
A9 00
20 F6 D4
85 80
FO IF
20 25 D1
FO Os
20 AB DD
D(I 06
20 8C CF
4C 50 n'

CLC
LOX
LOA
ADC
STA
INX
BNE
FTS
LDX
TXA
STA
INX
CPX
BNE
LDA
STA
RTS

#$FD
$8E,X
$93,X
$8E,X

register $90/$91/$92
add to register $8B/$SC/$8D

$CEFO
#$00
$FA,X
#$04
$CEFC
#$06
$FA,X

LDY
LDX
LDA
STX
CMP
BEO
DEY
BMI
TAX
JMP
RTS

#$04
$82
$OOFA,Y
$FA,Y
$82
$CFlD

JSF
JSR
BNE
JSF
JSR
BMI
JSR
LOA
PHA
LDA
PHA
LDA
JSF
STA
LDA
JSR
STA
BEO
JSR
BEO
JSR
BNE
JSR
JMP

$CF09
SDFB7
SCF6C
$D1D3
$D28E
$CF76
$OFC2
$80

set drive number

$81

sector

channel number
channel number

$CE~'A

$CFOD

track

#$01
$D4F6
$81
#$00
SD4F6
$80
$CF66
$D125
$CF57
$DDAR

get byte 1 from buffer
sector
get byte 0 from buffer
track
check file type
reI-file?

$C~'57

$CF8C
SCF5D
151

Anatomy of the 1541 Disk Drive

CFS7
CF5A
CF5D
CP5E
CF60
CF63

20
20
68
85
68
85
4C

CF66
CF67
CF69
CF6A
CP6C
CF6P
CF72
CF73

68
85
68
85
20
20
AA
4C

CP76

cns

A9 70
4C C8 Cl

LDA #$70
JMP $ClCS

CF7B
Cl"7E
CF8l
CF83
CF86
Cl"88
CF8B

20
20
DO
20
30
20
60

JSR
JSR
BNE
JSR

C~'61

8C CF
57 DE
81
80
6F CF
81
80
8C CF
93 DF
99 D5

09
B7
08
8E
EE
C2

CF'
DF
D2
DF

JSR
JSR
PLA
STA
PLA
STA
JMP
PLA
STA
PLA
STA
JSR
JSR
TAX
JMP

$CF8C
$DE57
$81

get sector

$SO
$CP6F

and track number

$81

get back sector

$80
$CF8C
$DF93

and track number

$D599

and verify
70,

$CF09
$DFB7
$CF8B
$D28E
B~II $CF76
JSR $DFC2
RTS

******************************

CF8C
CF8E
CF90
CF92
CF94
CF96
CF98
CF9A

A6
B5
49
95
B5
49
95
60

82
A7
80
A7
AE
80
AE

LDX
LDA
EOR
STA
LDA
EOR
STA
RTS

$82
$A7,X
#$80
$A7,X
$AE,X
#$80
$AE,X

A2
86
20
20
20
90
A9
20
AS
C9
PO
DO

C~'B7

A5 84
29 8F

CFB9

12
83
07
00
25
05
20
9D
83
OF'
23
08

Dl
Cl
D1
DD

LDX
STX
JSR
JSR
JSR
BCC
LDA
JSR
LDA
CMP
BEO
BNE

change buffer
channel number

rotate bit 7 in table

******************************

CF9B
CE'9D
CF9F'
CFA2
CFA5
CF'AB
CFAA
CFAC
CF'AP
CF'BI
n'B3
CFB5

'no channel'

#$12
$83
$D107
$C100
$D125
$CF'AF
#$20
$DD9D
$83
#$OF'
$Cf'D8
$CF'BF'

write data byte in buffer
channel 18
open write channel
turn LED on
check file type
no reI-file
change buffer
secondary address

IS?
yes
no

LDA $84
AND #$8P

secondary address

152

Anatomy of the 1541 Disk Orive
CFBB
CFBO
CFBF
CFC2
CFC4
CFC6

C9
BO
20
BO
AS
4C

CFC9
CFCB

00 03
4C AB EO

CFCE
CFDO
CFD3
CF05

AS
20
A4
4C

85
Fl CF
82
EE 03

LOA
JSR
LDY
JMP

$85
$CFF1
$82
$D3EE

CFD8
CFDA
O'DF
CFE1
CFE3
CFE5
CFE8
CFEA
CFEC

A9
85
20
C9
FO
AS
20
A5
FO
60

04
82
E8 D4
2A
05
85
Fl CF
F8
01

LDA
STA
JSR
CMP
BEO
LDA
JSR
LOA
BEO
RTS

#$04
$82
$D4E8
#$2A
$CFE8
$85

channel 4
corresponding input buffer
set buffer pointer
40
buffer end?

$C~'F1

write data byte in buffer
end flag set?
yes

CFED
CFFO

EE 55 02
60

C~'DC

OF
19
25 01
05
85
90 01

CMP
BCS
JSR
BCS
LOA
JMP

#$OF
$CFD8
$0125
$CFC9
$85
$0190

greater than 15?
then input buffer
check file type
reI-file or direct access?
data byte
write in buffer

BNE $CFCE
JMP $EOAB

direct access file?
write data byte in reI-file
write data byte in buffer
channel number
prepare next byte for output

$F8
$CFEO

INC $0255
RTS

set command flag

******************************

CFFl
CFF2
CFF5
0'F7
CFF8
CFFA
CFFD
O'FE
CFFF
DODO
D002
D004

48
20
10
68
A9
4C
OA

93 OF
06
61
C8 C1

AA

68
81 99
1"6 99
60

PHA
JSR
BPL
PLA
LDA
JMP
ASL
TAX
PLA
STA
INC
RTS

$DF93
$CFFD
#$61
$C1C8
A
($99,X)
$99,X

******************************

D005
D008
DOOB

20 D1 C1
20 42 DO
4C 94 C1

JSR $C1Dl
JSR $0042
JMP $C194

******************************

DOOE
DOll
D012
D014
D016
D019

20 OF Fl
A8
86 A7
EO 1"1"
48
20 8E 02

JSR
TAY
LDX
CPX
PHA
JSR

SFIOF
SA7,Y
#SFF
$D28E

153

write data byte in buffer
save data byte
get huffer number
associated buffer?
61, ' file not open'
buffer number times 2
as index
data byte
write in buffer
increment buffer pointer
I-command, Initialize
find drive number
load BAM
prepare disk status

Anatomy of the 1541 Disk Drive
DOIC
DOID
D02l
D024
D025
D026
DO 27
D029
D02C
D02D
D02F
0031
D033
D035
D038
D03A
D03D
D03F

AA

A9
20
68
A8
8A
09
99
8A
29
85
A2
86
AE
86
20
A9
4C

70
48 E6

80
A7 00
OF
F9
00
81
85 FE
80
D3 D6
BO
8C D5

TAX
LDA
JSR
PLA
TAY
TXA
ORA
STA
TXA
AND
STA
LDA
STX
LDX
STX
JSR
LDA
JMP

lI$70
$E648

70, 'no channel'

H80
$OOA7,Y
lISOF
SF9
lISOO
S81
SFE85
$80
$D6D3
#$BO

sector 0

18
track 18
transmit param to disk controll
command code 'read block header
transmit to disk controller

$D58C

******************************
D042
20 Dl Fa
JSR $FODI
D045
20 13 D3
JSR $D313
D048
JSR $DOOE
20 OE DO
D04B
LDX $7F
A6 7F
D04D
A9 00
LDA lISOO
D04F
9D 51 02
STA S025l,X
D052
8A
TXA
D053
OA
ASL A
D054
AA
TAX
D055
AS 16
LDA S16
D057
95 12
STA $12,X
D059
LDA $17
A4 17
D05B
95 13
STA S13 ,X
D05D
JSR $D586
20 86 D5
D060
AS F9
LDA $F9
D062
OA
ASL A
D063
AA
;TAX
D064
A9 02
LDA #$02
D066
95 99
STA $99,X
D068
Al 99
LDA ($99,X)
D06A
A6 7F
LDX S7F
D06C
9D 01 01
STA SOlOl,X
D06F
A9 00
LDA #$00
95 lC
D07l
STA $lC,X
D073
95 FF
STA $FF,X
******************************

D075
D078
D07A
D07C
D07D
D07E
0080
D082

20 3A EF
AO 04
A9 00
AA

18
71 6D
90 01
E8

JSR
LDY
LOA
TAX
CLC
ADC
BCC
INX

$EF3A
lI$04
#SOO
(S6D),Y
$D083

load BAM
read block
drive number
reset flag for 'BAM changed'

save ID
buffer number
buffer pointer to $200
get character from buffer
drive number
flag for write protect
flag for read error
calculate blocks free
buffer address to $6D/$6E
begin at position 4

add no. of free blocks per track
X as hi-byte

154

Anatomy of the 1541 Disk Drive
D083
D084
D085
D086
D087
D089
D08B
D08D
D08F
D090
D091
D093
D096
D097
D09A

C8
C8
C8
C8
CO
FO
CO
DO
48
8A
A6
9D
68
9D
60

48
F8
90
EE
7F
FC 02
FA 02

INY
INY
INY
INY
CPY
BEO
CPY
BNE
PHA
TXA
LDX
STA
PLA
STA
RTS

plus 4
#$48
$D083
#$90
$D07D
$7F
$02FC ,X
$02FA,X

track 18?
then skip
last track number?
no
lo-byte
hi-byte
drive number
hi-byte to $2FC
lo-byte
to $2FA

******************************

D09B
D09E
DOAI
DOM
DOA7
DOA9
DOAC
DOAE

20
20
20
20
85
20
85
60

DO
C3
99
37
80
37
81

DOAF
DOR2
DOR4
DOB6
DOB7
DOBA
DOBD
DOCO

20
A5
DO
60
20
20
20
4C

9B DO
80
01
IE
DO
C3
IE

D6
DO
D5
Dl
Dl

CF
D6
DO
CF

JSR
JSR
JSR
JSR
STA
JSR
STA
RTS

$D6DO
$DOC3
$D599
$D137
$80
$D137
$81

parameters to disk controller
read block
ok?
get byte from buffer
track
next byte from buffer
sector

JSR
LDA
BNE
RTS
JSR
JSR
JSR
JMP

$D09B
$80
$DOB7

track

$CFlE
$D6DO
$DOC3
$CFIE

change buffer
parameters to disk controller
read block
change buffer

******************************

DOC3
DOC5

A9 80
DO 02

LDA #$80
BNE $DOC9

******************************

DOC7
DOC9
DOCC
DOCF
DODO
DOD3
DOD4
DOD5
DOD6
DOD7
DOD9
DODB
DaDE
DOEO
DOE2

A9
8D
20
AA
20
SA
48
aA
AA
A9
95
20
C9
BO
F6

90
4D 02
93 DF
06 D5

00
99
25 Dl
04
06
B5

LDA
STA
JSR
TAX
JSR
TXA
PHA
ASL
TAX
LDA
STA
JSR
CMP
BCS
INC

read block
code for tread'

#$90
$024D
$DF93

write block
code for 'write'
save
get buffer number

$D506

get track/sector, read/write blk

A

buffer pointer times 2

#$00
$99,X
$D125
#$04
SDOES
SB5,X

pointer in buffer to zero
get file type
reI-file or direct access?
yes

155

Anatomy of the 1541 Disk Drive
DOE4
DOE6
DOE8
DOE9
DOEA

DO 02
F6 BB
68
AA

60

BNE $DOE8
INC $BB,X
PLA
TAX
RTS

increment block counter

******************************
DOEB
A5 83
LOA $83
DOED
C9 13
CMP #$13
DOEF
90 02
BCC $DOF3
DOFI
29 OF
AND #$OF
DOF3
C9 OF
CMP #$OF
DOF5
DO 02
BNE $DOF9
DOF7
A9 10
LOA #$10
DOF9
AA
TAX
DO FA
38
SEC
DOFB
BD 2B 02
LOA $022B,X
DOFE
30 06
BMI $0106
DI00
29 OF
AND #$OF
DI02
85 82
STA $82
DI04
AA
TAX
0105
18
CLC
DI06
60
RTS

open channel for reading
secondary address
19
smaller?

******************************
0107
A4 83
LDA $83
DI09
C9 13
CMP #$13
DI0B
90 02
BCC $DI0F
0100
29 OF
AND #$OF
DI0F
AA
TAX
DllO
BO 2B 02
LDA $022B,X
DID
A8
TAY
OA
D1l4
ASL A
90 OA
BCC $D121
D1l5
D1l7
30 OA
BMI S0123
98
TYA
D1l9
DllA
29 OF
AND #SOF
DllC
85 82
STA S82
AA
DllE
TAX
18
DllF
CLC
D120
60
RTS

open channel for writing
secondary address
19
smaller?

D121
0123
0124

30 F6
38
60

BMI $D119
SEC
RTS

A6
B5
4A
29
C9
60

82
EC
07
04

LOX
LDA
LSR
AND
OIP
RTS

flag for ok

channel number

flag for ok

flag for channel allocated

***.*.** •• i**.** •• ************
0125
0127
D129
D12A
D12C
Ol2E

16

check for file type 'REL'

S82
$EC,X

A
#$07
#$04

'REL'?

***************.**************
156

get buffer and channel numbers

Anatomy of the 1541 Disk Drive
012F
0132
0133
0134
0136

20 93 OF
OA
AA
A4 82
60

JSR $OF93
ASL A
TAX
LOY $82
RTS

get buffer number

******************************

0137
013A
0130
013F
0141
0142
0144
0147
0149
014B
0140
014E
0150
0151
0153
0155

20
B9
FO
Al
48
B5
09
00
A9
95
68
F6
60
Al
F6
60

2F 01
44 02
12
99
99
44 02
04
FF
99
99
99
99

JSR
LOA
BEO
LOA
PHA
LOA
CMP
BNE
LOA
STA
PLA
INC
RTS
LOA
INC
RTS

$012F
$0244,Y
$0151
($99,X)
$99,X
$0244,Y
$014D
i$FF
$99,X

($99,X)
S99,y

get character from buffer
increment buffer pointer

20
00
85
B9
FO
A9
99
A5
60

37 01
36
85
44 02
08
80
F2 00
85

JSR
BNE
STA
LOA
BEQ
LOA
STA
LOA
RTS

S0137
$0191
$85
$0244,Y
S016A
i$80
$00F2,Y
$85

016A
0160
016F
0172
0175
0177
0179
Ol7B
Ol7E
0180
0183
0186
0189
018C
018F
0191

20
A9
20
20
C9
FO
85
20
85
20
20
20
20
20
A5
60

IE
00
C8
37
00
19
80
37
81
IE
03
00
C3
IE
85

JSR
LOA
JSR
JSR
CHP
BEQ
STA
JSR
STA
JSR
JSR
JSR
JSR
JSR
LOA
RTS

$CFlE
#$00
$04C8
$0137
#$00
$0192
$80
S0137
$81
$CFlE
$DI03
$0600
$00C3
SCFIE
S85

0192
0195
0197

20 37 Dl
A4 82
99 44 02

01
CF
01
06
00
CF

buffer pointer
equal end pOinter?
no

$99,X

******************************

04
01

get byte from buffer

buffer pointer to -1
data byte
increment buffer pointer

0156
0159
015B
0150
0160
0162
0164
0167
0169

CF

get a byte from buffer
get buffer and channel number
end pointer

get byte and read next block
get byte from buffer
not last character?
save data byte
end pointer
yes
REAO-flag
data byte
change buffer and read next block
set buffer pointer to zero
get first byte from buffer
track number zero
yes, then last block
save last track number
get next byte
save as following track
change buffer and read next block
save drive number
param to disk controller
transmit read command
change buffer and read block
get data byte

JSR $D137
LOY $82
STA S0244,Y
157

get next byte from buffer
save as end pointer

Anatomy of the 1541 oisk Drive
LOA $85
D19A
AS 85
019C
60
RTS
******************************
20 F1 CF
JSR $CFFI
0190
DIAO
FO 01
BEQ $D1A3
D1A2
60
RTS

get data byte back

DIA3
DIA6
DIA9
DIAB
OIAE
DIBO
DlB3
DIB5
DIB8
OIBB
DIBE
DlCl
DlC3

get drive number
find free block in BAM

20
20
A9
20
AS
20
AS
20
20
20
20
A9
4C

D3
IE
00
C8
80
Fl
81
Fl
C7
IE
00
02
C8

D1
Fl
04
CF
CF
00
CF
06
D4

JSR
JSR
LDA
JSR
LDA
JSR
LDA
JSR
JSR
JSR
JSR
LOA
JMP

$DI03
$FllE
#$00
$D4C8
S80
SCFFl
S81
SCFFI
SDOC7
SCFlE
S0600
#$02
SD4C8

buffer pointer to zero
track number as first byte
sector number as second byte
write block
change buffer
param to disk controller
buffer pointer to 2

******************************
DIC6
85 6F
STA $6F
DICB
20 EB 04
JSR $04EB
DlCB
18
CLC
DICC
65 6F
ADC $6F
DICE
95 99
STA $99,X
DIDO
85 94
STA $94
DlD2
60
RTS
******************************

DID3
DID6
DID7
DIDA
DIDC
DIDE

20
AA
BD
29
85
60

93 DF
58 02
01
7F

JSR
TAX
LDA
AND
STA
RTS

3B
BO 01
18
08
85
20
20
85
A6
28
90
09
90
29

6F
27 02
7F D3
82
83
02
80
2B 02
3F

and increment

$025B,X
#SOl
$7F

isolate drive number
and save

SEC
BCS SOlE3
CLC
PHP
STA
JSR
JSR
STA
LOX
PLP
BCC
ORA
STA
ANO

get buffer pointer

get drive number
get drive number

******************************

DIE2
DIE3
DIE4
DIE6
DIE9
DIEC
DIEE
DIFO
DIFI
DIF3
DIF5
DIFB

increment buffer pointer

$DF93

******************************

DlDF
OlEO

byte in buffer and write blocl
byte in buffer
buffer full?

$6F
$0227
SD37F
S82
$83
SOIF5
#SBO
$022B,X
#S3F

158

find write channel and buffer
flag for writing
find read channel and buffer
flag for reading
save
bu ffer number
close channel
allocate free channel
channel number
secondary address
read channel?
flag for writing
set

Anatomy of the 1541 Disk Orive
OIFA
OlFB
OlFD
0200
0203
0206
0208
020A
0200
020F
0212
0214
0217
021A
021C
021E
0221
0223
0226

A8
A9
99
99
99
C6
30
20
10
20
A9
4C
99
C6
30
20
30
99
60

FF
A7
AE
CO
6F
lC
8E
08
5A
70
C8
A7
6F
08
8E
EC
AE

00
00
00
02
02
Cl
00
02
00

TAY
LOA
STA
STA
STA
OEC
BMI
JSR
BPL
JSR
LOA
J~IP

STA
OEC
BMI
JSR
BMI
STA
RTS

#SFF
$00A7,Y
$OOAE,Y
$OOCO,Y
$6F
$0226
$028E
$0217
$025A
*$70
$CIC8
$00A7,Y
$6F
$0226
$028E
$020F
$OOAE,Y

******************************

0227
0229
022B
0220

AS 83
C9 OF
00 01
60

LOA $83
CMP *$OF
BNE $022E
RTS

022E
0230
0233
0235
0237
0239
D23B
0230
0240
0242
0244
0246
D249
024B
0240
024E
D250
0251
0253
D256
0259

A6
BO
C9
FO
29
85
A9
90
A6
A9
95
20
A6
A9
CA
30
OA
00
00
80
60

LOX
LOA
CMP
BEO
ANO
STA
LOA
STA
LDX
LOA
STA
JSR
LOX
LOA
OEX
BMI
ASL
BNE
ORA
STA
RTS

83
2B 02
FF
22
3F
82
FF
2B 02
82
00
F2
5A 02
82
01
03
FA
56 02
56 02

$83
$022B,X
#$FF
$0259
#$3F
$82
#$FF
$022B ,X
$82
#$00
$F2,X
$D25A
$82
#$01
$0253
A
$0240
$0256
$0256

A6
B5
C9
FO
48
A9

82
A7
FF
09
FF

LOX
LDA
CMP
BEO
PHA
LDA

write in associated table
decrement buffer number
done already?
find buffer
found?
erase flags in table
70, 'no channel'
buffer number in table
buffer number
already done?
find buffer
not found?
buffer number in table
close channel
secondary address
IS?
no
else done already
channel number
not associated?
then done
channel number
erase association in table
erase REAO and WRITE flag
free buffer
channel number
set bit 0
shift to correct position
free in allocation register

******************************

025A
025C
025E
0260
D262
D263

default value

$82
$A7,X
#$FF
$D26B

free buffer
channel number
buffer number
not associated?

#$FF
159

Anatomy of the 1541 Disk Drive

0265
0267
0268
026B
026D
026F
0271
0273
0274
0276
0278
D279
027C
D27E
0280
D282
0284
0285
0287
D289
D28A
D28D

95
68
20
A6
B5
C9
FO
48
A9
95
68
20
A6
B5
C9
FO
48
A9
95
68
20
60

A7
F3 D2
82
AE
FF
09
FF
AE
F3 D2
82
CD
FF
09
FF
CD
F3 D2

STA
PLA
JSR
LDX
LOA
CMP
BEO
PHA
LDA
STA
PLA
JSR
LDX
LDA
CMP
BEO
PHA
LDA
STA
PLA
JSR
RTS

$A7,x

erase buffer association

$D2~'3

erase buffer allocation
channel number

$82
$AE,X
#$FF
$D27C

A2
89
3D
FO
CA

07
4F 02
E9 EF
04

LDX
LDA
AND
BEO
DEX

iste

associated in second table?
no

#$FF
$AE,X

erase association

$D2F3
$82
$CD,X
#$FF
$D28D

erase buffer in allocation reg.
channel number
associated in 3rd table?
no

#$FF
$CD,X

erase association

$D2F3

erase buffer in allocation reg

******************************
D28E
98
TYA
028F
48
PHA
0290
AO 01
LDY #$01
0292
20 BA D2
JSR $D2BA
10 DC
BPL $D2A3
D295
0297
DEY
88
D298
20 BA D2
JSR $D2BA
029B
10 06
BPL $D2A3
D29D
20 39 D3
JSR $0339
D2AO
AA
TAX
D2A1
30 13
BMI $D2B6
D2A3
LDA $OO,X
B5 00
D2A5
30 FC
BMI $D2A3
D2A7
LDA $7F
AS 7F
D2A9
95 00
STA $OO,X
D2AB
9D 5B 02
STA $025B,X
D2AE
8A
TXA
D2AF
OA
ASL A
D2BO
A8
TAY
D2B1
A9 02
LDA #$02
D2B3
99 99 00
STA S0099,y
D2B6
68
PLA
D2B7
TAY
A8
D2B8
8A
TXA
D2B9
60
RTS

D2BA
D2BC
D2BF
D2C2
D2C4

re~,

#$07
$024F,Y
$EFE9 ,Y
$D2C8

160

find buffer

erase bit

Anatomy of the 1541 oisk Drive
02C5
02C7

10 F5
60

BPL $D2BC
RTS

02C8
02CB
02CE
0201
0202
0203
0205
0206
0208
0209
020A
020C
020E
02EO
02El
02E2
02E4
02E5
02E7
02E9
02EB
02EO
02EE
02FO
02F2
02F3
02F5
02F6
02F7
02F9
02FC
02FF
0300
0302
0303
0304
0306

B9
50
99
8A
88
30
18
69

LOA
EOR
STA
TXA
OEY
BMI
CLC
AOC
TAX
RTS
LOX
LOA
BMI
TXA
CLC
AOC
TAX
LOA
BPL
CMP
BEQ
PHA
LOA
STA
PLA
ANO
TAY
INY
LOX
ROR
ROR
OEY
BNE
CLC
OEX
BPL
RTS

4F 02
E9 EF
4F 02
03
08

AA

60
A6
B5
30
8A
18
69
AA
B5
10
C9
FO
48
A9
95
68
29
A8
C8
A2
6E
6E
88
00
18
CA
10
60

82
A7
09
07
A7
FO
j,'F
EC
FF
A7
OF
10
50 02
4F' 02
01
F3

$024F,Y
$EFE9,X
$024F,Y

buffer number
$0208
*$08
buffer number
$82
$A7,X
$02E9
#$07
$A7,X
$0209
#$FF
$0209
*$FF
$A7,X
#$OF
buffer number
#$10
$0250
$024F

16
rotate 16-bit allocation reg.

S0303
erase bit for buffer
$02F9

******************************

0307
0309
030B
030E
0310
0312

A9
85
20
C6
00
60

OE
83
27 02
83
F9

LOA
STA
JSR
OEC
BNE
RTS

#$OE
$83
$0227
$83
$030B

******************************

0313
0315
0317
0319
D31C

A9
85
A6
BO
C9

OE
83
83
2B 02
FF

LOA
STA
LOX
LOA
CMP

rotate bit

#$OE
$83
$83
S022B,X
#$FF
161

close all channels
14
secondary address
close channel
next secondary address

close channels of other drives
14
secondary address
association table
channel associated?

Anatomy of the 1541 Disk Drive
D31E
D320
D322
D324
D327
D328
D32B
D32D
D32F
D331
D334
D336
D338

FO
29
85
20
AA
BD
29
C5
DO
20
C6
10
60

14
3F
82
93 DF
5B 02
01
7F
03
27 D2
83
DF

BEO
AND
STA
JSR
TAX
LDA
AND
CMP
BNE
JSR
DEC
BPL
RTS

$D334
#$3F
$82
$DF93

no
channel number
get buffer number

$025B,X
#$01
$7F
$D334
$D227
$83
$D317

******************************

D339
D33B
D33C
D33E
D340
0342
0344
D346
D348
D349
D34A
D34e
D34D
D34F
D351
D353
D355
D356
D358
D35A
D35C
D35E
D360
D362
D363
0365
D367
0369
036B
0360
036F
0371

A5
48
AO
B6
B5
10
C9
DO
8A
18
69
AA
B5
10
C9
DO
C8
CO
90
A2
DO
86
29
AA
B5
30
C9
90
A6
EO
90
BO

6F

0373
D375
0377
D37A
037B
0370
037E

A4 6F

00
FA
A7
04
FF
16
07
A7
04
FF
09
05
E4
n~

lC
6F
3F
00
FC
02
08
6F
07
07
E2

A9 FF
99 A7 00
68
85 6F
8A
60

LDA
PHA
LDY
LDX
LDA
BPL
CMP
BNE
TXA
CLC
ADC
TAX
LDA
BPL
CMP
BNE
INY
CPY
BCC
LDX
BNE
STX
ANO
TAX
LOA
BMI
CMP
Bee
LOX
epx
Bce
BeS
LOY
LOA
STA
PLA
STA
TXA
RTS

$6F
#$00
$FA,Y
$A7,X
$D348
#$FF
$D35E
#$07
$A7,X
$D355
#SFF
$D35E
#$05
SD33E
#SFF
$D37A
$6F
#$3F
SOD ,X
$0363
#$02
$0373
S6F
#$07
S0348
$0355
S6F
#SFF
$00A7,Y
SoF

162

drive number
isolate
equal to actual drive number
no
close channel
next channel

Anatomy of the 1541 Disk Drive

******************************
037F
AD 00
LOY #$00
0381
A9 01
LOA #$01
0383
BIT $0256
2C 56 02
D386
DO 09
BNE $0391
0388
C8
INY
0389
OA
ASL A
038A
DO F7
BNE $0383
D38C
A9 70
LOA #$70
038E
4C C8 C1
JMP $ClC8

0391
0393
0396
0399
039A

49 FF
20 56 02
80 56 02
98
60

EOR #$FF
AND $0256
STA $0256
TYA
RTS

find channel and allocate
set bit 0
channel free?
rotate bit to left
all channels checked?
70, 'no channel'
rotate bit model
erase bit
allocate channel

******************************
039B
20 EB DO
JSR $OOEB
JSR $ClOO
039E
20 00 Cl
03Al
20 AA 03
JSR $03AA
LOX $82
03A4
A6 82
BO 3E 02
03A6
LOA $023E,X
03A9
60
RTS

get byte for output
open channel for reading
turn LED on
get byte in output register
channel number
get byte

03AA
03AC
03AF
03Bl

A6
20
DO
4C

82
25 Dl
03
20 El

LOX
JSR
BNE
JMP

$82
$0125
$03B4
$E120

channel number
check file type
no reI-file?
get byte from reI-file

03B4
03B6
03B8
03BA
03BC
03BE
03CO
03C3
03C5
03C7
D3C9
03CB

A5
C9
FO
B5
29
DO
20
C9
00
A9
95
4C

83
OF
5A
F2
08
13
25 01
07
07
89
F2
OE 03

LOA
CMP
BEO
LOA
AND
ENE
JSR
CMP
BNE
LOA
STA
JMP

$83
#$01"
$0414
$F2,X
#$08
$0303
$0125
#$07
$03CE
#$89
$F2,X
$030E

secondary address
15
yes, r:ead error channel

03CE
0300
0302

A9 00
95 F2
60

LOA #$00
STA $F2,X
RTS

0303
0305
0307
030A
030C
030E
03EI

A5
FO
20
C9
90
20
B5

LOA
BEO
JSR
CMP
BCC
JSR
LDA

83
32
25 01
04
22
2F Dl
99

end flag set?
no
check file type
direct access file?
no
set REAO and WRITE flag

erase READ and WRITE flag

$83
$0409
$0125
#$04
$0400
$012F
$99,X

secondary address
zero, LOAD?
check file type
reI-file or direct access?
no
get buffer and channel number
buffer pointer
163

Anatomy of the 1541 Disk Drive
D3E3
D3E6
03E8
03EA
03EC
03EE
03FO
03F3
03F5
03FA
03FC
03FF

D9
DO
A9
95
F6
Al
99
B5
09
DO
A9
99
60

0400
D403
0405
0408

20 56 Dl
A6 82
9D 3E 02
60

0409
D40C
040E
0411

AO
FO
20
4C

0414
0417
D419
D4lB
D41D
D41F
0421
0423
0425
D428
042A
042D
042F
0431
0433
0436
0438
043A
043C
043F
0441
0443
D445
D447
D449
D44C

03~'8

44
04
00
99
99
99
3E
99
44
05
81
F2

02

02
02
00

CMP
BNE
LOA
STA
INC
LOA
STA
LOA
CMP
BNE
LOA
STA
RTS

$0244,Y
SD3EC
#$00
S99,X
S99,X
(S99,X)
S023E,y
S99,X
S0244,y
SD3FF
#S8l
SOOF2,Y

buffer pointer to zero
increment buffer pointer
get byte from buffer
into output register
buffer pointer
equal end pointer?
no
set flags

JSR $0156
LDX $82
STA $023E,X
RTS

get byte from buffer
channel number
byte in output register

54 02
F2
67 EO
03 04

LOA
BEO
JSR
JMP

$0254
$0400
$E067
SD403

flag for directory?
no
create directory line

20
C9
DO
AS
C9
DO
A9
85
20
A9
20
C6
A9
00

E8 04
D4
18
95
02
12
OD
85
23 Cl
00
Cl E6
AS
80
12

JSR
CMP
BNE
LDA
CMP
BNE
LDA
STA
JSR
LOA
JSR
OEC
LOA
BNE

SD4E8
#$D4
SD433
S95
#S02
SD433
#$00
S85
$C123
#$00
$E6Cl
$A5
#S80
$0445

set buffer pointer

20
85
00
A9
20
A9
95
A9
85
AS
80
60

37 01
85
09
04
C8 D4
02
9A
88
F7
85
43 02

JSR
STA
BNE
LOA
JSR
LDA
STA
LOA
STA
LOA
STA
RTS

$D137
$85
$0443
#SD4
SD4C8
#$02
S9A,X
#S88
SF7
S85
S0243

CR
in output register
erase error flags
create 'ok l message
set buffer pointer back
set REAO flag
get byte from buffer
into output register
set buf ptr in front of error ptr
hi-address
set READ flag
data byte
into output register

******************************

D440
0450

equal end pointer?
no

20 93 OF
OA

JSR SOF93
ASL A

164

read next block
get buffer number
times 2

Anatomy of the 1541 Disk orive

0451
0452
0454
0456
0458
045A
045C
045F

AA

A9
95
Al
FO
06
4C
60

00
99
99
05
99
56 01

TAX
LOA
STA
LOA
BEO
OEC
JMP
RTS

*$00
$99,X
($99,X)
$045F
$99,x
$0156

******************************

0460
0462

A9 80
00 02

LDA *$80
BNE $0466

buffer pointer to zero
get first byte from buffer
no block following?
buffer pointer to -1
read next block
read block
command code for reading

******************************
0464
A9 90
LOA #$90
0466
05 7F
ORA $7F
STA $0240
0468
80 40 02
046B
A5 F9
LOA $F9
0460
20 03 06
JSR $0603
0470
LOX $F9
A6 F9
JMP $0593
0472
4C 93 05

write block
command code for writing
drive number
save code

******************************
0475
LOA *$01
A9 01
0477
STA $024A
80 4A 02
047A
A9 11
LOA #$11
047C
STA $83
85 83
047E
20 46 OC
JSR $OC46
0481
A9 02
LOA #$02
JMP $D4C8
0483
4C C8 04

allocate buffer and read block

******************************

allocate new block
18
secondary address
allocate new block

D486
0488
048A

A9 12
85 83
4C DA DC

LDA #$12
STA $83
JMP $DCDA

******************************

D480
0490
0492
0494
D496
0497
0499
049B
049E
049F
04A1
D4A3
04A6
04A8
04AB
04AO
04BO
04B3

20 3B
A9 01
85 6F
A5 69
48
A9 03
85 69
20 20
68
85 69
A9 00
20 C8
A5 80
20 F1
A5 81
20 Fl
20 C7
20 99

DE

Fl

04
CF
CF
00
05

JSR
LOA
STA
LOA
PHA
LOA
STA
JSR
PLA
STA
LOA
JSR
LOA
JSR
LDA
JSR
JSR
JSR

$OE3B
#$01
$6F
$69

param to disk controller
execute command

file type to sequential
17
secondary address
allocate buffer and read block
buffer pointer to 2

write directory block
get track and sector number
a block
save step width 10 for block
allocation

*$03
$69
$F12D

find free block in BAM

$69
#$00
$D4C8
$80
$CFF1
$81
$CFFl
$00C7
$D599

get step width back
buffer pointer to zero
track number in buffer
sector number in buffer
wri te block to disk
and verify
165

Anatomy of the 1541 Oisk Orive
04B6
04B8
D4BB
D4BE
D4CO
04C3
D4C5

A9
20
20
00
20
A9
4C

00
C8
FI
FB
FI
FF
FI

04
CF
CF
CF

LOA
JSR
JSR
BNE
JSR
LOA
JMP

HOO
$04C8
$CFFI
$D4BB
$CFFI
*$FF
$CFFI

buffer pointer to zero
fill buffer with zeroes
zero as following track
$FF as number of bytes

******************************
04CB
85 6F
STA $6F
D4CA
20 93 OF
JSR $OF93
04CO
OA
ASL A
04CE
AA
TAX
04CF
B5 9A
LOA $9A,X
04Dl
85 95
STA $95
04D3
A5 6F
LDA $6F
0405
95 99
STA $99,X
D4D7
85 94
STA $94
04D9
60
RTS

set buffer pointer
save pointer
get buffer number
times 2

******************************
D4DA
A9 11
LOA #$11
04DC
85 83
STA $83
20 27 02
D40E
JSR $0227
A9 12
04El
LOA #$12
04E3
85 83
STA $83
04E5
4C 27 02
JMP $0227

close internal channel
17

******************************

set buffer pointer
get buffer number

04E8
04EB
04EC
04ED
04EF
04Fl
04F3
D4F5

20
OA
AA
B5
85
B5
85
60

93 OF
9A
95
99
94

JSR
ASL
TAX
LDA
STA
LOA
STA
RTS

$OF93
A
$9A,X
$95
$99,X
$94

85
20
AA
BO
85
AO
Bl
60

71
93 OF
EO FE
72

00
71

STA
JSR
TAX
LOA
STA
LOY
LDA
RTS

BO
29
00
A8
86
8A

5B 02
01
40 02
F9

LOA
ANO
ORA
PHA
STX
TXA

close channel
18
close channel

buffer pointer 10

$71
$OF93
$FEEO,X
$72
#$00
($7l),Y

******************************

0506
0509
D50B
050E
050F
D511

buffer pointer 10, new value

buffer pointer hi

******************************

04F6
D4F8
04FB
04FC
04FF
0501
0503
0505

buffer pointer hi

$025B,X
#$01
$0240
$F9

166

get byte from buffer
pointer 10
get buffer number
hi-byte buffer address
pointer hi
get byte from buffer
check track and sector numbers
command code for disk controller
drive number
plus command code
save
buffer number

Anatomy of the 1541 Disk Drive
0512
D513
OS14
0516
OS19
DSIB
oSlo
D520
0522
D523
D524
D525
D527
D529
D52B
D52C
D520
D52E
D530
D533
D535
D538
D53A
D53D
D53F
D540
D543
D546
D548
054A
0540
D54F

OA
AA

BS
80
BS
FO
CD
BO

07
40 02
06
20
07 FE
28

AA

68
48
29
C9
DO
68
48
4A
BO
AD
90
AD
FO
CO
DO
8A
20
CD
FO
BO
20
A9
4C

FO
90
4F

05
01 01
03
02 01
05
D5 FE
33
4B
40
02
30
52
66
45

F2
02
05
E6

ASL
TAX
LOA
STA
LOA
BEO
CMP
BCS
TAX
PLA
PHA
AND
CMP
BNE
PLA
PHA
LSR
BCS
LOA
BCC
LOA
BEO
CMP
BNE
TXA
JSR
CMP
BEO
BCS
JSR
LDA
,TMP

A

times 2

$ 07 ,X
$0240
$06,X
$oS4A
$FE07
$oS4A

sector
save
track
66, , illegal track or sector'
36, highest track number + 1
66, , illegal track or sector'
command code

lI$FO
#$90
$DS7A

code for writing?
no

A

$OS35
$0101
$OS38
$0102
$053F
$FED5
$0572

IAI, format marker
73, 'cbm dos v2.6 1541'
track number
get maximum sector number
compare with sector number
equal, then error
smaller?
get track and sector number

$F24B
$0240
$D54A
$057A
$0552
#S66
$E645

66, 'illegal track or sector'

******************************

D552
D554
0555
D5S6
0558
OSSA
055C
055E

A5
OA
AA
B5
85
B5
85
60

F9

055F
D561
0563
D566
0568
056R
OS60
056F
0571

A5
FO
Co
BO
20
C5
FO
90
60

0572
0575

20 52 D5
A9 73

06
80
07
81
80
EA
07 FE
E5
4B F2
81
OE
DC

LOA
ASL
TAX
LOA
STA
LOA
STA
RTS

$F9
A

LOA
BEO
CMP
BCS
JSR
CMP
BEO
BCC
RTS

$80
$0540
$FED7
$054D
$F24B
$81
S054D
$054D

S06,X
$80
$07,X
$81

get track and sector number
buffer number
*2
as index
track
sector
track
zero, then error
36, maximum track number + 1
66, 'illegal track or sector'
get maximum sector number
sector
error

JSR S0552
LDA #$73

get track and sector numbet

167

Anatomy of the 1541 Disk Drive

D577

4C 45 E6

JMP $E645

D57A
D57C
D57D
D580
D582
D585

A6
68
8D
95
9D
60

LDX
PLA
STA
STA
STA
RTS

F9
4D 02
00
5B 02

73, 'cbm dos v2.6 1541'

$F9

buffer number

$024D
$OO,X
$025B,X

command code for disk controller
in command register
and write in table

******************************
A9 80
LDA #$80
D586
D588
DO 02
BNE $D58C

read block
code for read

******************************

write block
code for write
drive number
buffer number

D58A
D58C
D58E
D590
D593
D596

A9
05
A6
8D
AD
20

90
7F
F9
4D 02
4D 02
OE D5

LDA
ORA
LDX
STA
LDA
JSR

#$90
$7F
$F9
$024D
$024D
$D50E

command code
check track and sector

******************************
D599
20 A6 D5
JSR $D5A6
D59C
BO FB
BCS $D599
48
D59E
PHA
A9 00
D59F
LDA #$00
D5Al
8D 98 02
STA $0298
68
D5A4
PLA
60
D5A5
RTS

verify execution
verify execution
wait for end

D5A6
D5A8
D5AA
D5AC
D5AE
D5BO
D5B2
D5B4
D586
D5B8
D5BA
DSBD
D5BF
D5C2
D5C3

B5
30
C9
90
C9
Fa
C9
Fa
C9
DO
2C
30
4C
18
60

cmd code (bit 7) still in reg?
yes

D5C4
D5C5

38
60

SEC
RTS

D5C6
D5C7
D5C8
D5CA
05CB

98
48

TYA
PHA
LOA $71"
PHA
LDA $025B,X

00
1A
02
14
08
08
08
04
OF
OC
98 02
03
3F D6

7F
48
BO 58 02

AS

LDA
BMI
CMP
BCC
CMF
BEO
CMP
BEO
CMF
BNE
BIT
BMI
JMP
CLC
RTS

$OO,X
SD5C4
#$02
$D5C2
#$08
$D5BA
#$OB
$D5BA
#SOF
$D5C6
$0298
$DSC2
SD63F

erase error flag

error-free execution
8
write protect
11
ID mismatch
15

create error message
execution ended
execution not yet ended

168

drive number

Anatomy of the 1541 Disk Drive

D5CE
D5DO
D5D2
D5D3
D5D6
D5D9
D5DC
D5DE
D5EO
D5E3
D5E6
D5E8
D5E9
D5EB
D5ED
D5EF
D5Fl
D5F4
D5F6
D5F8
D5FA
D5FD
D600
D603
D606
D607
D60A
D60D
D6l0
D6l3
D616
D6l9
D6lB
D6lD
D620
D623
D625
D628
062B
D62D
062F
0631
D633
0635
D636
D638
063A
D63C
063F
0641
D644
0645
D648
D64A
064B

29
85
A8
B9
8D
20
C9
BO
4C
BD
29
48
C9
DO
A5
09
9D
24
70
A9
8D
8D
AC
AD
38
F9
8D
B9
20
EE
20
C9
90
AC
B9
DO
AO
20
B5
C9
90
24
10
68
C9
DO
05
90
85
20
68
2C
30
48
A9

01
7F
CA
6D
A6
02
03
6D
5B
FO
90
07
7F
B8
5B
6A
39
00
99
9A
99
9A

FE
02
D6
D6
02

02

02
02
02
02

DB
9A
DB
76
99

FE
02
FE
D6
02
A6 D6
02
08
99 02
DB FE
DB
9A 02
76 D6
00
02
2B
6A
OF
90
05
7F
5B 02
00
OA E6
98 02
23
CO

AND
STA
TAY
LDA
STA
JSR
CMP
BCS
JMP
LDA
AND
PHA
CMP
BNE
LDA
ORA
STA
BIT
BVS
LDA
STA
STA
LDY
LDA
SEC
SBC
STA
LDA
JSR
INC
JSR
CMP
BCC
LOY
LOA
BNE
LDA
JSR
LDA
CMP
BCC
BIT
BPL
PLA
CMP
BNE
ORA
STA
LDA
JSF
PLA
BIT
BMI
PHA
LOA

#$01
$7F

drive number

$FECA,Y
$026D
$D6A6
#$02
$D5E3
$D66D
$025B,X
#$FO

bit roodel for drive
read attempt
not ok?
done
command code
isolate

#$90
$D5F4
$7F
#$B8
$025B,X
$6A
$D63l
#$00
S0299
S029A
$0299
S029A

code for write
no
drive number

$FEDB,Y
$029A
$FEDB,Y
$D676
$0299
$D6A6
#$02
$D625
$0299
$FEDB,Y
$0600
$029A
$D676
$OO,X
#$02
$D65C
S6A
SD644

constants for read atteropts

#S90
SD63F
S7F
S025B,X
SOO,X
SE60A

cntr for searches next to track
counter

position head next to track
increment counter
read ateropt
return message
smaller than 2, ok?
load counter
get constants
not yet zero (table end )?
position head
return message
ok?
command code
for writing?
no
drive number
command code in table
return message
set error message

$0298
$D66D
#SCO

command code for head positioning
169

Anatomy of the 1541 Disk Orive
0640
064F
0651
0653
0655
0658
065A
065C
0650
065F
0661
0663
0666
0669
066B
0660
066E
0670
0671
0672
0674
0675

05
95
B5
30
20
C9
BO
68
C9
00
05
90
20
C9
BO
68
85
68
A8
B5
18
60

7F
00
00
FC
A6 06
02
09

0676
0678
067A
067C
067E
0681
0682
0684
0686

C9
FO
30
AO
20
38
E9
00
FO

00
18
OC
01
93 D6

0688
068A
0680
068E
0690
0692

AO
20
18
69
00
60

FF
93 06

0693
0694
0695
0697
069A
069D
069F
06A1
06A4
06A5

48
98
99
09
FO
A9
99
68
60

D6A6
06A8
D6AA
D6AB

A5 6A
29 3F
A8
AD 60 02

A4

90
OC
7F
5B 02
A6 D6
02
02
7F
00

01
F6
OA

01
F6

7F
F'E 02
FE 02
FB
00
FE 02

ORA
STA
LOA
BM!
JSR
CMP
RCS
PLA
CMP
RNE
ORA
STA
JSR
CMP
BCS
PLA
STA
PLA
TAY
LOA
CLC
RTS
CMP
BEO
BM!
LOY
JSR
SEC
SBC
BNE
BEO
LOY
JSR
CLC
AOC
BNE
RTS
PHA
TYA
LOY
STA
CMP
REO
LOA
STA
PLA
RTS

$7F
$OO,X
$OO,X
S0651
$06A6
#$02
$0635

drive number
in command registe~

#$90
$066D
$7F
$025B,X
$06A6
#$02
$063F

command code for writing
no
drive number
in table
attempt execution again
return message
error?

$7F

get drive number back

$OO,X

error code
end-of-execution flag

wait for execution
attempt command execution agair
return message
incorrect?

#$00
$0692
$0688
#$01
S0693

transmit data for head position

#$01
S067C
$0692
#SFF
S0693

transmit data for head position

#SOl
SD688

S7F
$02FE,Y
$02FE,Y
$069A
#$00
$02FE,Y

LOA $6A
ANO #S3F
TAY
LOA $026D

drive number
wait for r-eturn message from
disk contr-011er

maximum number of repetitions
bit for LED
170

Anatomy of the 1541 Disk Drive

D6AE
D6Bl
D6B4
D6B7
D6B9
D6BB
D6BD
D6BF
D6Cl
D6C2
D6C4
D6C5
D6C8
D6CB
D6CE
D6CF

4D
8D
BD
95
B5
30
C9
90
88
DO
48
AD
OD
8D
68
60

ODIC
ODIC
5B 02
00
00
FC
02
03
E7
6D 02
ODIC
ODIC

EOR
STA
LDA
STA
LDA
BMI
CMP
BCC
DEY
BNE
PHA
LDA
ORA
STA
PLA
RTS

$lCOO
$lCOO
$025B,X
$OO,X
$OO,X
$D6B9
#$02
$D6C4
$D6AB
$026D
$lCOO
$lCOO

command
transmit to disk controller
and return message
wait
ok?
yes
decrement counter
attempt again
LED off

******************************
20 93 DF
JSR $DF93
D6DO
ASL A
D6D3
OA
A8
TAY
D6D4
A5 80
LDA $80
D6D5
99 06 00
STA $0006,Y
D6D7
A5 81
LDA $81
D6DA
99 07 00
STA $0007,Y
D6DC
D6DF
A5 7F
LDA $7F
D6El
OA
ASL
D6E2
TAX
AA
60
RTS
D6E3

transmit param to disk controller
get buffer number

******************************

$83

enter file in directory
secondary address

$82

channel number

$81

sector number

$80

track number
save

D6E4
D6E6
D6E7
D6E9
D6EA
D6EC
D6ED
D6EF
D6FO
D6F2
D6F4
D6F7
D6FA
D6FB
D6FD
D6FF
D701
D703
D706
D707
D709
D70B
D70E
D711

A5
48
A5
48
A5
48
A5
48
A9
85
20
AD
48
A4
29
85
A6
5D
4A
90
A2
8E
20
FO

83
82
81
80
11
83
3B DE
4A 02
E2
01
7F
F9
5B 02
OC
01
92 02
AC C5
lD

LDA
PHA
LDA
PHA
LDA
PHA
LDA
PHA
LDA
STA
JSR
LDA
PHA
LDA
AND
STA
LDX
EOR
LSR
Bce
LDX
STX
JSR
BEO

#$11
$83
$DE3B
$024A
$E2
#$01
$7F
$F9
$025B,X
A
$D715
#$01
$0292
$C5AC
$D730
171

track number
transmit
sector number
transmit
drive number
times 2

secondary address 17
get track and sector number
file type
save
drive number
set
buffer number
equal drive number?
pointer in directory
load dir and find first entry
not found?

Anatomy of the 1541 Disk Drive

0713

00 28

BNE $0730

found?

0715
0718
071A
07lC
D7lE
0720
0723

AO
FO
C5
FO
85
20
4C

91 02
OC
81
IF
81
60 04
30 07

LOA
BEO
CMP
BEO
STA
JSR
JMP

$0291
$0726
$81
$0730
$81
S0460
$0730

sector number in directory
equal zero
equal sector number?
yes
save sector number
read block

0726
0728
072B
D72E
0730
0733
0735
0738
073A
0730
0740
0743
0744
0747
0749
074B
0740
0750
0751
0754
0757
0758
075B
075E
0761
0762
0765
0766
0768
076B
076D
076F
0771
D772
0774
0776
0779
077B
0770
077F
0782
0784
0785
0788
078A

A9
80
20
DO
20
A5
80

01

LOA
STA
JSR
BNE
JSR
LOA
STA
LOA
STA
LOA
JSR
PLA
STA
CMP
BNE
ORA
JSR
PLA
STA
JSR
PLA
STA
JSR
JSR
TAY
LOA
TAX
LOA
JSR
LOY
LOA
STA
INY
CPY
BCC
LDA
CMP
BNE
LDY
LOA
STA
INY
LDA
STA
INY

lI$Ol
$0292
$C617
$0730
$0480
$81
$0291
lIS02
$0292
$0292
$04C8

A9

80
AD
20
68
80
C9
00
09
20
68
80
20
68
80
20
20

92 02

17
00
80
81
91
02
92
92
C8

C6
04
02
02
02
04

4A 02
04
02
80
Fl CF
80 02
FI CF
85 02
Fl CF
93 OF

AS

AO
AA
A9
20
AO
A9
91
C8
CO
90
AO
C9
00
AO
AD
91
C8
AD
91
C8

7A 02
10
6E C6
10
00
94
IB
F9
4A 02
04
13
10
59 02
94
5A 02
94

pointer to one
find next entry in directory
found?
write directory block
sector number
pointer to 2
set buffer pointer

$024A
#$04
$0740
#$80
$CFFI

file type
reI-file?
no
set bit 7
and write in buffer

$0280
$CFFI

following track
in buffer

$0285
$CFFI
$OF93

following sector
in buffer
get buffer number

$027A

pointer to dr i ve numbe r

#$10
$C66E
#$10
#$00
(S94),Y

16, length of filename
write filename in buffer

#$lB

position 27 already?
no
file type
reI-file
no

$076F
$024A
#$04
$0790
#$10
$0259
($94) ,Y
S025A
(S94) , Y

172

fill with zeroes at pos 16

track
and sector
the side-sectors in dir entry

Anatomy of the 1541 Disk Drive
D78B
D78E
D790
D793
D794
D796
D797
D798
D79A
D79D
D79F
D7A2
D7A5
D7A7
D7AA
D7AD
D7AF
D7Bl
D7B3

AD
91
20
68
85
AA
68
85
AD
85
9D
AD
85
9D
AD
85
A5
85
60

58 02
94
64 D4
82
83
91
D8
60
92
DD
66
4A
E7
7F
E2

02
02
02
02
02

LOA
STA
JSR
PLA
STA
TAX
PLA
STA
LDA
STA
STA
LDA
STA
STA
LDA
STA
LDA
STA
RTS

$0258
(S94) ,Y
$D464

record length
in directory
write block

$82

channel number

$83
$0291
$D8
$0260,X
$0292
SDD
$0266,X
$024A
$E7
$7F
SE2

secondary address

******************************
D7B4
A5 83
LDA S83
D7B6
8D 4C 02
STA S024C
D7B9
20 B3 C2
JSR SC283
D7BC
8E 2A 02
STX S022A
D7BF
AE 00 02
LDX S0200
D7C2
AD 4C 02
LDA S024C
D7C5
DO 2C
BNE SD7F3
D7C7
EO 2A
CPX ltS2A
D7C9
DO 28
fiNE $D7n
D7CB
A5 7E
LDA S7E
D7CD
FO 4D
BEO $08lC
07CF
85 80
STA $80
D7Dl
AD 6E 02
LDA S026E
D7D4
85 7F
STA S7F
07D6
85 E2
STA $E2
D7D8
A9 02
LDA #$02
D7DA
85 E7
STA $E7
D7DC
AD 6F 02
LDA S026F
D7DF
85 81
STA S8l
D7El
20 00 Cl
JSR $CIOO
D7E4
JSR SDC46
20 46 DC
D7E7
A9 04
LDA #$04
D7B9
05 7F
ORA S7F
D7EB
A6 82
LDX S82
D7ED
99 EC 00
STA $OOEC,Y
D7FO
4C 94 Cl
JMP $C194

D7F3
D7F5
D7F7
D7FA
D7FC

EO
DO
AD
DO
4C

24
IE
4C 02
03
55 DA

D7FF

20 Dl Cl

CPX
BNE
LDA
BNE
JMP

file type
drive number

OPEN command, secondary adr
secondary address
get line length, erase flags
first character from buffer
secondary address
not equal 0 (LOAD)?

'* ,

last track number
track number
last drive number
drive number
set data type to program
last sector number
sector
turn LBD on
allocate buffer, read block
file type
drive number
channel number
set flag
done
'$ ,
no
secondary address
not equal to zero?
OPEN S

*$ 24
$0815
S024C
SD7FF
$OA55

JSR SCIDI

analyze line to end
173

<>

15

Anatomy of the 1541 Disk Drive
0802
0809
080B
080E
0810
0812

AD
85
A9
85
20
AS
09
4C

0815
D817
0819

EO 23
DO 12
4C 84 CB

CPX #$23
BNE $082R
JMP $CB84

08lC
08lE
D821
0823
0825
0828
082B
082E
0830
0832
D834
D835
0837
0839

A9
80
A9
85
80
20
20
DO
A2
FO
8A
FO
A9
4C

LOA
STA
LOA
STA
STA
JSR
JSR
BNE
LOX
BEO
TXA
REO
LOA
JMP

083C
D830
083f'
0840
0843
0845
0848
0849
084C
D84F
D852
0855
0857
D85A
D85D
D860
0861
0864
D866
0869
086A
0860
086F
087l
0873
D876
0879

88
FO
88
8C
A9
20
E8
8E
20
20
20
A2
8E
8E
8E
E8
EC
BO
20
Ell
EC
BO
CO
FO
20
AE
86

0805
0807

85 FE
80
00
81
46 DC
7F
02
EB 07

02
96
00
7F
8E
42
E5
04
00
OC

02
02
DO

Cl

05
30
C8 Cl
01
7A 02
80
68 C2
78
12
CA
9D
00
58
97
4A

02
C3
C3
C4
02
02
02

77 02

10
09 DA
77 02
07
04
3E
09 DA
4C 02
83

LOA
STA
LOA
STA
JSR
LOA
ORA
J~lP

DEY
BEO
OEY
STY
LOA
JSR
INX
STX
JSR
JSR
JSR
LDX
STX
STX
STX
INX
CPX
BCS
JSR
INX
CPX
BCS
CPY
REO
JSR
LOX
STX

$FE85
$80
#$00
$81
$OC46
$7F
#$02
$07EB

18, directory track
track
sector 0
allocate buffer, read block
drive number
continue as above
'# '
open direct access file

#$02
$0296
#$00
$7F
$028E
$0042
$CIE5
$0834
#$00
$0840

file type program
drive 0
load BAM
analyze line
colon found?
comma found?
no

$083C
#$30
$C1C8

30, 'syntax error'

$0840
$027A
#$80
$C268

pointer to drive number
shift CR
analyze line to end

$0278
$C312
$C3CA
$C49D
#$00
$0258
$0297
$024A

comma counter
get drive number
check drive number
find file entry in directory
default values
record length

$0277
$0876
$DA09

comma before equal sign?
no
get file type and control mode

$0277
$0876
*$04
S08Bl
$OA09
$024C
$83

additional comma?
no

file type

get file type and control method
secondary address
174

Anatomy of the 1541 Disk Drive
D87B
D87D
D87F
D882
D884
D887
D88A
D88C
D88E
D891
D894
D896
D898
D89A
D89D
DBAO
D8A2
DBA4
DBA7
DBAA
DBAC
DBAE

EO
BO
BE
A9
8D
AD
DO
A9
8D
AD
DO
AS
29
80
AD
DO
A9
BD
AD
C9
FO
4C

02
12
97
40
F9
4A
IB
02
4A
4A
11
E7
07
4A
80
05
01
4A
97
01
18
40

DBBI
D8B4
D8B7
DBBA
DBBD
DBBF
DBCl
D8C4

BC
B9
BD
AD
DO
A9
BD
DO

7A
00
5B
80
B7
01
97
BO

D8C6
DBC8
D8CA
D8CR
DB CD
D8CF
D8Dl
D8D3
D8D6

AS
29
AA
DO
A9
24
FO
20
4C

E7
80

D8D9
D8DC
D8DE
D8El
D8E4
D8E6
D8E8
D8E9
D8EB
DBED
DBFO
D8F2

A9
DO
4C
AD
C9
FO
8A
DO
A9
4C
A9
4C

80 02
03
E3 D9
00 02
40
00

02
02
02
02
02

02
02
02
02
D9
02
02
02
02
02

14
20
E7
06
B6 C8
E3 D9

05
63
C8 CI
33
CB CI

CPX
BCS
STX
LDA
STA
LDA
BNE
LDA
STA
LDA
BNE
LDA
AND
STA
LDA
BNE
LDA
STA
LDA
CMP
BEO
JMP

#$02
$DB91
$0297
#$40
$02F9
$024A
$D8A7
#$02
$024A
$024A
$D8A7
$E7
#$07
$024A
$02BO
$DBA7
#$01
$024A
$0297
#$01
$D8C6
$0940

LDY
LDA
STA
LDA
RNE
LOA
STA
BNE

$027A,X
$0200,Y
$025B
$02BO
$DB76
#$01
$0297
$DR76

pointer behind second comma
get value
record length
track number

LOA
AND
TAX
BNE
LDA
BIT
BEO
JSR
JMP

$E7
#$80

file type
isolate wildcard flag

$D8El
#$20
$E7
$D8D9
$C8B6
$D9E3

wildcard in name

LOA
BNE
JMP
LDA
CMP
BEO
TXA
BNE
LDA
JMP
LDA
JMP

$0280
$D8El
$D9E3
$0200
#$40
$D8FS

greater than 2?
yes
o or 1 (LOAD or SAVE)
file type
not deleted
PRG
-as file type

get file type and command line
track number
not equal zero?
file type sequential
control method

'w'
yes

'w'
as control method

was file closed?
yes
byte 0 in buffer and write block
track number of the first block
already existing
first character from input buffer
I@ I?

yes

$DBFO
#$63
$CICB
#$33
$CIC8

wildcard set?
63, 'file exists'
33, 'syntax error'

175

Anatomy of the 1541 oisk Orive
******************************
08F5
AS E7
LOA $E7
08F7
29 07
ANO *$07
08F9
CO 4A' 02
CMP $024A
08FC
DO 67
BNE $0965
08FE
C9 04
CMP 1t$04
0900
FO 63
BEO $0965
0902
20 OA DC
JSR $OCDA
AS 82
0905
LOA $82
0907
8D 70 02
STA $0270
D90A
A9 11
LDA *$11
20 EB DO
D90C
JSR $DOEB
AD 94 02
D911
LDA $0294
0914
20 C8 04
JSR $04C8
0917
AO 00
LOY *$00
0919
Bl 94
LDA ($94),Y
09lB
09 20
ORA *$20
0910
91 94
STA (S94),Y
091F
AD 1A
LOY lI$lA
0921
AS 80
LOA $80
0923
91 94
STA ($94) ,Y
092S
C8
INY
0926
A5 81
LOA $81
0928
STA ($94), Y
91 94
092A
AE 70 02
LOX S0270
0920
AS 08
LDA $08
092F
STA $0260,X
90 60 02
0932
AS 00
LOA $00
0934
90 66 02
STA S0266,X
0937
20 3B OE
JSR $DE3B
093A
20 64 04
JSR $D464
0930
4C EF 09
JMP $D9EF
0940
0943
0945
0947
094A
094D
094F
0951
0953
0955
0957
0959
D95C
095E
0960
D963
D965
D967
D96A
D96C
D96F
D972

AO
00
A9
4C
AD
C9
FO
A9
24
FO
A9
4C
AS
29
CD
FO
A9
4C
AO
8C
AE
EO

80
OS
62
C8
97
03
OB
20
E7
05
60
C8
E7
07
4A
05
64
C8
00
79
97
02

02
Cl
02

C1
02
Cl
02
02

LOA
BNE
LOA
JMP
LOA
CMP
BEO
LOA
HIT
BEO
LOA
JMP
LDA
AND
C~IP

BEO
LOA
JMP
LOY
STY
LDX
CPX

$0280
S094A
*$62
$ClC8
$0297
#$03
$D9SC
#$20
$E7
S09SC
#$60
i$ClC8
SE7
#$07
$024A
$096A
i$64
SClC8
#SOO
$0279
S0297
#$02

open a file with overwriting
file type
isolate
file type different?
reI-file?
64, , file type mismatch'
save channel number
open read channel
set buffer pointer for directory
file type
set bit S, open file
track
and sector
for open with at-sign
channel number
pointer to directory block
get track and sector number
write block
prepare trk, sector, and drive II
first track number
file not erased?
62, , file not found'
control mode

'M'

yes,then no test of unclosed fill
bit S
test in file type
not set, ok
60, 'write file open',
isolate file type

64, 'file type mismatch'
control mode
IAI, append
176

Anatomy of the 1541 Disk Drive
D974
D976
D978
D97A
D97C
D97E
D980
D982
D983
D985
D987
D98A
D98D
D98E
D990
D993
D996
D998
D99A
D99D

DO
C9
FO
Bl
29
91
A5
48
A9
85
20
20
68
85
20
AD
C9
DO
20
4C

D9AO
D9A2
D9A4
D9A7
D9A8
D9AA
D9AD
D9AE
D9BO
D9B3
D9B6
D9B7
D9B9
D9BC
D9BE
D9CO
D9C3
D9C6
D9C9
D9CB
D9CE
D9DO
D9D3
D9D5
D9D8
D9DA
D9DD
D9DF
D9E2

AO
Bl
8D
C8
Bl
8D
C8
Bl
AE
8D
8A
FO
CD
FO
A9
20
AE
BD
85
BD
85
20
A4
AE
B5
99
B5
99
60

D9E3
D9E5
D9F7
D9E9

A5
29
85
20

lA
04
EB
94
4F
94
83
11
83
3B DE
64 D4
83
AO
97
02
55
2A
94

D9
02
DA
Cl

13

94
59 02
94
5A 02
94
58 02
58 02
OA
58
05
50
C8
79
80
80
85
81
46
82
79
D8
60
DD
66

02
C1
02
02
02
DC
02
02
02

E2
01
7F
DA DC

BNE
CMP
BEQ
LDA
AND
STA
LDA
PHA
LDA
STA
JSR
JSR
PLA
STA
JSR
LDA
CMP
BNE
JSR
JMP
LDA
LDA
STA
INY
LDA
STA
INY
LDA
LDX
STA
TXA
BEO
CMP
BEQ
LDA
JSR
LDX
LDA
STA
LDA
STA
JSR
LDY
LDX
LDA
STA
LDA
STA
RTS
LDA
AND
STA
JSR

$D990
#$04
$D965
($94), Y
#$4F
($94), Y
$83
.$11
$83
$DE3B
$D464

no
reI-file?

channel 17
get track and sector number
write block

$83
SD9AO
$0297
#$02
$D9EF
$DA2A
$C194

get channel • back
control Illode

done

.$13
($94), Y
$0259

track

($94),Y
$025A
(S94), Y
$0258
$0258
SD9C3
.$0258
$D9C3
#$50
$CIC8
$0279
$0280,X
$80
$0285,X
$81
$DC46
$82
$0279
$D8,X
$0260,Y
$DD,X
$0266,Y
$E2
#$01
$7E'
SDCDA

record length
last record len

50, 'record not present'
track
sector

drive #

177

Anatomy of the 1541 Disk Drive
D9EC
D9EF
D9Fl
D9F3
D9F5
D9F8
D9FA
D9FC
D9FE
DAOI
DA03
DA06

20
A5
C9
BO
20
A5
85
A5
8D
A5
8D
4C

E4
83
02
11
3E
80
7E
7F
6E
81
6F
99

D6

DE

02
02
Cl

JSR
LDA
CMP
BCS
JSR
LDA
STA
LDA
STA
LDA
STA
JMP

$D6E4
$83
#$02
$DA06
$DE3E
$80
$7E
$7F
$026E
$81
$026F
$C199

channel #

******************************

DA09
DAOC
DAOF
DAll
DA12
DA14
DAl7
DA19
DAlC
DAlE
DAIF
DA2l
DA24
DA26
DA29

BC
B9
AO
88
30
D9
DO
BC
AO
88
30
D9
DO
8C
60

7A 02
00 02
04
08
B2 FE
F8
97 02
05
08
86 FE
F8
4A 02

LDY $027A,X
LDA $0200,Y
LDY #$04
DEY
BMI $DAIC
01P $FEB2,Y
BNE $DAll
STY $0297
LDY #$05
DEY
BMI $DA29
CMP $FEB6,Y
BNE $DAlE
STY $024A
RTS

******************************

DA2A
DA2D
DA2F
DA32
DA34
DA37
DA39
DA3A
DA3B
DA3D
DA40
DA42
DA45
DM7
OA49
OMB
OA40
OMF
DA5l
OA54

20
A9
20
FO
20
A6
E8
8A
DO
20
A9
20
A6
A9
95
A9
05
A6
90
60

39 CA
80
A6 DO
F6
95 OE
81
05
A3 01
02
C8 D4
82
01
F2
80
82
83
2B 02

JSR
LOA
JSR
BEQ
JSR
LDX
INX
TXA
BNE
JSR
LDA
JSR
LDX
LOA
STA
LDA
ORA
LOX
STA
RTS

$CA39
#$80
$DDA6
$DA 2A
SDE95
S8l

A9 OC
80 2A 02

control modes

• R I,

I

WI,

'AI,

$0A42
$DIA3
#$02
$D4C8
$82
#$01
$F2,X
#S80
$82
$83
S022B,X

LOA #SOC
STA $022A
178

I ~

save

file types ID' ,'S' ,'pi ,lUI ,'L I
save
preparation for Append
open channel to read, get byte
last byte?
no
get track and sector number
sector number

******************************

DA55
OA57

check file type and control mOl
pointer in command line
get characters from line

not $FF?
close buffer, write block
buffer pointer to 2
channel number
set flag for WRITE

channel number in table
OPEN U$"
command number 12

Anatomy of the 1541 Disk Drive
DA5A
DA5C
DA5F
DA60
DA62

DM3
DM5
DA68

DMB
DA6D
DA6F
DA72
DA75
DA78
DA7A
DA7C
DA7E
DAB 1

DA84
DA86
DAB9
DA8B
DA8E
DA90
DA91
DA92
DA95
DA98
DA9B
DA9E
DAAl
DAA4
DAA7
DAAA

DAAD
DAM'
DAB2
DAB4
DAB7
DAB9
DABB
DABD
DABF

A9
AE
CA
FO
CA
DO
AD
20
30
85
EE
EE
EE
A9
85
A9
BD
BD
DO
20
DO
20
AO
88
88
BC
20
20
20
20
20
20
20
20
A6
9D
A4
8D
09
95
A9
85
60

00
74 02
OB
21
01
BD
19
E2
77
78
7A
80
E7
2A
00
01
lB
E5
05
DC
03
7A
00
98
20
CA
B7
9D
9E
37
82
3E
7F
8E
04
EC
00
A3

02
C3
02
02
02

02
02
Cl
C2

02
C2
C3
C3
C3
C7
C4
EC
Dl
02
02

LDA
LDX
DEX
BEO
DEX
BNE
LDA
JSR
BMI
STA
INC
INC
INC
LDA
STA
LDA
STA
STA
BNE
JSR
BNE
JSR
LDY
DEY
DEY
STY
JSR
JSR
JSR
JSR
JSR
JSR
JSR
JSR
LDX
STA
LDA
STA
ORA
STA
LDA
STA
RTS

*$00
$0274
$DA6D
$DAB6
$0201
$C3BD
SDAB6
SE2
$0277
$0278
$027A
*$80
$E7
*$2A
$0200
$0201
$DA9E
$ClE5
$DA90
$C2DC
#$03

second character
get drive number
not a plain number?

set wildcard flag

,* ,

as file name in command buffer
absolute jump
test input line to ':'
found?
erase flags

pointer to drive no. in command
analyze 1 ine
ascertain file type
get drive number
initialize drive if necessary
prepare disk title
load directory
create and prepare directory
get byte from buffer
channel number
byte in output register
drive number
save as last drive number

$027A
$C200
$C398
$C320
$C3CA
$C7B7
SC49D
$EC9E
$D137
S82
$023E
S7F
$028E
*$04
$EC,X
#SOO
$A3

PRG-flag
set pointer back in input buffer

******************************

DACO
DAC2
DAC5
DAC7
DAC9
DACB
DACE
DADI

A9 00
8D F9 02
A5 83
DO OB
A9 00
BD 54 02
20 27 D2
4C DA D4

LDA
STA
LDA
BNE
LDA
STA
JSR
JMP

DAD4

C9 OF

CMP #$OF

*$00
$02F9
SB3
$DAD4
#$00
$0254
$D227
$D4DA

CLOSE-routine

secondary address
not zero?
secondary address 0, LOAD
close channel
close internal channels 17 & 18
15
179

Anatomy of the 1541 Disk Drive

DAD6
DADS
DADB
DADD
DADF
DAEI
DAE4
DAE6

FO
20
AS
C9
90
AD
DO
4C

14
02 DB
83
02
FO
6C 02
03
94 Cl

BEO
JSR
LDA
CMP
BCC
LDA
BNE
JMP

$DAEC
$DB02
$83
#$02
$DADI
$026C
$DAE9
$C194

DAE9
DAEC
-DAEE
DAFO
DAF3
DAF5
DAF7
DAFA
DAFC
DAFF

4C
A9
85
20
C6
10
AD
DO
4C
4C

AD
OE
83
02
83
F9
6C
03
94
AD

JMP
LDA
STA
JSR
DEC
BPL
LDA
BNE
JMP
JMP

$C1AD
#$OE
$83
$DB02
$83
$DAFO
$026C
$DAFF
$C194
$CIAD

CI
DB
02
C1
C1

yes, close all channels
close file
secondary address
smaller than 2?
termination
14
secondary address
close file
next secondary address

termination

******************************

DB02
DB04
DB07
DB09
DBOB

A6
BD
C9
DO
60

83
2B 02
FF
01

DBOC
DBOE
DB10
DBl3
DB15
DB17
DB19
DBIB
DBIE
DB20
DB23
DB26
DB29

29
85
20
C9
FO
C9
FO
20
BO
20
20
20
4C

OF
82
25 D1
07
OF
04

DB2C
DB2F
DB32
DB35
DB37
D839
DB3B
DB3D
DB3F
DB41
DB43
DB44
CB46
DB48

20
20
20
A6
86
E6
A9
85
85
A5
38
E9
85
20

11

07
09
62
A5
F4
27

D1
DB
DB
EE
D2

FI DD
IE CF
CB El
D5
73
73
00
70
71
D6
OE
72
51 DF

LDX
LDA
CMP
BNE
RTS

$83
$022B,X
#$FF
$DBOC

close file
secondary address
get channel number
no channel associated?
no, then done
isolate channel number

AND #$OF
STA $82
JSR $D125
CMP #$07
BEO $DB26
CMP #$04
BEO $DB2C
JSR $D107
BCS $DB29
JSR $DB62
JSR $DBA5
JSR $EEF4
JMP $D227
JSR
JSR
.TSR
LDX
STX
INC
LDA
STA

$DDFI
$CF1E
$EICB
$D5
$73
$73
#$00
$70

LDA
SEC
SBC
STA
JSR

$D6

check data type
direct access?
yes
reI-file?
yes
channel for writing open
no file for writing?
write last block
wri te en try in d ir and block
write BAM
close channel
get buffer number, write block
change buffer
get last side-sector
side-sector number

#$OE
$72
$ DF51

minus 14 for pointer
calculate block number of file
180

Anatomy of the 1541 Disk Drive

DB4B
DB4D
DB4F
DB51
DB53
DB55
DB 57
DB5A
DB5C
DB5F

A6
AS
95
A5
95
A9
20
FO
20
AC

B2
70
B5
71
BB
40
A6 DD
03
A5 DB
27 D2

LDX
LDA
STA
LDA
STA
LDA
JSR
BEO
JSR
JMP

$B2
$70
$B5,X
$71
$BB,X
#$40
$DDA6
$DB5F
$DBAS
$D227

channel number
record number 10
record number hi
bit 6 set?
no
enter in dirctory
close channel

**** •. *************************
DB62
DB64
DB66
DB68
DB6A
DB6D
DB6F
DB71
DB73
DB76
DB79
DB7B
DB7D
DB80
DB82
DBB4
DB86
DBB8
DBBA
DBBe
DB8D
DBBF
DB90
DB92
DB95
DB98
DB99
DB9C
DB9F
OBA2

A6
B5
15
DO
20
C9
DO
A9
20
20
C9
DO
20
A6
B5
DO
D6
D6
A9
38
E9
4B
A9
20
20
68
20
20
20
4C

B2
B5
BB
OC
EB D4
02
05
OD
Fl CF
E8 D4
02
OF
lE CF
82
B5
02
BB
B5
00
01
00
C8 D4
F'l CF
Fl
C7
99
IE

CF
DO
D5
CF

LDX
LDA
ORA
BNE
JSR
C~lP

BNE
LDA
JSR
JSR
CMP
BNE
JSR
LDX
LDA
BNE
DEC
DEC
LDA
SEC
SBC
PHA
LDA
JSR
JSR
PLA
JSR
JSR
JSR
JMP

S82
$B5,X
$BB,X
$DB76
SD4E8
#S02
$DB76
#SOD
SCFFI
$D4EB
#$02
$DB8C
$CF'l E
$82
$B5,X
SDB88
$BB,X
SB5,X
#$00

not 2
CR
in buffer
set buffer pointer
now equal to 2?
no
change buffer
channel numberrecord number 10
decrement block number hi
and block number 10

#$01

set pointer to end

#SOO
S04C8
$CFFI

buffer pointer- to zero
write zero in buffer
second byte = pointer to end
write in buffer
write block to disk
and verify
change buffer

$CFFI
SDOC7
$D599
$CF'lE

******************************

DBA5
DBA7
DBAA
DBAC
DBAD
DBBO
DBB2
DBB5
DBB8
OBBA
DBBC

82
8E 70 02
A5 83
48
BD 60 02
85 81
BD 66 02
8D 94 02
B5 EC
29 01
85 7F
A6

LDX
STX
LDA
PHA
LDA
STA
LOA
STA
LOA
AND
STA

write last block
channel number
record number 10
record number hi
not zero?
set buffer pointer

$82
$0270
$83
$0260,X
$81
$0266,X
$0294
$ EC,X
#SOl
$ 7 ~~
181

directory entry
channel number
save
secondary address
save
sector number in directory
set
pointer in directory

drive number

Anatomy of the 1541 Disk Drive
DBBE
DBCl
DBC3
DBC6
DBC7
DBC9
DBCC
DBCE
DBDI
DBD3
DRD6
DBDB
DBDA
DBDC
DBDE
DBEI
DBE3
DBE5
DBE7
DBE9
DBEB
DBEC
DBEE
DBFO
DBF2
DBF4
DBF6
DBF7
DBF8
DBFA
DBFC
DBFE
D8FF
DCOI
DC03
DC06
DC07
DC09
DCOB
DCOC
DCOE
DCOF
DCll
DCl3
DC14
DC16
DC18
DC19
DClB
DClE

AD
85
20
48
85
20

91
C8
Bl
85
68
91
20
4C

86

DC2l
DC23
DC25
DC27

Bl
29
09
91

AO

BD
85
AD
85
Bl
29
FO
20
C9
FO
Bl
29
91
C8
Bl
85
84
AO
Bl
48
88
Bl
DO
85
68
85
A9
20
48
A9
91
C8
91
68

85 FE
80
93 DF

$FE8S
$80
$DF93

86
7D C8
29 DC

LDA
STA
JSR
PHA
STA
JSR
LDY
LDA
STA
LDA
STA
LDA
AND
BEQ
JSR
CMP
BEQ
LDA
AND
STA
INY
LDA
STA
STY
LDY
LDA
PHA
DEY
LDA
BNE
STA
PLA
STA
LDA
JSR
PHA
LDA
STA
INY
STA
PLA
LDY
STA
INY
LDA
STA
PLA
STA
JSR
JMP

($86),Y
$C87D
$DC29

erase all files

86
OF
80
86

LDA
AND
ORA
STA

($86),Y
#$OF
#$80
($86) , Y

get fi Ie type
isolate bits 0-3
set bit 7 for closed file

F9
60 D4
00
EO ~'E
87
94 02
86
86
20
43
25 Dl
04
44
86
8F
86
86
80
71
IB
86
86
OA
80
81
67
45 E6
00
86
86

A4 71

86
81

18, directory track
set
increment buffer number

$F9
$D460
#$00
$FEEO,X
S87
$0294
$86
(S86), Y
#$20
$DC21
$D125
#$04
$DC29
($86),Y
#$8F
($86) , Y
($86),Y
$80
$71
#$lB
($86),Y

read directory block
buffer address
buffer pointer
file type
file closed?
yes
check file type
reI-file?
yes
erase bits 4,5, and 6
in file type
track number

sector # of the file for
overwriting

( $86) , Y
$DC06
$80

track # for overwriting
set?
set track number

$81
#$67
SE645

sector number
67, , illegal track or sector'

#$00
($86),Y
($86) , Y

erase track number
and sector number of the
substitute file

$71
($86),Y
set track

&

sec # of the new fil,

($86) , Y
$81

182

Anatomy of the 1541 Disk Drive
DC29
OC2C
OC2E
OC30
OC32
OC33
OC35
OC37
OC38
DC39
OC3B
OC40
DC41
DC43

AE
AO
B5
91
C8
B5
91
68

70 02
lC
B5
86
BB
86

AA

A9
20
68
85
4C

90
90 05
83
07 01

LDX
LOY
LDA
STA
INY
LDA
STA
PLA
TAX
LDA
JSR
PLA
STA
JMP

$0270
lI$lC
$B5,X
($86) ,Y

channel number

$BB,Y
($86),Y

and block number hi
write
buffer number

lI$90
$0590

code for 'writing'
write block

$83
$0107

secondary address
open channel for writing

******************************
OC46
A9 01
LOA lI$Ol
OC48
20 E2 01
JSR $ 01 E2
OC4B
20 B6 DC
JSR $DCB6
DC4E
AD 4A 02
LOA $024A
DC51
48
PHA
OC52
OA
ASL A
05 7F
DCS3
ORA $7F
OCS5
95 EC
STA $EC,X
DC57
20 9B DO
JSR $D09B
DC5A
A6 82
LDX $82
DC5C
A5 80
LDA $80
DO 05
OC5E
BNE $DC65
DC60
A5 81
LOA $81
9D 44 02
DC62
STA $0244,X
OC6S
68
PLA
DC66
C9 04
CMP lI$04
DC68
DO 3F
BNE $DCA9
DC6A
A4 83
LDA $83
B9 2B 02
DC6C
LDA $022B,Y
DC6F
09 40
ORA #$40
DC71
99 2B 02
STA $022B,Y
DC74
AD 58 02
LDA $0258
DC77
95 C7
STA $C7,X
DC79
20 8E D2
JSR $D28E
DC7C
10 03
BPL $DC81
DC7E
4C OF D2
JMP $D20F
DC8l
DC83
DC85
DC88
DC8A
DC8D
DC8F
DC92
DC95
DC98
DC9A
DC9C

A6
95
AC
84
AC
84
20
20
20
A6
A9
95

82
CD
59
80
5A
81
D3
73
99
82
02
Cl

02
02
D6
DE
D5

LDX
STA
LDY
STY
LDA
STY
JSR
JSR
JSR
LDX
LDA
STA

$82
$CD,X
$0259
$80
$025A
$81
$D6D3
$DE73
$D599
$82
lI$02
$Cl,X

block number 10
in directory entry

read block, layout buffer
find channel and buffer for read
set pointer
file type
save
drive number
read block in buffer
channel number
track
following track?
sector
as end pointer
file type
rel-file?
no
secondary address
channel number
set flag for READ and WRITE':
record length
find buffer for side-sector
found?
70, 'no channel'
channel number
track for side-sector
sector for side-sector
transmit parameters to disk cont.
read block
and verify
channel number
pointer for writing

183

Anatomy of the 1541 Disk Drive

DC9E
DCAO
DCA3
DCA6

A9
20
20
4C

00
C8 D4
53 E1
3E DE

LDA
JSR
JSR
JMP

#$00
$D4C8
$E153
$DE3E

DCA9
DCAC
DCAE
DCBl
DCB3
DCB5

20
A6
9D
A9
95
60

56 Dl
82
3E 02
88
F2

JSR
LDX
STA
LDA
STA
RTS

$D156
$82
$023E,X
#$88
$F2,X

buffer pointer to zero
find next record
get track and sector number

******************************

DCB6
DCB8
DCBA
DCBB
DCBC
DCBE
DCC1
DCC3
DCC5
DCC7
DCC8
DCC9
DCCB
DCCE
DCDO
DCD2
DCD4
DCD6
DCD9

A6
B5
OA
A8
A9
99
B5
09
95
OA
A8
A9
99
A9
95
95
A9
9D
60

82
A7
02
99 00
AE
80
AE
02
99 00
00
B5
BB
00
44 02

LDX
LDA
ASL
TAY
LDA
STA
LDA
ORA
STA
ASL
TAY
LDA
STA
LDA
STA
STA
LDA
STA
RTS

$82
$A7,X
A
lI$02
$0099,y
$AE,X
#$80
SAE,X
A
#$02
S0099,Y
#$00
$B5,X
$BB,X
#$ 00
$0244,X

******************************

DCDA
DCDD
DCDF
DCE2
DCE5
DCE8
DCEA
DCED
DCEE
DCEF
DCn
DCn
DCF4
DCF6
DCF8
DCFA
DCFC

20
A9
20
20
20
A6
AD
48
OA
05
95
68
C9
FO
A9
95
60

A9
01
DF
DO
B6
82
4A

DCFD
DeFF
DD02

A4 83

Fl

Dl
D6
DC
02

7 r'
EC
04
05
01
F2

89 28 02
29 3f'

JSR
LDA
JSR
JSR
JSR
LDX
LDA
PHA
ASL
ORA
STA
PLA
CMP
BEO
LDA
STA
RTS

get byte from buffer
channel number
byte in output register
set flag for READ

reset pointer
channel number
buffer number
times 2
buffer pointer 10
set bit 7

buffer pointer 10
block number 10
block number hi
end pointer
construct a new block
find free sector in BAM

$FIA9
#$01
$DIDF
$D6DO
$DCB6
$82
$024A

open channel
transm i t param to disk controller
reset pointer
channel number
file type

A
$7F
$EC,X

drive number
save as flag

#$04
$DCFD
#$01
$F'2,X

reI-file?
yes
set WRITE flag

LDY $83
LDA S022B,Y
AND #$1F
184

secondary address
channel number in table
erase the top two bits

Anatomy of the 1541 Disk Drive
DD04
DD06
DD09
DDOC
DDOE
DDll
DD13

09
99
AD
95
20
10
4C

40
2B
5S
C7
SE
03
OF

DD16
DD18
DDIA
DDID
DD20
DD22
DD25
DD27
DD2A
DD2C
DD2E
DD31
DD33
DD36
DD38
DD3B
DD3D
DD40
DD42
DD45
DD48
DD4B
DD4D
DD50
DD52
DD55
DD57
DD5A
DD5D
DD5F
DD62
DD64
DD67
DD6A
DD6D
DD6F
DD72
DD74
DD75
DD77
DD79
DD7B
DD7E
DD81
DD84
DDS7
DD8A

A6
95
20
20
AS
8D
A5
SD
A6
B5
20
A9
20
A9
20
A9
20
A9
20
AD
20
A5
20
A5
20
A9
20
20
AS
20
AS
20
20
20
A9
20
A6
3S
A9
F5
95
20
20
20
20
20
4C

82
CD

02
02
D2
D2

Cl DE

IE
80
59
81
5A
82
CD
D3
00
E9
00
8D

Fl
02
02
D6
DE
DD

11

8D
00
8D
58
8D
SO
8D
81
SD
10
E9
3E
SO
8D
81
SD
6C
99
02
CS
82
00
C7
Cl
E2
19
SE
99
F4
98

DD
DD
02
DO
DD
DD
DE
DE
DO
DD
DE
D5
D4

E2
DE
DE
D5
EE
DC

ORA
STA
LDA
STA
JSR
BPL
JMP

#$40
$022B,Y
$0258
$C7,X
$D28E
$DD16
$D20F

set bit 6
READ and WRITE flag
record length
in table
find buffer
found?
70, 'no channel'

LDX
STA
JSR
JSR
LDA
STA
LDA
STA
LDX
LDA
JSR
LDA
JSR
LDA
JSR
LDA
JSR
LDA
JSR
LDA
JSR
LDA
JSR
LDA
JSR
LDA
JSR
JSR
LDA
JSR
LDA
JSR
JSR
JSR
LDA
JSR
LDX
SEC
LDA
SBC
STA
JSR
JSR
JSR
JSR
JSR
JMP

$S2
$CD,X
$DECI
$FllE
$80
$0259
$81
$025A
$82
$CD,X
$D6D3
#$00
$DEE9
#$00
$DDSD
#$11
$DD8D
#$00
$DDBD
$0258
$DD8D
$SO
$DD8D
$81
$DD8D
#$10
$DEE9
SDE3E
SSO
SDD8D
S81
SDDSD
SDE6C
$D599
#S02
$D4C8
SS2

channel number
buffer number for side-sector
erase buffer
find free block in BAM
track
for side-sector
sector
for side-sector
channel number
buffer number
transmit param to disk controller
buffer pointer to zero
17
as end pointer in buffer
zero
as side-sector number in bt'ffer
record length
in buffer
track number of this block
in buffer
sector number
in buffer
16
buffer pointer to 16
get track and sector number
track # of the first data block
in buffer
sector # of the first data block
in buffer
write block to disk
and check
buffer pointer to 2
channel number

#$00
$C7,X
SCl,X
$E2E2
$DE19
SDESE
SD599
SEEF4
$DC98

record length
pointer for writing
erase buffer
write link bytes in buffer
write block to disk
and check
write BArI
and done

185

Anatomy of the 1541 Disk Drive

******************************

DDBD
DDBE
DD90
DD92

4B
A6 82
B5 CD
4C FD CF

PHA
LDX $82
LDA $CD,X
JMP SO'FD

write byte in side-sector block
save byte
channel number
buffer # of the side-sector
write byte in buffer

******************************
DD95
90 06
Bec $DD9D
DD9?
A6 82
LOX $82
DD99
15 EC
ORA $EC,X
BNE $DDA3
DD9B
DO 06
DD9D
A6 82
LDX S82
49 FF
EOR #$FF
DD9F
DDAI
35 EC
AND SEC,X
DDA3
95 EC
STA $EC,X
DDA5
60
RTS
DDA6
A6 82
LDX $82
DDA8
35 EC
AND $EC,X
DDAA
RTS
60

manipulate flags

******************************

$DF93

check command code for writing
get buffer number

$025B,X
#$FO
#$90

isolate command code
code for writing?

DDAB
DDAE
DDAF
DDB2
DDB4
DDB6

20
AA
BD
29
C9
60

93 OF
5B 02
FO
90

JSR
TAX
LDA
AND
CMP
RTS

channel number
set flag
channel number
erase flag
channel number
test flag

******************************

DDB?
DDB9
DDBB
DDBE
DDCO
DDC2
DDC4
DOCS
DDC7
DDC9

A2
86
BD
C9
DO

00
71
2B 02
FF
08
A6 71
88
EO 10
90 FO
60

LOX
STX
LOA
CMP
BNE
LOX
INX
CPX
Bce
RTS

#$00
571
S022R,X
#$FF
$ODCA
$71

DDCA
DDce
DDCE
DDCF
DDD2
DDD4
DDD6
DDD9
DDDR
DDDD
DDDF
DDEl
DDE4
DDE6

86
29
A8
B9
29
85
AE
B5
29
C5
DO
89
05
DO

STX
AND
TAY
LDA
AND
STA
LDX
LDA
AND
CMP
BNE
LDA
CMP
BNE

$71
#$3F

71
3F
EC 00
01
70
53 02
E2
01
70
81
60 02
DB
DA

counter for secondary address
get channel number from table
file open?
increment counter
smaller than l6?

#$10
$DDB9

isolate channel number

$OOEC,Y
#$ 01
S70
$0253
$E2,x
#$01
$70
$DDC2
$0260,Y
SD8,X
$DDC2
186

isolate drive number

isolate drive number
same drive?
no
sector number in directory
same as file?
nO

Anatomy of the 1541 Disk Drive
DDE8
DDEB
ODED
DDEF
DDFO

B9 66 02
D5 DD
DO D3
18
60

LDA $0266,Y
CMP $DD,X
BNE $DDC2
CLC
RTS

pointer same?
no

*.****************************
DDFI
JSR $D~'9E
20 9E DF
DDF4
50 06
BVC $DDFC
20 5E DE
JSR $DE5E
DDF6
20 99 D5
JSR $D599
DDF9
DDFC
60
RTS

write a block of a reI-file
get buffer number
no reI-file?
write block
and verify

******************************
20 2B DE
DDFD
JSR $DE2B
DEOO
AS 80
LDA $80
91 94
STA (S94),Y
DE02
DE04
INY
C8
AS 81
LDA $81
DE05
91 94
STA ($94),Y
DE07
4C 05 El
JMP $ElO5
DE09

write bytes for following track
set buffer pointer
track number
in buffer

******************************
DEOC
20 2B DE
JSR $DE2B
Bl 94
DEOF
LDA ($94),Y
STA $80
DEll
85 80
DEl3
C8
INY
DE14
Bl 94
LDA ($94),Y
85 81
DE16
STA $81
DE18
RTS

get following track and sector
set buffer pointer
following track number

******************************
DE19
20 2B DE
JSR SDE2B
DEIC
A9 00
LDA #$00
DElE
91 94
STA ($94),Y
DE20
C8
INY
DE21
A6 82
LDX $82
DE23
B5 Cl
LDA $Cl,X
DE25
AA
TAX
DE26
CA
DEX
DE27
TXA
8A
STA ($94),Y
91 94
DE28
DE2A
60
RTS

following track for last block
set buffer pointer
zero
as track number

******************************
DE2B
20 93 DF
JSR $DF93
OA
ASL A
DE2E
TAX
DE2F
AA
DE30
LDA $9A,X
B5 9A
DE32
85 95
STA $95
A9 00
LDA #$00
DE34
85"94
STA $94
DE36
AO 00
LDY #$00
DE38
DE3A
60
RTS

187

sector number
in buffer
set reI-flag

and get sector number

channel number
pointer in block
minus I
as pointer in block
buffer pointer to zero
get buffer number
times 2
buffer pointer hi
buffer pointer 10

*

Anatomy of the 1541 Disk Drive
******************************
JSR $OOEB
20 EB DO
OE3B
JSR $OF93
OE3E
20 93 OF
85 F9
STA $F9
OE41
OE43
OA
ASL A
OE44
A8
TAY
B9 06 00
OE45
LOA $0006.Y
85 80
STA $80
OE48
OE4A
B9 07 00
LOA $0007.Y
STA $81
OE40
85 81
RTS
OE4F
60

******************************
A9 90
LOA #$90
OE50
8D 4D 02
STA $024D
DE52
BNE $OE7F
DO 28
DE55
80
4D 02
21
90
40 02
26

get track
and sector # from disk controlle

command code for writing

command code for reading

DE57
OE59
DE5C
DE5E
OE60
OE63

A9
8D
DO
A9
80
DO

OE65
DE67
DE6A

A9 80
80 4D 02
DO IF

LOA #$80
STA $024D
BNE $OE8B

command code for reading

DE6C
DE6E
DE71

A9 90
80 4D 02
DO 02

LDA #$90
STA $0240
BNE $OE75

command code for writing

DE73
DE75
OE78
DE7A
DE7C
DE7D
OE7F
DEB2
DEBS
OEB6
DEB8
DE8B
DEBE
DE91
DE92

A9 80
8D 4D 02
A6 82
B5 CD

LOA
STA
LOX
LOA
TAX
BPL
JSR
JSR
TAX
LOA
STA
JSR
JSR
TAX
JMP

#$80
$0240
$82
$CO.X

command code for reading

$OE92
$0600
$OF93

buffer associated?
generate header for disk cont.
get buffer number

$7F
$025B.X
$E1l5
$OF93

drive number

$D506

wri te block

AA

10 13
20 00 06
20 93 OF
AA

AS
90
20
20

7F
5B 02
15 E1
93 OF

AA

4C 06 05

LDA
STA
BNE
LOA
STA
BNE

get track and sector
get channel number
get buffer number
save
times 2

#$80
$024D
$OE7/:O'
#$90
$024D
$OE8B

command code for writing

channel number
side-sector buffer number

******************************
LOA #$00
OE95
A9 00
20 C8 04
JSR $04C8
OE97
OE9A
JSR
$D137
20 37 01
85·80
STA $80
DE90
20 37 01
JSR $0137
OE9F
OEA2
85 81
STA $81

188

buffer number
get buffer number

get following track & sector fron
buffer
buffer pointer to zero
get byte
save as track
get byte
as sector

Anatomy of the 1541 Disk Drive

DEM

60

RTS

******************************
4B
PHA
DEA5
DEA6
LDA #$00
A9 00
85 6F
DEAB
STA $6F
DEM
85 71
STA $71
DEAC
B9 EO FE
LDA $FEEO,y
DEAF
B5 70
STA $70
DFBI
BD EO FE
LDA $FEEO,X
STA $72
DEB4
85 72
PLA
DEB6
68
DEB7
AB
TAY
88
DEBB
DEY
LDA ($6F),Y
DEB9
Bl 6F
DEBB
91 71
STA ($71l,Y
DEBD
88
DEY
DEBE
10 F9
BPL $DEB9
RTS
DECO
60

copy buffer contents

******************************

erase buffer Y
buffer number
get hi-address

DECI
DEC2
DEC5
DEC7
DEC9
DECB
DECC
DECE
DEC~'

DEDI

A8
89
85
A9
85
AS
91
C8
DO
60

EO FE
70
00
6F
6F
FB

TAY
LDA
STA
LDA
STA
TAY
STA
INY
BNE
RTS

$FEEO,y
$70
#$00
$6F
($6F), Y

A9
20
AO
Bl
60

00
DC DE
02
94

LDA
JSR
LDY
LDA
RTS

#$00
SDEDC
#$02
(S94),Y

******************************

DEDC
DEDE
DEEO
DEE2
DEE3
DEE6
DEE8

85 94
A6 82
B5 CD
AA

BD EO FE
85 95
60

STA
LDX
LDA
TAX
LDA
STA
RTS

48
20 DC DE
48
SA
OA
AA

copy contents of buffer Y
to buffer X

lo-address
erase buffer

get side-sector number
buffer pointer to zero
byte 2 contains the side-sector #

$94
$82
$CD,X

set buffer ptr to side-sector
pointer 10
channel number
buffer number

$FEEO,X
S95

buffer address hi
set

******************~***********

DEE9
DEEA
DEED
DEEE
DEEF
DEFO

buffer address X, hi

$DECC

******************************

DED2
DED4
DED7
DED9
DEDB

buffer address Y, hi

PHA
JSR $DEDC
PHA
TXA
ASL A
TAX

buffer pointer for side-sector
pointer in side-sector
set buffer pointer
buffer number
times 2

189

Anatomy of the 1541 oisk Orive
OEFI
OEF2
OEF4
OEF5
OEF7

68
95 9A
68
95 99
60

PLA
STA $9A,X
PLA
STA $99,X
RTS

buffer pointer hi
buffer pointer 10

******************************
20 66 OF
JSR $OF66
OEF8
8MI $OFOB
30 OE
OEFB
BVC $DF12
50 13
OEFO
OEFF
A6 82
LOX $82
LOA $CO,X
OFOI
B5 CO
20 18 OF
JSR $DFIB
OF03
20 66 OF
JSR $DF66
OF06
10 07
BPL $DF12
0F'09
OFOB
20 CB El
JSR $EICB
BIT $FECE
OFOE
2C CE FE
OFll
60
RTS
OF'12
A5 06
LOA $06
JSR $OEE9
OF14
20 E9 OE
BIT $FECD
OF17
2C CO OE
RTS
OFIA
60

get side-sector and buffer ptr
is side-sector in buffer
no
ok
channel number
buffer number
read side-sector
and check if in buffer
yes?
get last side-sector
set V bit

******************************
STA $F9
OFIB
85 F9
A9 80
OFIO
LDA *$80
OFIF
BNE $OF25
00 04

read side-sector
buffer number
command code for reading

******************************

write side-sector
buffer number
command code for writing

DF21
DF23
DF25
OF26
OF28
DF2A
Or'2C
OF2D
DF2F
DF32
OF34
DF36
DF37
DF39
DF3B
OF30
OF40
OF42

85
A9
48
B5
29
85
68
05
8D

F9
90
EC
01
7F

7F
40 02
Bl 94
85 80
C8
Bl 94
85 81
A5 F9
20 D3 D6
A6 F9
4C 93 05

STA
LOA
PHA
LOA
ANO
STA
PLA
ORA
STA
LOA
STA
INY
LOA
STA
LOA
JSR
LOX
JMP

$F9
#$90
$EC,X
#$01
$7F

side-sector end pointer
set pointer in side-sector
erase V bit

isolate drive number

$7F
$0240
($94),Y
$80

command code plus drive number
save
track number

($94), Y
$81
$F9
$0603
$F9
$0593

sector number
buffer number
transmit param to disk controller
buffer number
tranmit cmd to disk controller

******************************
01"45
A6 82
LOX $82
Df'47
B5 CD
LOA $CD,X
4C E8 04
JMP $D4EB
OF49

set buffer pointer in side-sector
channel number
buffer number
set buffer pointer

******************************

calculate block # of a reI-file
120 block ptrs per side-sector

DF4C

A9 78

LDA #$78
190

Anatomy of the 1541 Disk Drive
OF4E
OFSl
DFS2
DFS4
OFS6
OFS7
DF5A
DF5C
OF50
DF5F
DF61
DF63
DF65

20
CA
10
AS
4A
20
AS
18
6S
8S
90
E6
60

SC DF
F8
72
SC DF
73
70
70
02
71

JSR
DEX
BPL
LDA
LSI<
JSR
LDA
CLC
AOC
STA
BCC
INC
RTS

add to $70/$71
side-sector number
next side-sector?
pointer value in last block
divided by 2
add to previous sum
number of the side-sector block

$DFSC
$DNC
$72
A
$OFSC
$73
$70
$70
$DF65
$71

add

******************************

OF66
DF69
DF6B
DF6D
DF6F
DF71
DF73
OF76
OF77
DF7A

20 D2 DE
CS OS
DO OE
A4 D6
Bl 94
FO 04
2C CO FE
60
2C CF FE
60

JSR
CMP
BNE
LOY
LDA
BEQ
BIT
I write pointer?
no
change buffer
channel number
change buffer
change buffer

set buffer pointer
channel number
end pointer
buffer pointer to ze.ro
byte from buffer
not zero?

Anatomy of the 1541 Disk Drive
E1C7

60

RTS

E1C8
E1C9
E1CA

98
38
60

TYA
SEC
RTS

******************************

E1CB
E1CE
E1DO
E1D2
EID4
EID6

20
85
A9
85

D2 DE
D5
0-4
94
AD OA
DO 04

JSR
STA
LDA
STA
LDY
BNE

EID8
EID9
EIDA
EIDC
EIDE
EIEO
E1El
E1E2
E1E4
E1E6
E1E8
ElEA
E1EC
E1EF
E1Fl
EIF3
E1F5
E1F7
E1F8
EIFA
E1FB
EIFC
E1FE
E1FF

88
88
30
Bl
FO
98
4A
C5
FO
85
A6
B5
20
AO
84
Bl
DO
C8
Bl
1'18
88
84
98
4C

DEY
DEY
BMI
LDA
BEO
TYA
LSR
CMP
BEO
STA
LDX
LDA
JSR
LDY
STY
LDA
BNE
INY
LDA
TAY
DEY
STY
TYA
JMP

E202
E204

A9 67
20 45 E6

26
94
F8
D5
09
D5
82
CD
IB DF
00
94
94
OB
94
D6
E9 DE

$DED2
$D5
#$04
$94
*SOA
$EIDC

pointer to side-sectors

$E202
(S94),Y
$EID8

20
AD
85
20
90
1'19
20

divide by 2
number of the actual block?
yes
else save all numbers
channel number
buffer number
read block

($94),Y

sector number

$D6

save end pointer

$DEE9

set buffer pointer

#$67
JSR $E645

Cl

JSR
LDA
STA
JSR
BCC
LDA
JSR

$C2B3
$0201
$83
SDOEB
$E2l9
#$70
$C1C8

E2l9
E21B
E21E
E22l

1'19 AD
20 9D DD
20 25 Dl
FO 05

LDA
JSR
JSR
REO

#$AO
$DD9D
$D125
$E228

B3
01
83
EB
05
70
C8

C2
02
DO

track # of the previous block

A
$D5
SEIEF
$D5
S82
$CD,X
$DFIB
#$00
$94
($94) ,Y
$E202

=

buffer pointer
track number
another block?

=

end pointer

67, , illegal track or sector'

******************************

E207
E20A
E20D
E20F
E2l2
E2l4
E2l6

get last side-sector
get number of the side-sector
save

P-command,
'Record'
verify lines
secondary address
find channel number
found?
70, 'no block'
erase bits 6 & 7
verify if 'REL'-file
yes

191

Anatomy of the 1541 Disk Drive
E223
E225

A9 64
20 C8 Cl

LDA #$64
JSR $CIC8

E228
E22A
E22C
E22E
E231
E233
E236
E238
E23A
E23C
E23E
E241
E243
E244
E246
E248
E24A
E24C
E24E
E251
E253
E255
E258
E25B
E25D
E25F
E262

B5
29
85
AD
95
AD
95
A6
A9
95
AD
FO
38
E9
FO
D5
90
A9
8D
A9
85
20
20
50
A9
20
4C

DD
El

LDA
AND
STA
LDA
STA
LDA
STA
LDA
LDA
STA
LDA
BEO
SEC
SBC
BEO
CMP
BCC
LDA
STA
LDA
STA
JSR
JSR
BVC
LDA
JSR
JMP

#$01
$E253
$C7,X
$E253
#$51
$02liC
#$00
$D4
$CEOE
$DEF8
$E265
#$80
$DD97
$E15E

E265
E268
E26A
E26D
E26F
E272

20 75 E2
A9 80
20 A6 DD
FO 03
4C 5E El
4C 94 Cl

JSR
LDA
JSR
BEO
JMP
JMP

$E275
#$80
$DDM
$E272
$E15E
$C194

test bit 7
not set
50, 'record not present'
done

E275
E278
E27A
E270
E27F
E281
E282
E284
E286

20
A5
20
M
B5
38
E5
BO
4C

JSR
LDA
JSR
LDX
LDA
SEC
SBC
BCS
JMP

$E29C
$D7
$D4C8
$82
$C7,X

pointer in reI-file
set buffer pointer
channel number
record length

$D4
$E289
$E202

minus position
positive?
67, , illegal track or sector'

E289
E28A
E28C
E28E
E290
E291
E294

18
65
90
69
38
20
4C

$D7
$E291
#$01

add pointer in data blocK
no overflow
plus 2

$E009
$E138

set pointer
get byte froIl' buffer

EC
01
7F
02 02
B5
03 02
BB
B2
89
F2
04 02
10
01
08
C7
07
51
6C
00
D4
OE
F8
08
80
97
5E

02
CE
DE

9C E2
07
C8 D4
82
C7
D4
03
02 E2
07
03
01
09 EO
38 E1

CLC
ADC
BCC
ADC
SEC
JSR
JMP

64, , file type mismatch'

$EC,X
#$01
$7F
$0202
$B5,X
$0203
$BB,X
$82
#$89
$F2,X
$0204
$E253

drive number
record number 10
record number hi
channel number
READ and WRITE flag
byte-pointer
zero?

compare wi th record length
51, 'overflow in record'
calculate pointer in reI-file
and read appropriate side-sector
does blocK exist?
set bit 7
and 50, , record not present'

198

Anatomy of the 1541 Disk Drive

LDA #$51
JSR $CIC8

E297
E299

A9 51
20 C8 Cl

E29C
E29E
E2AO
E2A2
E2M
E2A7
E2A9

A5
85
A5
85
20
DO
60

94
89
95
8A
DO E2
01

LDA
STA
LDA
STA
JSR
BNE
RTS

$94
$89
$95
$8A
$E2DO
SE2AA

E2M
E2AD
E2BO
E2B2
E2B4
E2B7
E2B9
E2BC
E2BF
E2C2
E2C4
E2C6
E2C8
E2C9
E2CB
E2CD

20
20
A5
FO
20
DO
20
4C
20
AO
Bl
85
C8
Bl
85
4C

Fl
OC
80
OE
D3
06
IE
DA
DA
00
89
80

JSR
JSR
LDA
BEQ
JSR
BNE
JSR
JMP
JSR
LOY
LOA
STA
INY
LOA
STA
JMP

$DDFI
$DEOC
$80
$E2C2
$E2D3
$E2BF
$CFIE
$D20A
$D20A
#$00
($89), Y
$80

E2DO
E2D3
E2D5
E2D7
B2D9
E2DB
E2DC
B2DD
E20F
E2El

20
AO
Bl
C5
FO
60
C8
Bl
C5
60

3E DE
00
89
80
01

JSR
LOY
LOA
CMP
BEQ
RTS
INY
LDA

$OE3E
#$00
($89),Y
$80
$E2DC

DD
DE
E2
CF
D2
02

89
81
AF DO

89
81

C~lP

51, 'overflow in record'
buffer pointer 10
buffer pointer hi
compare track and sector
not equal?

($89),Y
$81
$DOAF

($89) ,Y
$81

20
AO
A9
91
C8
DO
20
95
A8
A9
91
20
90
DO

track
and sector of the next block
read block

track number
compare

sector number
compare

RTS

******************************

E2E2
E2E5
E2E7
E2E9
E2EB
E2EC
E2EE
E2Fl
E2F3
E2F4
E2f'6
E2F8
E2FB
E2FD

track
no block following?
compare track and sector number
not equal?
change buffer

2B DE
02
00
94
FB
04 E3
Cl
FF
94
04 E3
F4
04

JSR
LDY
LDA
STA
INY
BNE
JSR
STA
TAY
LDA
STA
JSR
BCC
BNE

$DE2B
#$02
#$00
($94) ,Y
$E2E9
$E304
$Cl,X

subdivide records in data block
set buffer pointer
erase buffer
set pointer to next record

#$FF
($94) ,Y
$E304
$ E2F1
$E303
199

SFF as 1st character in record
set pointer to next record
done in this block?
block full?

Anatomy of the 1541 Disk Drive
E2r'F
E301
E303

A9 00
95 Cl
60

LDA #SOO
STA $Cl,X
RTS

write pointer to zero

******************************
E304
A6 82
LDX $82
E306
B5 Cl
LDA $Cl,X
38
E308
SEC
FO OD
E309
BEO $E318
E30B
18
CLC
E30C
75 C7
ADC $C7,X
E30E
90 OB
BCC $E31B
BNE $E318
E310
DO 06
E312
A9 02
LDA #$02
E314
2C CC FE
BIT $F'ECC
60
E317
RTS

E318
E31A
E31B

69 01
38
60

ADC #$01
SEC
RTS

set pointer to next record
channel number
write pointer
equal zero?
add record length
smaller than 256?
equal 256?

add two

******************************
E31C
20 D3 Dl
JSR SDID3
JSR SEICB
E31F
20 CB El
E322
JSR $E29C
20 9C E2
E325
20 7B CF
JSR $CF7B
E328
AS D6
LDA SD6
E32A
85 87
STA $87
E32C
A5 D5
LDA $D5
E32E
85 86
STA $86
E330
A9 00
LDA #$00
E332
85 88
STA $88
E334
A9 00
LDA #$00
E336
STA $D4
85 D4
E338
20 OE CE
JSR $CEOE
E33B
20 40 EF
JSR $EF4D
E33E
A4 82
LDY $82
E340
B6 C7
LDX $C7,Y
E342
CA
DEX
E343
8A
TXA
E344
18
CLC
E345
65 07
ADC $07
E347
90 DC
FlCC $E355
E349
E6 06
INC SD6
E34B
INC $06
E6 06
DO 06
BNE $E355
E34D
E34F
E6 05
INC $D5
E351
A9 10
LDA #$10
E353
85 06
STA #06
E355
AS 87
LOA $87
E357
18
CLC
E358
69 02
ADC #$02
F,35A
20 E9 DE
JSR $DEE9
E35D
AS D5
LOA $D5
E35F
C9 06
CMP #$06
200

expand side-sector
get drive number
get last side-sector

side-sector number

calculate side-sector no. and pt
number of free blocks
channel number
record length

plus pointer in data hlock
increment ptr to end by 2
increment side-sector number
set pointer to 16

set buffer ptr for side-sector
side-sector number

Anatomy of the 1541 Disk Drive
E361
E363
E365
E368
E36A
E368
E36D
E36F
E371
E372
E374
E376
E378
E37A
E37C
E37E
E380
E381
E384
E386
E388
E38A
E388
E38D
E38F
E392
E394
E396
E399
E39B
E390
E39F
E3A2
E3A3
E3A5
E3A7
E3A9
E3AC
E3AF
E38l
E383
E3B6
E389
E3BC
E3BF
E3C2
E3C5

90
A9
20
A5
38
E5
80
E9
18
85
A5
E5
85
A2
86
86
20
A5
DO
A6
CA
DO
E6
CD
90
DO
AD
C5
90
A9
20
18
69
A6
95
20
20
A5
00
20
20
20
20
20
20
4C

51 DF
71
07
70

E3C8
E3CB
E3CE
E30l
E304
E3D7
E3DA

20
20
20
20
20
20
A5

IE
DO
E2
19
5E
OC
80

05
52
C8 Cl
06
87
03
OF
72
D5
86
73
00
70
71

AA

02
88
73 02
09
CD
72 02
70
C6
01
F6 D4
01
82
Cl
IE
FD
88
15
5E
IE
DCi'
IE
FD
E2
D4

Fl
DO
DE
CF
D6
Fl

DD
E2
E3
CF
D6
E2
DE
DE
DE

8CC
LOA
JSR
LOA
SEC
S8C
8CS
SBC
CLC
STA
LDA
SBC
STA
LDX
STX
STX
TAX
JSR
LDA
BNE
LDX
DEX
BNE
INC
CMP
BCC
BNE
LDA
CMP
8CC
LDA
JSR
CLC
ADC
LDX
STA
JSR
JSR
LDA
BNE
JSR
JSR
JSR
JSR
JSR
JSR
JMP

$E368
*$52
SCIC8
$D6

smaller than 6?

S87
$E372
HOF

minus last end pointer

JSR
JSR
JSR
JSR
JSR
JSR
LOA

$CF1E
$D6DO
$E2E2
SDE19
$DE5E
$OEOC
$80

52, ' file too large'
end pointer

minus 16

$72
SD5
$86
S73
#SOO
S70
$71

side-sector number
minus last side-sector number
save
erase sum for calculation

$OF5I
S71
$E38F
$70

calculate block # of reI-file

$E38F
$88
S0273
$E39D
SE363
S0272
$70
$E363
#$01
$D4F6

block number of reI-file
greater than free blocks on disk?
52, 'file too large'
52, 'file too large'
get byte from buffer

#$01
582
$Cl,X
$FllE
$ODFD
$88
$E3C8
$DE5E
$CFlE
$06DO
$FllE
$DDFD
$E2E2
$E3D4

plus 1
as write pointer
find free block in BAM
track and sector in buffer
only one block needed?
write block
change buffer
transmit param to disk controller
find free block in BAM
track and sector in buffer
erase buffer
change huffer
transmit par-am to disk controller
erase buffer
zero byte and end ptr in buffer
write block
get track and sector
track
201

Anatomy of the 1541 Disk Drive
E3DC
E3DD
E3DF
E3EO
E3E3
E3E5
E3E6
E3E8
E3E9
E3EC
E3ED
E3EF
E3F2
E3F4
E3F7
E3F9
E3FA
E3FD
EWE
E401
E402
E404
E405
E407
E409
E40B
E40D
E40F
E412
E414
E416
E418
E413
E41C
E41E
E421
E423
E424
E426
E427
E428
E429
E42B
E42D
E430
E433
E436
E439
E43C
E43F
E441

48
48
20
A5
48
A5
48
20
AA
DO
20
A9
20
E6
68
20
68
20
68
85
68
85
FO
A5
C5
00
20
C5
90
FO
20
48
A9
20
A9
A8
91
C8
68
38
E9
91
20
20
20
20
20
20
70
4C

E444
E446
E449

A9 BO
20 97 DO
A9 50

A4 81

3E DE
81
80
45 OF
OA
4E E4
10
E9 OE
86
80 DD
80 00
81
80
OF
86
05
A7
45 DF
D6
AO
BO
45 OF
00
DC DE
00
94

01
94
6C
99
F4
OE
IE
F8
03
75

DE
D5
EE
CE
CF
OE
E2

PHA
LDA
PHA
JSR
LOA
PHA
LOA
PHA
JSR
TAX
BNE
JSR
LOA
JSR
INC
PLA
JSR
PLA
JSR
PLA
STA
PLA
STA
BEO
LDA
CMP
BNE
JSR
CMP
BCC
BEO
JSR
PHA
LDA
JSR
LDA
TAY
STA
INY
PLA
SEC
SEC
STA
JSR
JSR
JSR
JSR
JSR
JSR
BVS
JMP

$DE3E
$81

and sector
save
get track and sector from disk
controller

$80

save track and sector

$DF45

set buffer ptr for side-sector

$E3F9
$E44E
#$10
$OEE9
$86

pointer not zero?
write side-sector

$0080

track in side sector

$008D

sector in side-sector

$81

sector

$80
$E418
$86
$D5
$E3B6
$0F45
$06
$E336
$E3C8
$DF45

and get track back
no more blocks?
side-sector number
changed?
yes
set buffer ptr in side-sector
end pointer
smaller?
same
set buffer ptr in side-sector

#$00
$DEDC
#$00

buffer pointer to zero

($94), Y

zero as track number

S81

buffer pointer to 16
increment side-sector number

end pointer
#$01
($94), Y
$DE6C
$0599
$EEF4
$CEOE
$CFIE
$OEFB
$E444
$E275

LOA i$80
JSR $0097
LDA #$50

minus one
as sector
write block
and verify
update BAM
update pointer for reI-file
change buffer
right side-sector?
no

set bit 7

202

Anatomy of the 1541 Disk Drive

E44B

20 C8 Cl

JSR $CIC8

50, 'record not present'

******************************

E44E
E451
E454
E457
E45A
E45B
E45E
E460
E462
E463
E464
E465
E467
E46A
E46C
E46F
E471
E473
E474
E476
E479
E47A
E47B
E470
E47F
E480
E482
E484
E485
E486
E488
E48A
E48C
E48E
E490
E491
E493
E495
E497
E499
E49A
E49C
E49D
E49F
E4A1
E4A3
E4A6
E4A9
E4AC
E4AE
E4BO

20
20
20
20
48
20
A6
B5
A8
68
AA
A9
20
A9
20
AO
Bl
48
A9
20
68
18
69
91
OA
69
85
A8
38
E9
85
AS
85
91
C8
AS
85
91
AO
98
91
C8
A9
91
A9
20
20
20
A6
B5
48

IE
IE
Fl
93

Fl
CF
DD
DF

Cl DE
82
CO

10

A5 OE
00
DC DE
02
94
00
C8 04
01
94
04
89
02
SA
80
87
94
81
88
94
00
94
II

94
10
C8 D4
50 DE
99 05
82
CD

JSR
JSR
JSR
JSR
PHA
JSR
LDX
LOA
TAY
PLA
TAX
LOA
JSR
LOA
JSR
LDY
LOA
PHA
LDA
JSR
PLA
CLC
AOC
STA
ASL
ADC
STA
TAY
SEC
SBC
STA
LOA
STA
STA
INY
LOA
STA
STA
LOY
TYA
STA
INY
LDA
STA
LDA
JSR
JSR
JSR
LDX
LDA
PHA

$FllE
$CFIE
$DDFI
$DF93

write side-sector and allocate
new one
find free block in BAM
change buffer
write block
get buffer number

$DECl
$82
$CO,X

erase buffer
channel number
buffer number

*$10
$OEA5
*$00
$OEDC
*$02
($94) , Y

16 bytes of the side-sector
copy in buffer

#$00
$04C8

buffer ptr to 0, old side-sector
side-sector number
buffer ptr to 0, new side-sector

*$01
($94) , Y
A
#$04
$89

increment side-sector numbE'r
and in buffer
times 2
plus 4

#$02
$8A
$80
$87
($94) , Y

minus 2
same pointer to old side-sector
track

$81
$88
($94) , Y
*$00

sector

($94) , Y

zero in buffer

#$11
($94) , Y
#$10
$D4C8
$DE50
$D599
$82
$CD,X

number of bytes in block
16
buffer pointer to 16
write block
and verify
channel number
buffer number of the side-~'ector

203

in buffer

in buffer

17

Anatomy of the 1541 DiskOrive
E4Bl
E4B4
E4B6
E4B8
E4B9
E4BC
E4BE
E4CO
E4C3
E4CS
E4C7
E4C9
E4CA
E4CC
E4CE

20
A6
95
68
AE
95
A9
20
AO
AS
91
C8
AS
91
4C

E4Dl
E404
E406
E409
E40B
EFDE
E4EO
E4E2
E4E4
E4E6
E4E8
E4E9
E4EB
E4ED
E4FO
E4F3
E4f'5
E4F7
E4F9

20
A6
20
A9
20
C6
C6
A4
AS
91
C8
AS
91
20
20
A4

CO
SO
4C

9E OF
82
CO
57 02
A7
00
C8 04
00
80
94
81
94
OE E4
93 OF
82
IB OF
00
C8 04
8A
8A
89
87
94
88
94
5E DE
99 D5
8A
03
08
IE CF

JSR
LOX
STA
PLA
LOX
STA
LOA
JSR
LOY
LOA
STA
INY
LOA
STA
JMP
JSR
LOX
JSR
LDA
JSR
OEC
DEC
LOY
LOA
STA
INY
LOA
STA
JSR
JSR
LOY
Cpy
BCS
JMP

$OF9E
$82
$CO,X

get buffer number
channel number
write in table

$0257
$A7,X
i$OO
$04C8
#$00
$80
($94), Y

channel number + 7
in table

$81
($94), Y
$E40E

sector
in buffer

$OF93
$82
$OFIB
#$00
$04C8
$8A
$8A
$89
$87
($94), y

get buffer number
channel number
read block

$88
($94), Y
$OE5E
$0599
$8A
#$03
$E401
$CFIE

sector number
in buffer
write block
and verify
counter for side-sector blocks

******************************
E4FC 00
E4FO AO 4F CB
E500 20 21 22 23 24 27
E506 02 45 41 44
E50A 89
E50B 52
E50C 83
E500 20 54 4F 4F 20 AC 4A 52 47
E517 50
E518 8B 06
E51A 20 50 52 45 53 45 4E 04
E522 51
E523 CF 56 45 52 46 4C 4F 57 20
E52E 8B
E52F 25 28
E531 8A 89
E533 26
E534 8A

204

buffer pointer to zero
track
in buffer

buffer pointer to zero
counter for side-sector blocks
track number
in buffer

greater than or equal to 3?
change buffer
table of error messages
00
, oK'
error numbers of ' read error'
'Read'
pointer to (error52
pointer to 'file'
, too largE'
C5
50
pointer to 'record , and 'not
, presenT'
51
'Overflow in'
pointer to 'record'
error numbers of ' write error'
pointer to 'write' and 'error
26
pointer to 'write'

,

,

Anatomy of the 1541 Disk Drive
E535
E540
E541
E542
E545
E546
E54B
E551
E552
E553
E556
E557
E558
E55F
E560
E561
E566
E567
E568
E570
E572
E57A
E582
E589
E58A
E58D
E590
E593
E594
E594
E59F
E5AO
E5AA
E5AB
E5AE
E5AF
E5BO
E5Bl
E5B6
E587
E5BF
E5C4
E5C5
E5CA
E5CB
E5D5
E5D6
E5DB
E5DC
E5El
E5E2
E5E6
E6E7
E5EB
E5EC

20
29
88
20
85
30
D3
89
60
8A
63
83
20
64
83
20
85
65
CE
66
C9
54
20
61
83
39
83
01
83
53
70
CE
71

C4
89
72
88
20
73
C3
56
74
C4
06
20
09
C5
OA
D7
03
C6
04
CF
05
CD

,

50 52 4F 54 45 43 54 20 4F CE
protect oN'
29
pointer to 'disk'
, id'
49 85
, mismatch'
pointer to
error numbers for 'syntax error'
31 32 33 34
'Syntax'
59 4E 54 41 58
, error'
pointer to
60
ptrs to 'write', 'file' & 'open'
03 84
63
pointer to 'file'
, existS'
45 58 49 53 54 D3
64
pointer to 'file'
, type'
54 59 50 45
pointer to 'mismatch'
65
'No block'
4F 20 42 4C 4F 43 CB
'illegal track or sector'
67
,
'Illegal
4C 4C 45 47 41 4C 20
'track or'
52 41 43 4B 20 4F 52
'sectoR'
53 45 43 54 4F D2
61
pointer to I fi Ie I , 1 not' & 'open'
06 84
error nos. for 'file not found'
62
ptrs to 'file', 'not' & 'found'
06 87
01
pointer to 'f i 1e'
20 53 43 52 41 54 43 48 45 C4
' s scratcheD'
70
4F 20 43 48 41 4E 4E 45 CC 'No channeL'
71
'Dirt
49 52
pointer to 'error'
72
pointer to 'disk'
, fulL'
46 55 4C CC
73
,
'Cbm dos
42 4D 20 44 4F 53 20
32 2E 36 20 31 35 34 Bl 'v2.6 1541'
74
'Drive'
42 49 56 45
pointer to 'not'
,
readY'
52 45 41 44 D9
52 52 4F D2

'ErroR'

52 49 54 C5

'''lritE'

49 4C C5

'FilE'

50 45 CE

'OpeN'

49 53 4D 41 54 43 C8

'MismatcH'
205

Anatomy of the 1541 Disk Drive
E5F4
E5F5
E5F8
E5F9
E5FE
E5FF
E603
E604

06
CE
07
C6
08
C4
OB
D2

4F D4

'NoT'

4F 55 4E C4

'FounD'

49 53 CB

' DisK'

45 43 4F 52 C4

'RecorD'

******************************
E60A
48
PHA
E60B
86 F9
STX $F9
E600
8A
TXA
E60E
OA
ASL A
E60F
AA
TAX
E610
B5 06
LOA $06,X
E612
85 80
STA $80
E614
B5 07
LOA $07,X
E616
85 81
STA $81
E618
68
PLA
E619
29 OF
ANO #$OF
E61B
FO 08
BEO $E625
E610
C9 OF
CMP jI$OF
E61F
00 06
BNE $E627
E621
A9 74
LOA #$74
E623
00 08
BNE $E620
E625
A9 06
LOA #$06
E627
09 20
ORA #$20
E629
AA
TAX
E62A
CA
DEX
E62B
CA
OEX
E62C
8A
TXA
E620
48
PHA
E62E
AD 2A 02
LOA $022A
E631
C9 00
CMP #$00
E633
00 OF
BNE $E644
E635
A9 FF
LOA #$FF
E637
80 2A 02
STA $022A
E63A
68
PLA
E63B
20 C7 E6
JSR $E6C7
E63E
20 42 00
JSR $0042
£641
4C 48 E6
JMP $£648

E644
E645
E648
£64B
E64D
E650
E653
E656
E658
E65A
£65C
£65D

68
20
20
A9
80
20
20
A9
85
A2
9A
A5

C7
BO
00
F9
2C
OA
00
A3
45

84

E6
C1
02
C1
04

PLA
JSR
JSR
LOA
STA
JSR
JSR
LOA
STA
LOX
TXS
LOA

$£6C7
$ClBD
#$00
$02F9
$C12C
$04DA
#$00
$A3
#$45

prepare error number and messagl
save error code
drive number
times 2
as pointer
get track
and sector number
get error code back
isolate bits 0-3
zero, then 24, , read error'
15?
74, 'drive not ready'
6
add $20
subtract two
save error number
number of the disk command
OPEN or VALIDATE?
no
get error number back
generate error message
load BAM
set error message
set error message
erase input buffer
erase error flag
turn LED off
close channels 17 and 18
input buffer pointer to zero
initialize stack pointer
secondary address

S84
206

Anatomy of the 1541 Disk Drive
E65F
E661
E663
E665
E667
E668
E66A
E66C
E66E
E670
E672
E675
E677
E679
E67B
E67D

29
85
C9
FO
78
A5
DO
A5
DO
A6
BD
C9
FO
29
85
4C

OF
83
OF
31
79
lC
7A
10
83
2B 02
FF
IF
OF
82
8E E6

AND
STA
CMP
BEQ
SEI
LDA
BNE
LDA
BNE
LDX
LDA
CMP
BEO
AND
STA
JMP

#$OF
$83
#$OF
$E698

IS?
yes, command channel

$79
$E688
$7A
$E680
$83
S022B,X
#$FF
$E698
#$OF
$82
$E68E

******************************

E680
E683
E686

20 EB DO
20 4E EA
DO 06

JSR SDOEB
JSR $EA4E
BNE $E68E

******************************

E688
E68B
E68E
E691
E693
E695
E698

20
20
20
C9
BO
20
4C

07
4E
25
04
03
27
E7

Dl
EA
Dl
D2
EB

JSR
JSR
JSR
CMP
BCS
JSR
JMP

$DI07
$EA4E
$D125
#S04
$E698
$D227
$EBE7

******************************

E69B
E69C
E69E
E69F
F6Al
E6A3
E6A4
A6A6
E6A7
E6AA

AA
A9 00
F8

EO 00
FO 07
18

69 01
CA
4C 9F F,6
D8

TAX
LDA
SED
CPX
BEQ
CLC
ADC
DEX
JMP
CLD

AA
4A
4A
4A
4A
20
SA
29
09
91
C8

B4 E6
OF
30
AS

TAX
LSR
LSR
LSR
LSR
JSR
TXA
AND
ORA
STA
INY

addr

no
channel number
TALK
open channel for reading
accept byte
LISTEN
open channel for writing
accept byte
verify file type
file type REL?
yes
close channel
convert hex to decimal (2 bytes)

#SOO
#SOO
SE6AA

convert hex to BCD

#S01
SE69F

******************************

E6AB
E6AC
E6AD
E6AE
E6AF
E680
E6B3
E6B4
E6B6
E6B8
E6BA

LISTEN act i ve?
yes
TALK active?
yes
channel number
open channel to this second.

A
A
A
A
$E6B4

divide BCD number into two bytes
shift hi-nibble down
convert to ASCI I

#$OF
#$30
($A5),Y

207

erase top 4 bits
add '0 '
write in buffer
increment buffer pointer

Anatomy of the 1541 Disk Drive
E6BB

60

RTS

******************************
E6BC
20 23 Cl
JSR SC123
E6BF
A9 00
LDA IISOO
AO 00
E6C1
LDY IISOO
84 80
STY S80
E6C3
84 81
STY S81
E6C5

write 'ok' in buffer
erase error flag
error number 0

******************************
E6C7
AO 00
LOY IISOO
A2 D5
LDX IISD5
E6C9
86 A5
E6C8
STX SA5
A2 02
LDX IIS02
E6CD
E6CF
86 A6
STX SA6
20 AB E6
E6Dl
JSR SE6AB
A9 2C
LDA jlS2C
E6D4
STlI (S1I5),Y
9A A5
E6D6
ED6B
C8
INY
E6D9
AD D5 02
LDlI S02D5
8D 43 02
E6DC
STA S0243
E60F
8A
TXA
20 06 E7
E6EO
JSR SE706
A9 2C
E6E3
LOA IIS2C
E6E5
STA (S1I5),Y
91 A5
C8
INY
E6E7
A5 80
LDA S80
E6EB
E6EA
20 98 E6
JSR SE69B
A9 2C
LDA 1I$2C
E6ED
E6EF
STA (SA5),Y
91 A5
E6Fl
C8
INY
E6F2
A5 Bl
LDA $81
20 9B E6
JSR SE69B
E6F4
88
OEY
E6F7
E6FB
9B
TYA
E6F9
IB
CLC
E6FA
69 D5
AOC lI$05
STA $0249
E6FC
8D 49 02
E6FF
INC $1I5
E6 AS
E701
A9 88
LDA #S88
E703
85 F7
STA $F7
E705
60
RTS

error message in buffer
buffer pointer

******************************
E706
All
TAX
E707
A5 86
LOA $86
E709
48
PHA
E70A
AS 87
LOA $87
PHA
E70C
48
A9 FC
LOA #$FC
E70D
E70F
85 86
STA lIS E4
E713
85 87
STA $87
E7l5
8A
TXA
E716
A2 00
LOX #$00
E718
Cl 86
CMP ($86,X)

write error message to buffer
error code to X

208

track 0
sector 0

pointer $A5/S1I6 TO $205
error

* to

.,. comma

lISCII and in buffer

write in buffer
increment buffer pointer
first digit of the disk status
in output register
error number in accumulator
error message in buffer
I,' comma
write in buffer
and increment buffer pointer
track number
to ASCII and in buffer
• " comma
wri te in buffer
increment buffer pointer
sector
convert to ASCII and in buffer

end pointer
set READ flag

preserve pointer $86/$87

start of the error messages
error number in accumulator
compare with error no in table

Anatomy of the 1541 Disk Drive
E7lA
E7lC
E71D
E720
E722
E725
E727
E729
E72B
E72D
E72F
E731
E733
E735
E736
E739
E73A

FO
48
20
90
20
90
A5
C9
90
DO
AO
C5
90
68
4C
68
4C

21

E73D
E740
E742
E745
E748
E74A
E74D
E74E
E750
E751
E753

20
90
20
20
90
20
68
85
68
85
60

67
FB
54
67
F8
54

75 E7
05
75 E7
FB
87
E6
08
OA
OA
86
04
18 E7
4D E7
E7
E7
E7
E7

87
86

BEO
PHA
JSR
BCC
JSR
BCC
LDA
CMP
BCC
BNE
LDA
CMP
BCC
PLA
JMP
PLA
JMP
JSR
BCC
JSR
JST
BCC
JSR
PLA
STA
PLA
STA
RTS

$E73D
$E775
$E727
$E775
$E722
$87
#SE6
$E735
$E739
#SOA
$86
$E739

bit 7 into carry and erase
not set?
bit 7 into carry
wait for character with bit 7 set

$E7l8

no, continue

$E74D

done

$E767
$E73D
$E754
$E767
$E742
$E754

get a character, bit 7 in carry
wait for character with bit 7 set
and write in buffer
get next character
wait for character with bit 7 set
put character in buffer

$E60A, check to end of table

$87
get pointer $86/$87 back
$86

******************************

E754
E756
E758
E759
E75B
E75D
E75E
E75F
E762
E763
E765
E766

C9 20
SO OB
AA
A9 20
91 A5
C8
8A
20 06 E7
60
91 A5
C8
60

CMP #$20
BCS $E763
TAX

LDA
STA
INY
TXA
JSR
RTS
STA
INY
RTS

#$20
($AS),Y
SE706
($A5),Y

******************************

E767
E769
E76B
E76D
E76F
E770
E772
E774

E6
DO
E6
Al
OA
Al
29
60

86
02
87
86
86
7F

INC
BNE
INC
LDA
ASL
LDA
AND
RTS

$86
$E76D
$87
($86,X)
A
($86,X)
#$7F

******************************

209

get character and in buffer
• • blank
greater, then write in buffer
save code
blank
write in buffer
increment buffer pointer
code in accumulator
output previous text
write character in buffer
and increment pointer
get a char of the error message
increment pointer
get character
bit 7 into carry
get character
erase bit 7
increment pointer

Anatomy of the 1541 Disk Drive
E77S
E778
E77A
E77C
E77E

20
E6
DO
E6
60

6D E7
86
02
87

JSR
INC
BNE
INC
RTS

bit 7 into carry

SE76D
S86
$E77E
S87

increment pointer

******************************
E77F
60
RTS
******************************

E780
E783
E784
E786
E788
E789
E78B
E78D
E78E
E791
E793
E795
E798
E79B
E79D
E7AO

AD
AA
29
Fa
8A
29
FO
58
AD
29
FO
EE
EE
A9
80
4C

00 18
04
F7
01
F2
00
05
F9
78
74
2A
00
A8

18
02
02
02
E7

LDA
TAX
AND
BEO
TXA
AND
BEO
CLI
LDA
AND
BNE
INC
INC
LDA
STA
JMP

S1800

check for AUTO-start
read IEEE port

#$04
$E77F

isolate 'CLOCK IN' bit
not set, then done

#$01
SE77F

isolate 'DATA IN' bit
not set, then done

$1800
#$05
SE78E
S0278
$0274
#S2A
$0200
SE7A8

load IEEE port
test 'DATA IN' and 'CLOCK IN'
wait until both set
file name
character in the input line
'* , as filename
write in buffer

******************************

E7A3
E7A5
E7A8
E7AB
E7AE
E7AF
E7Bl
E7B4
E7B6
E7B8
E7BB
E7BE
1':7CO
E7C2
E7C5
E7C6
E7C9
E7CC
E7CE
E7D1
E703
E705
E708
E7DA
E7DC
E70F
E7E1

A9
20
20
AD
48
A9
80
A9
8S
20
AD
DO
A9
20
68
80
AD
85
AO
85
A9
20
A9
85
20
85
20

8D
68 C2
58 F2
78 02
01
78
FF
86
4F
80
05
39
C8
78
80
80
85
81
03
77
00
87
39
88
4B

02
C4
02
C1
02
02
02
D4
E8
E8

LDA
JSR
JSR
LOA
PHA
LDA
STA
LOA
STA
JSR
LOA
BNE
LOA
JSR
PLA
STA
LDA
STA
LDA
STA
LOA
JSR
LOA
STA
JSR
STA
JSR

#S8D
SC268
$F2S8
S0278

'& '

-

command

check command line to end
(RTS)
number of file names
save

#$01
S0278
iSFF
S86
SC44F
$0280
SE7C5
#$39
SClC8

file name
find file
found?
39, ' file not found'
get number of file names back

S0278
S0280
S80
$0285
S81
#$03
$D477
#$00
$87
$E839
$88
S884B

track
and sector
file type 'USR'
buffer allocated, read 1st bloc
erase checksum
get byte from file
save as start address 10
form checksum
210

Anatomy of the 1541 Disk Drive
E7E4
E7E7
E7E9
E7EC
E7EE
E7FO
E7F2
E7F3
E7F5
E7F6
E7F8
E7FA
E7FD
E7FF
E802
E805
E807
E809
E80C
E80E
E80F
E811
E813
E8l5
E8l7
E819
E8lB
E8lE
E820
E822
E824
E827
E829
E82C
E82E
E830
E831
E833
E834
E836
E839
E83C
E83E
E840
E843
E845
E848
E84A

20
85
20
A5
FO
A5
48
A5
48
A9
85
20
85
20
20
AO
91
20
A5
18
69
85
90
E6
C6
DO
20
A5
C5
FO
20
A9

20
A5
DO
68
85
68
85
6C
20
A5
DO
20
A9
20
A5
60

39 E8
89
4B E8
86
OA
88
89
00
86
39
8A
4B
39
00
88
4B
88

E8
E8
E8
E8

01
88
02
89
8A
E7
35 CA
85
87
08
3E DE
50
45 E6
F8
A8
89
88
88
35
F8
08
3E
51
45
85

00
CA
DE
E6

JSR
STA
JSR
LOA
BEO
LOA
PHA
LDA
PHA
LOA
STA
JSR
STA
JSR
JSR
LOY
STA
JSR
LDA
CLC
AOC
STA
BCC
INC
OEC
BNE
JSR
LDA
CMP
BEO
JSR
LOA
JSR
LOA
BNE
PLA
STA
PLA
STA
JMP
JSR
LOA
BNE
JSR
LDA
JSR
LDA
RTS

$E839
$89
$E84B
$86
$E7FA
$88

get byte from file
as start address hi
form checksum

save program start address
$89
#$00
$86
$E839
$8A
$E84B
$E839
#$00
($88),y
$E84B
$88
UOI
$88
$E8l7
$89
$8A
$E802
$CA35
$85
$87
$E82C
$OE3E
#$50
$E645
$F8
$E7D8

get byte from file
save as counter
form checksum
get byte from file
save as program bytes
form checksum

increment $88/$89
decrement pointer
get next byte
data byte
equal to checksuro?
yes
transmit param to disk controller
50, 'record not present'
end?
no, next data block

$89
get program start address back
$88
($0088)
$CA35
$F8
$E848
$DE3E
#$51
$E645
$85

******************************
E84B
A8
CLC
E84C
65 87
ADC $87
E84E
69 00
ADC #$00
E850.
85 87
STA $87
60
E852
RTS
211

and execute program
get byte from file
end?
no
transmit param to disk controller
51, 'overflow in record'
data byte
generate checksum

Anatomy of the 1541 Disk Drive

******************************

E853
E856
E858
E85A

AD 01 18
A9 01
85 7C
60

LDA $1801
LDA #$01
STA $7C
RTS

set flag for 'ATN received'

******************************

E85B
E85C
E85E
E860
E862
E864
E866
E867
E869
E86B
E86D
E870
E873
E876
E878
E87B
E87E
E880
E882
E884
E887
E889
E88B
E88D
E88F
E891
E893
E895
E897
E899
E89B
E89D
E89F
E8A1
E8A3
E8A5
E8A7
E8A9
E8AB
E8AD
E8AF
EBB1
EBB3
EBB5
E8B7
E8B8
EBBA

78
A9
85
85
85
A2
9A
A9
85
85
20
20
AD
09
8D
AD
10
29
DO
20
C9
DO
A9
85
FO
C9
DO
A9
85
FO
C5
DO
A9
85
A9
85
FO
C5
DO
A9
85

00
7C
79
7A
45
80
F8
7D
B7
A5
00
10
00
00
57
04
F7
C9
3F
06
00
79
71

5F
06
00
7A
67
78
OA
01
7A
00
79
29
77
OA
01
79
A9 00
85 7A
FO IB
AA
29 60
C9 60

E9
E9
18
18
18

E9

SEI
LDA
STA
STA
STA
LDX
TXS
LDA
STA
STA
JSR
JSR
LDA
ORA
STA
LDA
BPL
AND
BNE
JSR
CMP
BNE
LDA
STA
BEO
CMP
BNE
LDA
STA
BEO
CMP
BNE
LDA
STA
LDA
STA
BEO
CMP
BNE
LDA
STA
LDA
STA
BEO
TAX
AND
CMP

IRO routine for serial bus
read port A, erase IRO flag

#$00
$7C
$79
$7A
#$ 45

servicing the serial bus
erase flag for • ATN received'
erase flag for LISTEN
erase flag for TALK
ini tiali ze stack pointer

#$80
$F8
$7D
$E9B7
$E9A5
$1800
jI$10
$1800
$1800
$E8D7
#$ 04
$E87B
$E9C9
#$3F
$E891
jI$OO
$79
$E902
#$5F
$E89B
#$00
$7A
$E902
$78
$E8A9
#$01
$7A
jI$OO
$79
$E8D2
$77
$E8B7
jI$Ol
$79
#$ 00
$7A
$E8D2

erase end
erase EOI
CLOCK OUT
DATA OUT,

flag
flag
10
bit ' 0 I , hi

switch data lines to input
read IEEE port
EO!?
CLOCK IN?
no
get byte from bus
un1isten?
no
reset flag for LISTEN
untalk?
no
reset flag for TALK
TALK address?
no
set flag for TALK
reset flag for LISTEN
LISTEN address?
no
set flag for LISTEN
reset flag for TALK

#$60
#$60

set bit 5 and 6

212

Anatomy of the 1541 Disk Drive
E8BC
E8BE
E8BF
E8Cl
E8C3
E8C5
E8C7
E8C9
E8CB
E8CD
E8CE
E8Dl
E8D2
E8D5
E8D7
E8D9
E8DB
E8DE
E8EO
E8E3
E8E5
E8E7
E8EA

DO
8A
85
29
85
AS
29
C9
DO
58
20
78
2C
30
A9
85
AD
29
8D
AS
FO
20
4C

ESED
E8EF
ESFl
ESF4
ESF7
E8FA
ESFD
ESFF
E902
E905
E907

AS
FO
20
20
20
4C
A9
SD
2C
10
30

3F
84
OF
83
84
FO
EO
35
CO DA
00
AD
00
7D
00
EF
00
79
06
2E
E7
7A
09
9C
AE
09
4E
10
00
00
DO
F9

18

18
18
EA
EB

E9
E9
E9
EA
IS
18

BNE
TXA
STA
AND
STA
LDA
AND
CMP
BNE
CLI
JSR
SEI
BIT
BMI
LDA
STA
LDA
AND
STA
LDA
BEQ
JSR
JMP
LDA
BEQ
JSR
JSR
JSR
JMP
LDA
STA
BIT
BPL
BMI

$E8FD

no

$84
#$OF
$83
$84
#$FO
#$EO
$E902

byte is secondary address

$DACO

CLOSE routine

channel number
CLOSE?

$1800
$E884
#$00
$7D
$1800
#$EF
$1800
$79
$E8ED
$EA2E
$EBE7

set EOI
IEEE port
switch data lines to output
LISTEN active?
no
receive data
to delay loop

$7A

TALK active?
no
DATA OUT, bit 11· , 10
CLOCK OUT hi
send data
to delay loop
either TALK or LISTEN,ignore byte
switch data lines to input

$ES~'A

$E99C
$E9AE
$E909
$EME
#$10
$lSOO
$1800
$ESD7
$E902

wait for handshake

*******************.**********
7S
E909
SEI
E90A
20 EB DO
JSR $DOEB
E90D
BO 06
BCS $E9l5
A6 S2
LOX $82
E90F
E911
B5 F2
LOA $F2,X
E913
30 01
BMI $E916
60
RTS
E915
E916
JSR $EA59
20 59 EA
E919
20 CO E9
JSR $E9CO
29 01
AND *$01
E91C
08
PHP
E91E
E91F
20 B7 E9
JSR $E9B7
E922
28
PLP
E923
FO 12
BEQ $E937
E925
20 59 EA
JSR $EA59
E928
20 CO E9
JSR $E9CO
E92B
29 01
AND #$01
E92D
00 F6
BNE $E925

213

send data
open channel for read
channel active
channel number
set READ flag?
yes
check EOI
read IEEE port
isolate data bit
and save
CLOCK OUT 10
check EOI
read IEEE port
isolate data bit

Anatomy of the 1541
E92F
E931
E933
E935
E937
E93A
E93D
E93F
E941
E944
E947
E949
E84B
E94E
E951
E954
E956
E958
E9SA
E95C
E95F
E961
E963
E965
E968
E969
E96C
E96E
E971
E973
E976
E979
E97B
E97D
E980
E983
E985
E987
E98A
E98D
E98F
E991
£992
E995
E996

A6 82

B5
29
DO
20
20
29
DO
20
20
29
FO
20
20
20
29
DO
A9
8S
20
29
DO
A6
BO
6A
9D
BO
20
DO
20
20
AS
DO
20
20
C6
DO
20
20
29
FO
58
20
78
4C

E999

4C 4E EA

F2
08
14
59
CO
01
F6
59
CO
01
F6
AE
59
CO
01
F3
08
98
CO
01
36
82
3E
3E
OS
AS
03
9C
B7
23
03
F3
FB
98
D5
59
CO
01
F6

EA
E9
EA
E9
E9
EA
E9

E9

02
02
E9
E9
E9
FE
FE
EA
E9

AA D3

OF E9

Dis~

Drive

LDX
LDA
AND
BNE
JSR
JSR
AND
BNE
JSR
JSR
AND
BEO
JSR
JSR
JSR
AND
BNE
LDA
STA
JSR
AND
BNE
LDX
LDA
ROR
STA
BCS
JSR
BNE
JSR
JSR
LDA
BNE
JSR
JSR
DEC
BNE
JSR
JSR
AND
BEO
CLI
JSR
SEI

$82
$F2,X
#$08
$E94B
$EA59
$E9CO
#$01
$E937
$EA59
$E9CO
#$01
$E941
$E9AE
$EA59
$E9CO
#$01
$E94B
#$08
$98
$E9CO
#$01
$E999
$82
$023E,X
A
$023E,X
$E973
$E9A5
$E976
$E99C
$E9B7
$23
$E980
$FEF3
$FEFB
S98
$E95C
$EA59
$E9CO
#$01
$E987
$D3AA

get next data byte

J~lP

$E90F

and output

JMP $EA4E

channel number

check EOI
read IEEE port
isolate data bit
check EOI
read IEEE port
isolate data bit
CLOCK OUT hi
check EOI
read IEEE port
isolate data bit
counter to 8 bits for serial
transmission
read IEEE port
isolate data bit

lowest bit in carry
set bit
DATA OUT, output bit ' 0'
absolute jump
DATA OUT, output bit ' I'
set CLOCK OUT
delay for serial bus
set DATA OUT and CLOCK OUT
all bits output?
no
check EOI
read IEEE port
isolate data bit

to delay loop

******************************
E99C
AD 00 18
LDA $1800
E99F
29 FD
AND #$FD
E9A1
8D 00 18
STA $1800
E9A4
60
RTS

output bit 'I'

******************************

DATA OUT hi

214

DATA OUT 10

Anatomy of the 1541 Disk Drive
E9A5
E9A8
E9AA
E9AD

AD 00 18
09 02
80 00 18
60

LOA $1800
ORA #$02
STA $1800
RTS

output bit '0 '

******************************

E9AE
E9B1
E9B3
E9B6

AD 00 18
09 08
80 00 18
60

LOA $1800
ORA #$08
STA $1800
RTS

set bit 3

******************************

E9B7
E9BA
E9BC
E9BF

AD 00 18
29 F7
80 00 18
60

LOA $1800
AND #$F7
STA $1800
RTS

AD 00 18
CD 00 18
DO F8
60

CLOCK OUT 10
erase bit 3

******************************

E9CO
E9C3
E9C6
E9C8

CLOCK OUT hi

LOA $1800
CMP $1800
BNE $E9CO
RTS

read IEEE port
read port
wait for constants

******************************

E9C9
E9CB
E9CD
E9DO
E9D3
E9D5
E9D7
E9DA
E9DC
E9DF
E9E2
E9E5
E9E7
E9E9
E9EC
E9EE
E9FO
E9F2
E9F5
E9F7
E9FB
E9FA
E9FD
EAOO
EA03
EA05
EA07
EA09
EAOB
EAOE
EAI0

A9
85
20
20
29
DO
20
A9
80
20
AD
29
DO
20
29
FO
DO
20
A2
CA
DO
20
20
20
29
FO
A9
85
AD
49
4A

08
98
59
CO
04
F6
9C
01
05
59
00
40
09
CO
04
EF
19
A5
OA
FD
9C
59
CO
04
F6
00
F8
00
01

EA
E9
E9
18
EA
18
E9

E9

E9
EA
E9

18

LOA
STA
JSR
JSR
AND
BNE
JSR
LOA
STA
JSR
LOA
AND
BNE
JSR
AND
BEQ
BNE
JSR
LOY
DEX
BNE
JSR
JSR
JSR
AND
BEO
LOA
STA
LOA
EaR
LSR

#$08
$98
$EA59
$E9CO
#$04
$E9CD
$E99C
#$01
$1805
$EA59
$1800
#$40
$E9F2
$E9CO
#$04
$E9DF
$EAOB
$E9A5
#$OA

bit counter for serial output
check EOI
read IEEE port
CLOCK IN?
no, wait
DATA OUT, bit ' I'
set timer
check EOI
timer run down?
yes, EOI
read IEEE port
CLOCK IN?
no, wait
DATA OUT bit '0' hi
10
delay loop, approx 50 micro sec.

$E9F7
$E99C
$EA59
$E9CO
#$04
$E9FD
#$00
$F8
$1800
#$01
A

DATA OUT, bit '1' , 10
check EOI
read IEEE
CLOCK IN?
no, wait
set Eor flag
IEEE port
invert data byte

215

Anatomy of the 1541 Disk Drive
EAll
EA13
EA15
EA16
EAl7
EA18
EAIA
EAID
EA20
EA22
EA24
EA26
EA28
EA2B
EA2D

29
DO
EA
EA
EA
66
20
20
29
FO
C6
DO
20
A5
60

02
F6

85
59 EA
CO E9
04
F6
98
E3
A5 E9
85

AND
BNE
NOP
NOP
NOP
ROR
JSR
JSR
AND
BEQ
OEC
BNE
JSR
LOA
RTS

#$02
$EAOB

CLOCK IN?

$85
$EA59
$E9CO
#$04
$EAIA
$98
$EAOB
$E9A5
$85

prepare next bit
check EOI
read IEEE port
CLOCK IN?
no
decrement bit counter
all bits output?
DATA OUT, bit ' 0 1 , hi
load data byte again

******************************

78
20
BO
B5
6A
BO
A5
29
C9
FO
4C

EA44
EA47
EA48
EMB

20 C9 E9
58
20 B7 CF
4C 2E EA

JSR $E9C9
CLI
JSR $CFB7
JMP $EA2E

EA4E
EA50
EA53

A9 00
80 00 18
4C E7 EB

LOA #$00
STA $1800
JMP $EBE7

reset IEEE port
to wait loop

EA56

4C 5B E8

JMP $EB58

to serial bus main loop

07 01
05
F2
DB
84
FO
FO
03
4E EA

SEI
JSR
RCS
LOA
ROR
BCS
LOA
ANO
CMP
BEO
JMP

accept data from serial bus

EA2E
EA2F
EA32
EA34
EA36
EA37
EA39
EA3B
EA30
EA3F
EMI

$0107
$EA39
$F2,X
A
$EM4
$84
#$FO
#$FO
$EM4
$EME

open channel for writing
channel not active?
WRITE flag
not set?
secondary address
OPEN command?
yes
to wait loop
get data byte from bus
and write in buffer
to loop beginning

******************************

EA59
EA5B
EA5D
EA60

A5
FO
AD
10

7D
06
00 18
09

EA62

60

RTS

EA63
EA66
EA68

AD 00 18
10 FA
4C D7 E8

LDA $1800
BPL $EA62
JMP $E807

LOA
BEO
LOA
BPL

$70
$EA63
$lROO
$EA6B

EOI received?
yes
IEEE port

IEEE port
set EOI, serve serial bus

******************************

EA6E
EA70

A2 00
2C

LOX #$00
.BYTE $2C
216

blink LED for hardware defects
blink once, zero page

Anatomy of the 1541 Disk Drive
EA7l
EA73
EA74
EA75
EA77
EA7A
EA7D
EA7E
EA7F
EA81
EA83
EA84
EA86
EAB9
EABB
EA8E
EABF
EA90
EA92
EA94
EA95
EA97
EA98
EA9A
EA9C
EA9E

A5
9A
BA
A9
OD
4C
98
18
69
DO
88
DO
AD
29
8D
9B
IB
69
DO
B8
DO
CA
10
EO
DO
FO

6F
08
00 lC
EA FE
01
FC
F8
00 Ie
F7
00 lC
01
FC
FB
DB
FC
FO
D4

LDX
TXS
TSX
LDA
ORA
JMP
TYA
CLC
ADC
ENE
DEY
BNE
LDA
AND
STA
TYA
CLC
ADC
BNE
DEY
BNE
DEX
BPL
CPX
BNE
BEO

$6F

blink X+l times for RAM/ROM err

#$08
$lCOO
$FEEA

select LED bit in the port
turn LED on, back to $EA7D

#$01
$EA7F
$EA7E
$lCOO
#$F7
$lCOO

turn LED off

#$01
$EA90

delay loop

$EABF
$EA75
#$FC
$EA8E
$EA74

wait for delay
turn LED on again

******************************

EAAO
EAAI
EAA2
EAA4
EAA7
EAA8
EAAA
EAAC
EAAD
EAAF
EABO
EAB2
EAB3
EAB5
EAB7
EAB9
EABA
EABC
EABE
EACO
EAC2
EAC4
EAC6
EAC7
EAC9
EACB
EACD

78
D8
A2
BE
E8
AO
A2
BA
95
E8
DO
8A
D5
DO
F6
C8
DO
D5
DO
94
B5
DO
EB
DO
E6
86
A9

FF
03 IB
00
00
00
FA
00
B7
00
FB
00
AE
00
00
AB
E9
6I"

76
00

SEl
CLD
LDX
STX
lNX
LDY
LDX
TXA
STA
INX
BNE
TXA
CMP
BNE
INC
INY
BNE
CMP
BNE
STY
LDA
BNE
lNX
BNE
INC
STX
LDA

#$FF
SlB03

RESET routine

port A to output

#SOO
#SOO
$OO,X

erase zero page

$EAAC
$OO,X
$EA6E
$OO,X

is byte erased?
no, then to error display (blink)

SEAB7
$OO,X
$EA6E
$OO,x
$OO,X
$EA6E

error
error

$EAB2
$6F
$76
#$00
217

Anatomy of the 1541 Disk Drive
EACF
EADI
EAD2
EAD4
EAD5
EAD7
EAD9
EADA
EADC
EADD
EADF
EAEI
EAE2
EAE4
EAE6
EAE8
EAEA
EAEe
EAEE
EAFO
EAF2
EAF3
EAF4
EAF6
EAF8
EAF9
EAFB
EAFD
EAFE
EBOO
EB02
EB04
EB05
EB06
EB07
EB09
EBOB
EBOD
EBOF
EBll
EBl3
EB15
EB17
EB18
EB1A
EBlB
EBID
EB1F

85
A8
A2
18
C6
71
C8
DO
CA
DO
69
AA
C5
DO
EO
DO
A9
85
E6
A2
98
18
65
91
C8
DO
E6
CA
DO
A2
C6
88
98
18
65
Dl
DO
49
91
51
91
DO
98
DO
CA
DO
FO
4C

EB22
EB24
EB25
EB28
EB2A
EB2D

A2
9A
AD
29
8D
A9

75
20
76
75
FB
F6
00
76
39
CO
DF
01
76
6F
07
76
75
F7
76
F2
07
76

76
75
12
FF
75
75
75
08
EA
E5
03
71 EA
45
00 lC
F7
00 lC
01

STA
TAY
LDX
CLC
DEC
ADC
INY
BNE
DEX
BNE
ADC
TAX
CMP
BNE
CPX
BNE
LDA
STA
INC
LDX
TYA
CLC
ADC
STA
INY
BNE
INC
DEX
BNE
LDX
DEC
DEY
TYA
CLC
ADC
CMP
BNE
EOR
STA
EOR
STA
BNE
TYA
BNE
DEX
BNE
BEO
JMP
LDX
TXS
LDA
AND
STA
LDA

$75
#$20

test 32 pages

$76
($75) ,Y
$EAD7
$EAD5
#$00

test ROM

$76
$EBIF

ROM error

#$CO

$EAC9
#$01
$76
$6F'
#$07

test RAM, beginning at page 7

$76
($75) ,Y
$EAF2
$76
$EAF2
#$07
$76

$76
($75),Y
$EBIF
#$FF
($75),Y
($75),Y
($75) ,y
$EB1F

RAM error

RAM error

$EB04
$EB02
$EB22
$EA7l

continue test
ok
to error display

#$45
initialize stack pointer
$ICOO
#$F7

turn LED off

$lCOO

#$01
218

Anatomy of the 1541 Disk Drive
EB2F
EB32
EB34
EB37
EB3A
EB3D
EB3F
EB40
EB41
EB42
EB43
EB45
EB47
EB49
EB4B
EB4D
EB4F
EB51
EB53
EB54
EB57
EB59
EB5A
EB5B
EB50
EB5F
EB61
EB63
EB64
EB66
EB68
EB69
E86B
EB6D
EB6E
EB70
EB72
EB74
EB76
EB79
EB7A
EB7C
EB7E
EB80
EB82
EB84
EBB5
EB87
EB89
EBBB
EB8D
EB8F
EB91
EB93
EB95

8D
A9
8D
8D
AO
29
OA
2A
2A
2A
09
85
49
85
A2
AO
A9
95
E8
B9
95
E8
C8
CO
DO
A9
95
E8
A9
95
E8
A9
95
E8
A9
95
A9
A2
9D
CA
10
A2
95
95
95
CA
10
A9
85
A9
85
A9
85
85
A9

OC
82
OD
OE
00
60

18
18
18
18

4B
78
60
77
00
00
00
99
EO FE
99
05
FO
00
99
02
99
D5
99
02
99
FF
12
2B 02
FA
05
A7
AE
CD
F7
05
AB
06
AC
F'F
AD
B4
05

STA
LOA
STA
STA
LDA
AND
ASL
ROL
ROL
ROL
ORA
STA
EOR
STA
LOX
LDY
LDA
STA
INX
LDA
STA
INX
INY
CPY
BNE
LDA
STA
INX
LDA
STA
INX
LDA
STA
INX
LDA
STA
LDA
LDX
STA
DEX
BPL
LDX
STA
STA
STA
DEX
BPL
LOA
STA
LDA
STA
LDA
STA
STA
LDA

S180C
#S82
S180D
S180E
S1800
#S60
A
A

CAl (ATN IN) trigger on pas edge

A

rotate to bit positions 0 & 1

interrupt possible through ATN IN
read port B
isolate bits 5 & 6 (device #)

A
#S48
S78
#S60
S77
#SOO
#SOO
#SOO
S99,x

add offset from 8 + S40 for TALK
device number for TALK (send)
erase bit 6, set bit 5
device number + S20 for LISTEN

low-byte of buffer address

$F'EEO, Y
$99,x

high byte of address from table
save

#S05
SEB4F'
#$00
S99,X
ptr SA3/$A4 to S200,

input buffer

#S02
S99,X
#$D5
S99,X
#S02
$99,X
#SFF
#S12
$022B,X
SEB76
#$05
SA7,X
SAE,X
$CD,X

pointer SA5/SA6 to S2D5, error
message pointer

fill channel table with SFF

erase buffer table
erase side-sector table

SEB7E
#$05
SAB
#S06
SAC
#SFF
SAD
SB4
#S05

buffer 5
associate with channel 4
buffer 6
associate with channel 5

219

Anatomy of the 1541 Disk Drive
EB97
EB9A
EB9C
EB9F
EBAI
EBA4
EBA6
EBA8
EBAA
EBAC
EBAE
EBBI
EBB3
EBB6
EBB8
EBBA
EBBC
EBBF
EBC2
EBC5
EBC7
EBC9
EBCB
EBCD
EBCF
EBOI
EBD3
EB05
EB07
EBDA
EBDC
EBOF
EBEI
EBE4
EBE7
EBES
EBEB
ERED
EBFO
EBF3
EBF5
EBF7
EBFA
EBFC

SO
A9
SO
A9
80
A9
85
A9
85
A9
80
A9
80
A9
85
85
20
20
20
A9
85
A9
85
A9
85
A9
85
A9
20
A9
8D
A9
8D
20
58
AO
29
SO
AO
FO
A9
80
85
20

3B
84
3A
OF
56
01
F6
88
F7
FO
4F
FF
50
01
lC
10
63
FA
59
22
65
EB
66
OA
69
05
6A
73
Cl
lA
02
00
00
80

02

00
E5
00
55
OA
00
55
67
46

18

02
02

02
02

CB
CE
F2

E6
18
18
E7

18
02
02
Cl

STA
LDA
STA
LOA
STA
LOA
STA
LOA
STA
LOA
STA
LOA
STA
LOA
STA
STA
JSR
JSR
JSR
LOA
STA
LOA
STA
LOA
STA
LOA
STA
LDA
JSR
LOA
STA
LOA
STA
JSR
CLI
LDA
AND
STA
LOA
BEO
LDA
STA
STA
JSR

$023B
*$S4
$023A
*$OF
$0256
*$01
$F6
*$S8
SF7
*$EO
$024F
*$FF
$0250
*$01
SIC
S10
SCB63
$CEFA
$F259
*$22
$65
#$EB
$66
*$OA
$69
H05
$6A
#$73
$E6Cl
#$lA
$1802
#$00
$1800
$E7S0

channel 5 WRITE flag erased
channel 4 WRITE flag set
initialize channel allocation
bit '1 ' equals channel free
WRITE flag
REAO flag
5 buffers free
initialize buffer allocation reg
$24F/$250, 16 bit
flags for WRITE protect
set vector for UO
initialize channel table
intialization for disk controller
pointer $65/$66 to $EB22
step width 10
for sector assignment
5 read attempts
prepare power-up message
73, 'cbm dos v2.6 1541'
bit 1, 3 & 4 to exit
data direction of port B
erase data register
check for auto-start

$lS00
#$E5
$1800
$0255
$EBFF
*$00
$0255
$67
$C146

reset serial port
command flag set?
no
reset command flag
analyze and execute command

******************************

EBFF
ECOO
EC02
EC04
EC07
EC08
ECOA
ECOC
ECOE

58
A5
FO
4C
58
A9
85
A9
85

7C
03
58 E8
OE
72
00
6F

CLI
LDA
REO
JMP
CLI
LOA
STA
LDA
STA

re~

wait loop

$7C
$EC07
SE85B

ATN signal discovered?
no
to IEEE routine

#$OE
$72
#$00
$6F

14
as secondary address
job counter
220

Anatomy of the 1541 Disk Drive
EClO
EC12
EC14
EC17
EC19
EClB
EClD
EClF
EC22
EC23
EC26
EC28
EC29
EC2B
EC2D
EC2F
EC3l
EC34
EC36
EC38
EC39
EC3B
EC3C
EC3E
EC3F
EC42
EC44
EC45
EC47
EC49
EC4B
EC40
EC4F
EC51
EC53
EC55
EC58
EC59
EC5B
EC5C
EC5E
EC60
EC62
EC64
EC66
EC69
EC6A
EC6C
EC6D
EC6F
EC71
EC72
EC75
ECn
EC7A

85
A6
BD
C9
FO
26
85
20
AA
BD
29

70
72
2B 02
FF
10
3F
82
93 OF
5B 02
01

AA

F6
C6
10
AO
B9
10
29
AA
F6
88
10
78
AD
29
48
A5
85
A9
85
A5
FO
AS
FO
20
68
09
48
E6
AS
FO
AS
FO
20
68
09
48
A5

6F
72
E3
04
00 00
05
01
6F
F3
00 1C
F7
7F
86
00
7F
6F
OB
lC
03
13 D3
08
7F
70
DB
ID
03
13 D3
00
86

85 7F

68
AE
Fa
AD
EO

6C 02
21
00 lC
80

STA
LOX
LOA
CMP
BEO
AND
STA
JSR
TAX
LOA
AND
TAX
INC
DEC
BPL
LOY
LDA
BPL
AND
TAX
INC
DEY
BPL
SEI
LDA
AND
PHA
LOA
STA
LDA
STA
LOA
BEO
LOA
BEO
JSR
PLA
ORA
PHA
INC
LDA
BEO
LDA
BEO
JSR
PLA
ORA
PHA
LDA
STA
PLA
LDX
BEO
LDA
CPX

$70
$72
$022B,X
#$FF
$EC2B
#S3F
$82
SDF93

secondary address
channel associated?
no
channel number
get buffer number

$025B,X
#$01

drive number

$6F,X
$72
$EC12
#$04
$OOOO,y
SEC3B
#$01

increment job counter
10 address
continue search
buffer counter
disk controller in action?
no
isolate drive number

$6F ,X

increment job counter

$EC31

next buffer

$ICOO
#$P?

erase LED bit

$7F
$86
#$00
$7F
S6F
$EC5C
SIC
$EC58
$0313

drive 0
job for drive O?
no
write protect for drive O?
no
close all channels to drive 0

#$08

set LED bit

$7F
$70
$EC6D
$10
SEC69
S0313

increment drive number
job for drive I?
no
write protect for drive I?
no
close all channels to drive 1

drive number

#$00
S86
$7F

get drive number back
bit for LED
interrupt counter
to zero?

$026C
$EC98
$lCOa
#S80

221

Anatomy of the 1541 Disk Drive
EC7C
EC7E
EC81
EC84
EC86
EC88
EC8B

ECBE
EC90
EC93
EC95
EC98
EC9B

DO
4C
AE
30
A2
8E
CE
DO
4D
A2
8E
8D
4C

03
8B
05
12
AO
05
6C
08
6D
10
6C
00
FF

EC
18
18
02
02
02
lC
EB

BNE
JMP
LDX
BMI
LDX
STX
DEC
BNE
EOR
LDX
STX
STA
JMP

$EC81
$EC8B
$1805
$EC98
#$AO
$1805
$026C
$EC98
$026D
#$10
$026C
$lCOO
$EBFF

erase timer interrupt
set timer
decrement counter
not yet zero?
reset counter
turn LED on/off
back to wait loop

******************************
EC9E
A9 00
LDA #$00
ECAD
85 83
STA $83
A9 01
ECA2
LDA #$01
ECA4
20 E2 Dl
JSR $DIE2
ECA7
A9 00
LDA #$00
ECA9
20 C8 D4
JSR $D4C8
ECAC
A6 82
LDX $82
ECAE
A9 00
LDA #$00
ECBO
9D 44 02
STA $0244,X
ECB3
20 93 DF
JSR $DF93
ECB6
AA
TAX
ECB7
AS 7F
LDA $7F
ECB9
9D 5B 02
STA $025B,X
ECBC
A9 01
LDA #$01
ECBE
20 Fl CF
JSR $CFFI
ECCI
A9 04
LDA #$04
ECC3
20 Fl CF
JSR $CFFI
ECC6
A9 01
LDA #$01
ECC8
20 Fl CF
JSR $CFFI
ECCB
20 Fl CF
JSR $CFFI
ECCE
AD 72 02
LDA $0272
ECDI
20 Fl CF
JSR $CFFI
ECD4
A9 00
LDA #$ 00
ECD6
20 Fl CF
JSR $CFFI
ECD9
20 59 ED
JSR $ED59
ECDC
20 93 DF
JSR $DF93
ECDF
OA
ASL A
ECEO
AA
TAX
ECEI
D6 99
DEC $99,X
ECE3
D6 99
DEC $99,X
ECE5
A9 00
LDA #$00
ECE7
JSR $CFFl
20 1:'1 CF
ECEA
A9 01
LDA #$01
ECEC
20 Fl CF
JSR $CFFl
ECEF
20 Fl CF
JSR $CFFI
ECF2
20 CE C6
JSR $C6CE
ECF5
90 2C
BCC $ED23
ECF7
AD 72 02
LDA $0272
ECFA
20 Fl CF
JSR $CFFI
ECFD
AD 73 02
LDA $0273

222

LOAD 11$11
secondary address 0
find channel and buffer
initialize buffer pointer
channel number
pointer to end = zero
get buffer number
drive number
bring in table
1
write in buffer
4, start address $0401
write in buffer
2 times 1
write in buffer as link address
drive number
write in buffer as line number
line number hi
in buffer
directory entry in buffer
get buffer number
decrement buffer pointer
0 as line end in buffer
2 times 1 as link address
directory entry in buffer
another entry?
block number 10
in buffer
block number hi

Anatomy of the 1541 Disk Drive
EDOO
Eo03
ED06
E008
EOOB
EOOO
EOIO
EOll
E012
E014
E016
E018
EOIA
EOIO
E020
E022

20
20
A9
20
00
20
OA

Fl
59
00
Fl
00
93

CF
EO
CF
OF

AA

A9
95
A9
A4
80
99
A5
60

00
99
88
82
54 02
F2 00
85

JSR
JSR
LOA
JSR
BNE
JSR
ASL
TAX
LOA
STA
LOA
LOY
STA
STA
LOA
RTS

$CFFI
$E059
#$00
$CFFl
$ECEA
$OF93
A

in buffer
directory entry in buffer
zero as end marker in buffer
buffer full? no
get buffer number

#$00
$99,X
#$88
$82
$0254
$00F2,Y
$85

***********.******************
E023
AO 72 02
LOA $0272
20 Fl CF
E026
JSR $CFFI
E029
AD 73 02
LOA $0273
E02C
20 Fl CF
JSR $CFFI
E02F
20 59 ED
JSR $E059
E032
20 93 OF
JSR $OF93
E035
OA
ASL A
E036
AA
TAX
E037
06 99
DEC $99,X
E039
06 99
DEC $99,X
E03B
A9 00
LOA #$00
20 Fl CF
JSR $CFFI
E030
E040
20 Fl CF
JSR $en'l
E043
20 Fl C~'
JSR $CFFI
E046
JSR $OF93
20 93 OF
E049
OA
ASL A
E04A
A8
TAY
E04B
B9 99 02
LOA $0099,Y
E04E
A6 82
LOX $82
E050
90 44 02
STA $0244,X
OE 44 02
E053
DEC $0244,X
E056
JMP $EOOO
4C 00 EO
******************************
E059
AO 00
LOY #$00
E05B
B9 Bl 02
LOA $02Bl,Y
E05E
20 Fl CF
JSR $CFFI
E06l
C8
INY
E062
CO IB
CPY #$lB
E064
00 F5
BNE $E05B
E066
60
RTS
******************************
E067
20 37 01
JSR $0137
E06A
FO 01
BEO $E060
60
E06C
RTS

223

buffer pointer to zero
set REAO flag
channel number
flag for channel
data byte

block number 10
write in buffer
block number hi
in buffer
I Blocks
free. I in buffer
get buffer number

buffer pointer minus 2
three zeroes as program end
get buffer number
times 2
buffer pointer
as end marker

transmit directory line
character from buffer
write in output buffer
27 characters?

get byte from buffer
get byte
buffer pointer zero?

Anatomy of the 1541 Disk Drive
E06D
E06F
E071
E074
E076
E078
E07B
E07D

85
A4
B9
FO
A9
99
AS
60

85
82
44 02
08
80
F2 00
85

E07E
E07F
E082
E083

48
20 EA EC
68
60

STA
LOY
LOA
BEO
LOA
STA
LOA
RTS

$85
$82
$0244,Y
$E07E
#$80
$00F2,Y
$85

PHA
JSR $ECEA
PLA
RTS

save data byte
channel number
set end marker
zero (LOAD S)?
set REAO flag
data byte

create directory line in buffer

******************************
E084
20 01 C1
JSR $C101
E087
20 42 DO
JSR $0042
E08A
A9 40
LOA #$40
80 F9 02
STA $02F9
EOBC
E08F
20 B7 EE
JSR $EEB7
E092
A9 00
LOA #$00
E094
80 92 02
STA $0292
20 AC C5
JSR $CSAC
E097
E09A
00 3D
BNE $E009
A9 00
LOA #$00
E09C
E09E
85 81
STA $B1
EOAO
AO 8E FE
LOA SFE85
B5 80
STA $80
EOA3
EOAS
20 E5 EO
JSR SEOE5
LOA #SOO
EDAB
A9 00
EOAA
80 F9 02
STA $02F9
20 FF EE
JSR SEEFF
EOAO
EOBO
4C 94 C1
JMP $C194
******************************
EOB3
C8
INY
EOB4
B1 94
LOA (S94),Y
PHA
EOB6
48
EOB7
C8
INY
EOB8
Bl 94
LOA (S94),Y
EOBA
48
PHA
EOBB
AO 13
LOA #$13
Bl 94
LDA (S94),Y
EOBO
EOBF
FO OA
BEO SEDCB
EOC1
85 80
STA S80
C8
INY
EOC3
EDC4
B1 94
LOA ($94),Y
EOC6
85 81
STA $81
20 E5 EO
EOC8
JSR SEOE5
EOCB
68
PLA
EOCC
85 81
STA $81
EOCE
68
PLA
EOCF
85 80
STA $80
EOD1
20 ES ED
JSR $EDE5
EOD4
20 04 C6
JSR $C604
224

V command,
• collect •
find drive number in input line
load BAM
create new BAM in buffer
load directory, find 1st flag
found?
sector 0
18
track 18 for BAM
mark dir blocks as allocated
write BAM back to disk
done, prepare disk status

save track
and sector
pointer to side-sector block
no track following?
track and
sector of 1st side-sector block
mark side-sector blocks as
allocated
get track and sector back
mark blocks of file as allocated
read next entry in directory

Anatomy of the 1541 oisk Drive

E007
E009
EOOB
EOOO
EOOF
EOE2

FO
AO
Bl
30
20
4C

C3
00
94
04
B6 C8
04 EO

BEO
LOY
LOA
BMI
JSR
JMP

$E09C
#$00
($94) , Y
SEOB3
SC8B6
SE004

******************************

EOE5
EOE8
EOEB
EOEE
EOFO
EOF3
EOF6
EOF8
EOFB
EDFD
EDFF
EEOl

20
20
20
A9
20
20
85
20
85
A5
DO
4C

5F
90
75
00
C8
37
80
37
81
80
03
27

05
EF
04

EE04
EE07
EEOA

20 90 EF
20 4D 04
4C EE EO

04
01
Dl

02

JSR
JSR
JSR
LOA
JSR
JSR
STA
JSR
STA
LOA
BNE
JMP

S055F
SEF90
$0475
#$00
S04C8
$0137
S80
$D137
$81
$80
SEE04
$0227

20
A5
10
A9
4C
29
85
20
A5
OA
AA
AC
CC
FO
B9
95
B9
95
20
A9
85
20
20
4C

12 C3
E2
05
33
C8 Cl
01
7F
00 Cl
7F
7B
74
lA
00
12
01
13
07
01
80
C6
05
56

JSR SEF90
JSR S044D
JI1P $EDEE
$C312
$E2
SEE19
#$ 33
$C1C8
#$01
$7F
SCIOO
$7F
A

C8
FO
EE

EE46
EE49
EE4B
EE4E

20
A6
BO
CO

42 00
7F
01 01
05 FE

JSR
LDX
LOA
CMP

$0042
$7F
$OlOl,X
SFE05

02
02
03

allocate file blocks in BAM
check track and sector number
allocate block in BAM
read next block

allocate block in BAM
read next block
continue

JSR
LDA
BPL
LDA
JI1P
ANO
STA
JSR
LOA
ASL
TAX
LOY
CPY
BEO
LOA
STA
LDA
STA
JSR
LOA
STA
JSR
JSR
JMP

02
02

file type
bit 7 set, file closed?
file type to zero and write BAM

buffer pointer zero
get byte from buffer
track
get byte from buffer
sector
another block?
yes
close channel

******************************

EEOD
EEIO
EE12
EE14
EE16
EE19
EEIB
EEID
EE20
EE22
EE23
EE24
EE27
EE2A
EE2C
EE2F
EE31
EE34
EE36
EE39
EE3B
EE30
EE40
EE43

end of directory?

N command,
'header'
get drive number
drive number
not clear?
33,

'syntax error'

drive number
turn LED on
drive number
times 2

$027B
$0274
$EE46
$0200,Y
$12,X
S0201,Y
$13,X
$0307
#$01
$80
$C8C6
$F005
SEE56

225

comma position
compare with end name
format without 1D
first character of 1D
save
second character
close all channels
track 1
format disk
erase buffer
continue as below
load BAM
drive number
'A' , marker for 1541 format

Anatomy of the 1541 Disk Orive
EE51
EE53

FO 03
4C 72 05

BEO SEE56
JMP S0572

ok
73, 'cbm dos v2.6 1541'

EE56
EE59
EE5B
EE5C
EESD
EE5E
EE61
EE63
EE66
EE6B
EE6B
EE6D
EE6F
EE72
EE75
EE76
EE77
EE7B
EE7A
EE7C
EE70
EE7F
EE81
EE82
EE83
EE85
EE87
EE8B
EE8B
EE8D
EE8F
EE91
EE94
EE96
EE99
EE9B
EE90
EEAO
EEA3
EEA6
EEAB
EEAA
EEAC
EEAF
EEBI
EEB4

20 B7 EE
A5 F9

JSR
LOA
TAY
ASL
TAX
LOA
STA
LOX
LOA
JSR
LDY
LOX
LOA
STA
TXA
ASL
TAX
LOA
STA
INY
LOA
STA
INY
INY
LOA
STA
INY
LDA
STA
LDY
STA
LOA
STA
JSR
LOA
STA
JSR
JSR
JSR
LOY
LOA
STA
JSR
OEC
JSR
JMP

create BAM
buffer number

AS

OA
AA
AD
95
AE
A9
20
AO
A6
AO
90
8A
OA
AA
B5
91
C8
B5
91
C8
C8
A9
91
C8
AO
91
AO
91
AO
85
20
A9

85
20
20
20
AO
A9
9A
20
C6
20
4C

88
99
7A
1B
6E
12
7F
D5
01

FE
02
C6
FE
01

12
94
13
94

32
94
D5
94
02
6D
85
BO
93
01
Bl
93
FF
05
01
FF
6D
64
81
60
94

F'E

FE
EF
EF

BE
FO

D4
04
Cl

SEEB7
SF9
A
SFE88
S99,X
S027A
#SlB
SC6f;E
1IS12
S7F
SFE05
S0101,X

S90, start of disk name
buffer pointer to name

A

times 2

S12,X
(S94),Y

ID, first character
in buffer

S13 ,X
(S94) ,Y

and second character
in buffer

#S32
(S94) ,Y

'2'
in buffer

SFE05
(S94), Y
1IS02
(S60) ,Y
SFE85
$80
SEF93
#SOI
S81
SEF93

'A'
1541 format
in buffer

$EE~'F

SF005
#SOI
#SFF
(S6D),Y
S0464
S81
$0460
SC194

******************************
EEB7
20 01 FO
JSR SFOOI
EEBA
AO 00
LOY #SOO
EEBC
A9 12
LOA #S12
EEBE
91 60
STA (S60),Y

226

27
write filenames in buffer
position 18
drive number
'A'r 1541 format

and at position 2
18
track number
mark block as allocated
1
sector number
mark block as allocated
wri te BAM
pointer S60/$6E to buffer, erase
buffer
track following is zero
write BAM
decrement sector number, 0
read block
prepare disk status
create BAM
18
pointer to directory track

Anatomy of the 1541 Disk Drive
EECO
EECl
EEC2
EEC4
EEC5
EEC6
EEC7
EEC9
EECB
EECD
EECF
EEDO
EEDl
EED2
EED5
EED7
EED8
EED9
EEDA
EEDC
EEDE
EEEO
EEEl
EEE3
EEE5
EEE7
EEE8
EEE9
EEEB
EEED
EEEF
EEFI

C8
98
91
C8
C8
C8
A9
85
85
85
98
4A
4A
20
91
C8

6D

00
6F
70
71

4B F2
6D

6F
70
71

F6
6F
6D
03
F6
90
D6
75 DO

SEC
ROL
ROL
ROL
DEX
BNE
LDA
STA
INY
INX
CPX
BCC
CPY
BCC
JMP

S6F
S70
S71

1\9 00

99
20
AS
OA
48
20
68
18
69
20

3 bytes

=

24 bits for sectors

byte position
divided by 4 = track number
get number of sectors
and in BAM

create bit model

SEED9
S6F,X
(S6D),Y

3 bytes
the BAM in huffer

#S03
SEEE3
#S90
SEEC7
S[)075

position 144?
no, next track
calculate number of free blocks

******************************
EEF4
20 93 DF
JSR SDf'93
EEF7
TAX
AA
BD 5B 02
LDA S025B,X
EEF8
29 01
EEFB
AND #$01
85 7F
STA S7F
EEFD
114 7F
LDY S7F
EEFF
EFOI
B9 51 02
LDA $025I,Y
EF04
DO 01
BNE SEF07
60
EF06
RTS
EF07
EF09
EFOC
EFOF
EFll
EF12
EF13
EF16
EFl7
EF18
EFIA

1
pointer to directory sector

TAX

AA

38
26
26
26
CA
DO
B5
91
C8
E8
EO
90
CO
90
4C

INY
TYA
STA (S6D),Y
INY
INY
INY
LDA #$00
STA S6F
STA S70
STA S71
TYA
LSR A
LSR A
JSR SF24B
STA(S6D),Y
INY

51 02
3A EF
7F
A5 FO
01
AS FO

LDA
STA
JSR
LDA
ASL
PHA
JSR
PLA
CLC
ADC
JSR

#$00
S025l,Y
SEF3A
S7F

write BAM if needed
get buffer number
command for disk controller
isolate drive number
BAM-changed flag set?
yes

A

reset BAM-changed flag
set buffer pointer for BAM
drive number
times 2

SFOA5

verify BAM entry

#SOl
$FOA5

increment track number
verify BAM entry
227

Anatomy of the 1541 Disk Drive
EFID
EFIF
EF20
EF22
EF24
EF25
EF26
EF28
EF2B
EF20
EF2F
EF32
EF34
EF35
EF37

AS
48
A9
85
OA
OA
85
20
E6
AS
CD
90
68
85
4C

80
01
80
6D
20 F2
80
80
07 FE
FO
80
SA DS

LDA
PHA
LDA
STA
ASL
ASL
STA
JSR
INC
LOA
CMP
BCC
PLA
STA
JMP

S80

track

#SOl
S80
A
A
S6D
SF220
S80
S80
SFED7
SEF24

and compare with max val + 1
ok, next track

S80
S058A

get track number back
write BAI' to disk

track 1
times 4
verify BAM
increment track number

******************************
EF3A
20 OF FI
JSR SFIOF
EF30
AA
TAX
EF3E
20 DF FO
JSR SFODF
EF41
A6 F9
LDX SF9
BO EO FE
EF43
LOA $FEEO,X
EF46
STA S6B
85 6E
EF48
A9 00
LDA #SOO
EF4A
85 60
STA $6D
EF4C
60
RTS
******************************

EF4D
EF4F
EF52
EFS5
EF58
EF5B

A6 7F

BD
8D
BD
8D
60

FA
72
FC
73

02
02
02
02

LDX
LDA
STA
LDA
STA
RTS

S7F
S02FA,X
S0272
S02FC,X
S0273

******************************

EF5C
EF5F
EF62
EF63
EF65
EFG7
EF6A
EF6C
EF6F
EF71
EF72
EF74
EF76
EF78
EF7A
EF7D
EF7F
EF82
EF84

20
20
38
DO
Bl
10
91
20
M

18
Bl
69
91
AS
CD
FO

Fl EF
CF EF
22
6D
£9 EF
6D
88 EF
6F

6D
01
60
80
85 FE
313
~"E FA 02
DO 03
FE FC 02

JSR
JSR
SEC
BNE
LDA
ORA
STA
JSR
LOY
CLC
LDY
AOC
STA
LOA
CMP
BEO
INC
BNE
INC

SEFFI
SEFCF
SEFS7
($60), Y
SEFE9
(S60) ,Y
SEFS8
S6F
(S60),Y
#SOI
(S60),Y
SSO
SFE8S
SEFBA
S02FA,X
SEF87
S02PC,X
228

set buffer pointer for BAM
get 6 for drive 0
allocate buffer
buffer nUJllber
buffer address, hi byte
10 byte
pointer to S60/S6E
get # of free blocks for dir
drive number
number of blocks, 10
number of blocks, hi
in buffer for directory
mark block as free
set buffer pointer
erase bit for sector in BAM
block already free, then done
bit model of BAM
set bit X, marker for free
set flag for BAM changed

increment # of free blocks/track
track
equal to 18?
then skip
inc # of free blocks in disk
increment number of blocks hi

Anatomy of the 1541 Oisk Orive
EF87

60

FTS

******************************
EF88
A6 7F
LOX $7F
EF8A
A9 01
LOA #$01
EF8C
90 51 02
STA $0251,X
EF8F
60
RTS

set flag for 'BAM changed'
dri ve number

******************************
EF90
20 F1 EF
JSR $EFFI
EF93
20 CF EF
JSR $EFCF
EF96
FO 36
BEO $EFCE
EF98
Bl 60
LOA ($60) ,Y
50 E9 EF
EOR $EFE9,X
EF9A
EF90
STA (S60) ,Y
91 60
EF9F
20 88 EF
JSR SEF8S
EFA2
M 6F
LOA $6F
EFM
Bl 60
LOA (S60),Y
EFA6
38
SEC
EFA7
E9 01
SBC #$01
EFA9
91 6D
STA (S60),Y
EFAB
A5 80
LDA S80
EFAD
CD 85 FE
CMP SFE85
FO OB
EFBO
BEO $EFBO
EFB2
BD FA 02
LDA $02FA,X
EFR5
DO 03
BNE SEFBA
EFB7
DE FC 02
DEC $02FC,X
EFBA
DE FA 02
DEC S02FA,X
EFBD
BD FC 02
LOA S02FC,X
EFCO
DO OC
FINE SEFCE
EFC2
BD FA 02
LDA $02FA,X
EFC5
C9 03
CMP #S03
EFC7
BO 05
BCS SEFCE
EFC9
A9 72
LDA #$72
EFCB
20 C7 E6
JSR $E6C7
EFCE
60
RTS

mark block as allocated
set buffer pointer
erase bit for sector in BAM
already allocated, then done

**********~*******************

erase bit for sector :n BAM entry
find BAM field for this track

EFCF
EFD2
EFD3
EFD5
EFD7
EFD8
EFD9
EFDA
EFDB
EFDD
EFDE
EFEO
EFE2
EFE3
EFE5
EFE8

20
98
85
A5
4A
4A
4A
38
65
A8
A5
29

11 FO
6F
81

6F
81
07

AA

B1 60
30 E9 EF
60

JSR
TYA
STA
LDA
LSR
LSR
LSR
SEC
ADC
TAY
LDA
AND
TAX
LDA
AND
RTS

SFOll
$6F
$81
A
A
A

flag = 1

erase bit for block
set flag for BAM changed

decrement 1I of blocks per track
track
18?
number of free blocks 10
decrement number of free blocks
number of free blocks hi
more than 255 blocks free?
free blocks 10
smaller than 37
72, 'disk full'

sector
divide by 8

S6F
byte number in BAM entry
sector number

$81
#S07
(SfiD) ,Y
SEFE9,X

229

bit number in BAM entry
byte in BAM
erase bit for corresponding
sector

Anatomy of the 1541 Disk Drive
******************************
EFE9
01 02 04 08 10 20 40 80

powers of 2

******************************
EFFI
A9 FF
LOA #$FF
EFF3
2C F9 02
BIT $02F9
EFF6
FO OC
BEO $F004
EFF8
10 OA
BPL $F004
EFFA
70 08
BVS $F004
EFFC
A9 00
LOA #$00
EFFE
80 F9 02
STA $02F'9
FOOl
4C 8A 05
JMP $DS8A
FOO4
60
RTS

write BAM after change

******************************
FOOS
20 3A EF
JSR $EF3A
FOO8
AO 00
LOY #$00
FOOA
98
TYA
FOOB
91 6D
STA (S6f),Y
FOOD
C8
INY
FOOE
DO FB
BNE SFOOB
FOIO
60
RTS

reset flag
write block
erase BAM buffer
pointer $6D/S6E to BAM buffer
erase BAM buffer

** •• *******.*******.*******.*.
Fall
F013
F014
F016
F017
FOl9
FOIB
FOlD
FOIF
F022
F025
F027
F028
F029
F02B
F02C
F02E
F031
F033
F034
F036
F039
F03B
F03E
F040
F042
F045
F046
F047
F048
F04A

AS
48
AS
48
A6
B5
FO
A9
20
20
85
8A
OA
85
AA
A5
DD
FO
EB
86

6F
70
7F
FF
as
74
48 E6
OF FI
6F
70
80
9D 02
OB
70

00 9D 02

FO
20
AS
A6
90
OA
OA
18
69
85

03
5R FO
70
7F
9B 02

Al
6D

LOA
PHA
LDA
PHA
LDX
LDA
BEO
LDA
JSR
JSR
STA
TXA
ASL
STA
TAX
LOA
CMP
BEO
INX
STX
CMP
BEO
JSR
LOA
LDX
STA
ASL
ASL
CLC
ADC
STA

$6F
S70
$7F
$FF,X
$F022
#$74
$E648
$FIOF
$6F

drive number
drive zero?
'drive not ready'
get buffer number for BAM

A
$70
S80
S0290,X
$F03E
$70
S029D,X
SF03E
SFOSB
S70
$7F
S029B,X
A
A
#$Al
S6D
230

track

drive number
times 4

Anatomy of the 1541 Oisk Orive
F04C
F04E
F050
F052
F054
F055
F057
F058
F05A

A9
69
85
AO
58
85
68
85
60

02
00
6E
00
70
6F

LOA
AOC
STA
LOY
PLA
STA
PLA
STA
RTS

1IS02
#SOO
S6E
#SOO
S70
S6F

******************************

F05B
F050
F060
F062
F063
F064
F067
F069
F06B
F060
F070
F072
F073
F074
F076
F077
F078
F07A
F07C
F070
F07E
F07F
F08l
F084
F086
F088
F08A
F08B
F08C
F08E
F090
F092
F094
F097
F09A
F09C

A6
20
A5
AA
OA
10
49
29
85
20
AS
OA
AA
AS
OA
OA
95
AS
OA
OA
A8
Al
99
A9
81

99
Al 02
00
99
F6 99
C8
98
29 03
00 EF'
A6 70
A5 80
90 90 02
AO F9 02
DO 03
4C 8A 05

LOX
JSR
LOA
TAX
ASL
ORA
EOR
ANO
STA
JSR
LOA
ASL
TAX
LOA
ASL
ASL
STA
LOA
ASL
ASL
TAY
LOA
STA
LOA
STA
INC
INY
TYA
ANO
BNE
LOX
LOA
STA
LDA
BNE
JMP

F09F
FOAl
FOM

09 80
80 F9 02
60

ORA #S80
STA S02F9
RTS

FOA5
FOA6
FOA9

A8
B9 90 02
E'O 25

TAY
LDA S0290,y
BEO SFOOO

6F
Of FO
7F
9B 02
01
03
70
A5 FO
F9
80
99
70

S6F
SFOOF
S7F

dri ve number

A
$029B,X
#SOI
#S03
S70
SFOA5
SF9
A
S80
A
A
S99,X
S70
A
A

buffer number
track
times 4
equal pointer in BAM field

(S99,X)
S02Al,X
#SOO
(S99,X)
S99,X
#S03
SF07F
S70
S80
S0290,X
S02F9
SF'09F
S058A

231

zero in buffer
increment buffer pointer

track

write block

Anatomy of the 1541 Disk Drive
FOAB
FOAC
FOAE
FOBl
FOB3
FOB4
FOBS
FOB6
FOB7
FOBB
FOBA
FOBB
FORC
FOBD
FOBE
FOCI
FOC3
FOC5
FOCB
FOCA
FOCB
FOCC
FOCE
FODO

48
A9 00
99 9D 02
AS F9
OA

FODI
FOD3
FOD4
FOD5
FOD7
FODA
FODS
FODE

AS
OA
AA
A9
9D
E8
9D
60

FODF
FOEI
FOE3
FOES
FOE6
FOE7
FOEA
FOEB
FOED
FOEF
(,"01"2
FOF4
1"01"5
FOF6
FOF7
FOF9
FOFC
FOFD
FOFE
1"101
FI03

B5
C9
DO
8A
48
20
AA
10
A9
20

AA

68
OA
OA
95
98
OA
OA
AB
B9
81
A9
99
F6
C8
9B
29
DO
60

99

Al 02
99
00
Al 02
99
03
EE
7F
00
9D 02
9D 02
A7
FF
25
HE D2

05
70
C8 Cl
fl6 1"9
68
A8
8A
09 80
99 A7 00
OA
AA
AD 85 FE
95 06
A9 00

PHA
LDA
STA
LDA
ASL
TAX
PLA
ASL
ASL
STA
TYA
ASL
ASL
TAY
LDA
STA
LDA
STA
INC
INY
TYA
AND
BNE
RTS

#$00
$029D,Y
$F9
A

buffer number
times 2

A
A
$99,x
A
A
$02AI,Y
($99,X)
#$00
$02AI,Y
$99,X

write in buffer
increment buffer pointer

#$03
$FOBE

LDA
ASL
TAX
LDA
STA
INX
STA
RTS

$7F
A

LDA
CMP
ENE
TXA
PtTA
JSR
TAX
BPL
LDA
JSR
STX
PLA
TAY
TXA
ORA
STA
ASL
TAX
LDA
STA
LDA

SA7,X
#$1"1"
SFIOA

drive number

#$00
$029D,X
$029D,X

$D28E
SFOF2
#$70
SCIC8
SF9

70, • no channel'

#S80
$00A7,Y
A
SFE85
S06,x
#$00

18, directory track
save
0
232

Anatomy of the 1541 Disk Drive
Fl05
FI07

95 07
4C 86 D5

STA S07,X
JMP $D586

as sector
write hlock

FIOA
FlOC
FlOE

29 OF
85 F9
60

AND #$OF
STA $F9
RTS

buffer number

******************************

FIOF
Flll
FIl3
F1l5
FIlii

Fll8

A9
A6
DO
18
69
60

06
7F
03
07

LDA
LDX
BNE
CLC
ADC
RTS

drive number

#$07

gives 13 for drive 0

******************************

F1l9
FllC
FllD

20 OF Fl
AA

60

JSR SFIOF
TAX
RTS

******************************

FllE
Fl21
F123
Fl25
F127
F12A
F12D
F12F
F130
Fl33
F134
F136
F138
Fl3A
Fl3C
F13F
F141
F143
F145
F147
Fl4A
F14C
F14F
F150
F152
F154
F156
F158
F15A
F15C
F15F
F161
F163
F166

20
A9
85
A9
OD
8D
A5
48
20
68
85

3E DE
03
6F
01
F9 02
F9 02
6F
11 FO

6F

Bl 6D

DO
A5
CD
FO
90
E6
A5
CD
DO
AE
CA
86
A9
85
C6
DO
A9
20
C6
DO
AE
E8

39
80
85 FE
19
lC
80
80
D7 FE
El
85 FE
80
00
81
6F
D3
72
C8 Cl
80
CA
85 FE

JSR
LDA
STA
LDA
ORA
STA
LDA
PHA
JSR
PLA
STA
LDA
BNE
LDA
CMP
REO
BCC
INC
LDA
CMP
BNE
LDX
DEX
STX
LDA
STA
DEC
BNE
LDA
JSR
DEC
BNE
LDX
INX

get buffer number for RAM

#$06
$7F
SF1l8

SDE3E
41$03
S6F
#SOI
S02F9
S02f'9
S6F

buffer number for BAM
get buffer number

find and allocate free block
get track and sector number

counter

save counter

SFOll

find BAM field for this track

S6F
(S6D),Y
Sf'173
S80
SFE85
SF15A
SF15F
S80
S80
SFED?
SF12D
SFE85

get counter back
number of free blocks in track
blocks still free?
track
18, directory track?
yes, 'disk full'
smaller, then next lower track
increment track number

S80
#SOO
S81
S6F
SF12D
#S72
SCIC8
S80
SF12D
SFE85

36, highest track number plus one
no, continue searching thi~ track
18, directory track
decrement
save as track number
begin with sector number zero
decrement counter
not yet zero, then continue
72, 'disk full'
decrement track number
not yet 0, continue in this track
18, directory track
increment

233

Anatomy of the 1541 Disk Drive
FI67
FI69
F16B
F160
Fl6F
F171

86
A9
85
C6
DO
FO

80
00
81
6F
BC
E7

STX
LDA
STA
DEC
BNE
BEO

Fl73
Fl75
Fl76
F178
Fl7A
Fl7C
Fl7F
Fl82
Fl8S
Fl87
Fl1l9
F18A
FIBC
FIBF
FI9!
Fl93
Fl9S
Fl98
F19A
Fl9D
Fl9F
FIAI

A5
18
65
85
A5
20
8D
80
CS
BO
38
AS
ED
85
FO
C6
20
FO
4C
A9
85
20
DO
4C

81

LDA $81
CLC
ADC $69
STA $81
LDA $80
JSR SF24B
STA $024E
STA S024D
CMP S8l
BCS SF195
SEC
LDA S8l
SBC S024E
STA $81
BEO SF195
DEC S81
JSR SFIFA
BEO SFI, then 29, 'disk id mismatch'
decrement counter for attempts
and try again
else
20, 'read error'

******************************

F410
F412
F414
F416
F41S
F41A
F41B
F41D
F41E
F420

compare with ID1

LDA $16
STA $12
LDA $17
STA $13
LDA #$01
.BYTE $2C
LDA #$OB
.BYTE $2C
LDA #$09
JMP $F969

preserve block header
1D1
and 1D2
preserve
ok
29, 'disk id mismatch'
27, 'write error'
done

******************************

F423
F425
F427
F429
F42A
F42C
F42E
1'430
F432
F434
F436
F438
F43A
F43D
F43F'
F'441
F443

A9
85
A5
IS
69
C5
90
E5
R5
A2
86
A2
20
10
85
29
CS

7F
4C
19
02
43
02
43
4D
05
3F
FF
93 F3
44
44
01
3E

LDA
STA
LDA
CLC
ADC
OlP

BCC
SEC
STA
LDX
STX
LDX
JSR
BPL
STA
AND
CMP

#$7F
$4C
$19
#$02
S43
$F432
$43
S4D
#S05
S3F
#$F'F
SF393
SF483
S44
#$01
S3E

set buffer ptr for disk control.

240

Anatomy of the 1541 Oisk Orive
F445
F447
F449
F44B
F440
F44F
F451
F453
F455
1"457
F458
F45A
F45C
F45E
F45F
F461
F463
F465
F466
F468
F46A
F46B
F460
F46F
F471
F473
F475
F477
F478
F47A
F47C
F47E
F47F
F481
F483
F485
F487
F488
F48A

00
AO
81
C5
00
AS
C9
FO
AO
38
Bl
E5
10
i8
65
C4
BO
48
A5
FO
68
C9
90
C9
BO
85
A5
AA
69
85
DO
68
C9
90
C6
10
8A
10
4C

3C
00
32
40
34
45
60
OC
01

03
9C 10'9

BNE
LDY
LOA
CMP
BNE
LDA
CMP
BEO
LOY
SEC
LOA
SBC
BPL
CLC
AOC
CMP
RCS
PHA
LOA
BEO
PLA
CMP
BCC
CMP
BCS
STA
LOA
TAX
AOC
STA
BNE
PLA
CNP
BCC
DEC
BPL
TXA
BPL
JMP

F480
F48F
F492
F'494

86
20
A5
4C

3F'
93 F3
45
CA F4

F497
F499
F49A
F49C
F490
F49F
F4Al
F'4A3
F4A5
F4A7

A5
48
A5
48
A9
85
A9
85
A9
85

30

32
40
03
43
4C
IE
45
14

09
14
OC
10
4C
3F
03
31
05
06
FO
3[<
B3

31
24
30
00
31
00
34

$F483
#$00
($ 32) • Y
$40
$,,'483
$45
#$60
$F461
#SOI

command code

($ 32) • Y
S40
SF461
S43
S4C
SF483
S45
SF47E
#S09
SF483
#SOC
$F483
54C
53F
#$03
531
SF483
#$06
SF473
53F
5F43A
$F48D
5F99C

to job loop

STX
JSP
LOA
JNP

$3F'
5F393
$45
$F4CA

get buffer- numbercommand code
continue checking

LOA
PLA
LOA
PHA
LOA
STA
LDA
STA
LDA
STA

$30
save pointer $30/$31
$31
#$ 24
530
#$00
$31
#$00
$34

pointer $30/$31 to $ 24

241

Anatomy of the 1541 Disk Drive
F4A9
F4AC
F4AE
F4BO
F4B2
F4B4
F4B6
F4B8
F4EB
F4BO
F4BF
F4CI
F4C3
F4C4
F4C6
F4C7
F4C9

20
AS
85
AS
85
AS
85
20
AS
85
A5
85
68
85
68
85
60

E6 F7
55
18
54
19
53
IA
E6 F7
52
17
53
16
31
30

JSR
LOA
STA
LOA
STA
LOA
STA
JSR
LDA
STA
LOA
STA
PLA
STA
PLA
STA
RTS

$F7E6
$55
$18
$54
$19
$53
$IA
$F7E6
S52
$17
$53
S16
$31
get pointer S30/S31 back
$30

******************************
F4CA
C9 00
CMP #SOO
F4CC
FO 03
BEO $F401
F4CE
4C 6E F5
JMP SF56E
F401
F404
F406
F407
F40A
F4DC
F40D
F4DF
F4El
F4E3
F4E4
F4E7
F4EA
F4EB
F4EO
F4FO
F4F2
F4F4
F4F6
F4F8

20
50
B8
AO
91
C8
00
AO
50
B8
AO
99
C8
00
20
A5
C5
FO
A9
4C

F4FB
F4FE
F500
F502
F504
F505
F507

20
C5
FO
A9
2C
A9
4C

OA F5
FE
01 lC
30

F5
BA
FE
01 lC
00 01
F4
EO F8
38
47
05
04
69 F9
E9 F5
3A
03
05
01
69 F9

JSR
BVC
CLV
LOA
STA
INY
BNE
LOY
BVC
CLV
LOA
STA
INY
ENE
JSR
LDA
CMP
BEO
LOA
JMP

command code for 'read'?
yes
continue checking command code

$F50A
$F404

find beginning of data block
byte ready?

SICOl
($30) ,Y

get data byte
and write in buffer
256 times

SF404
#SBA
$F4EI

byte ready?

$lCOl
SOIOO,Y

read bytes
from SIBA to $IFF

$F4EI
SFIlEO
S38
$47
$F4FB
#$04
$F969

equal 7, beginning of data bloc
yes
22, 'read error'
error termination

JSR $F5E9
CMP $3A
BEO $F505
LOA #$05
.BYTE S2C
LOA #SOl
JMP SF969

calculate parity of data block
agreement?
yes
23, 'read error'
ok
prepare error message

******************************
F50A
20 10 ~'5
JSR SF510
F500
4C 56 F5
JMP $F556
242

find start of data block
read block header
wait for SYNC

Anatomy of the 1541 oisk Orive

******************************
F510
A5 30
LOA S30
ASL A
F512
OA
TAX
F513
AA
F514
B5 12
LOA S12,X
F516
85 16
STA S16
B5 13
LOA S13,X
F51S
F51A
85 17
STA $17
F51C
AD 00
LOY #SOO
LOA (S32),Y
F51E
Bl 32
F520
85 18
STA S18
INY
F522
C8
LOA (S32),Y
F523
Bl 32
F525
85 19
STA S19
F527
A9 00
LOA *SOO
F529
45 16
EOR $16
45 17
F52B
EOR S17
F520·
45 18
EOR S18
EOR $19
F52F
45 19
F531
85 lA
STA SlA
F533
20 34 F9
JSR SF934
F536
A2 5A
LOX #S5A
F53S
20 56 F5
JSR SF556
LOY tt$OO
F53B
AO 00
F530
50 FE
BVC SF'350
F53F
B8
CLV
F540
AO 01 lC
LOA SlCOl
09 24 00
F543
CMP S0024,Y
F546
BNE SF54E
00 06
F548
INY
C8
F549
CO 08
CPY #S08
F54B
00 FO
BNE SF530
F540
RTS
60

read block header
drive number

F54E
F54F
F551
F553

decrement counter
not yet zero?

CA

00 E7
A9 02
4C 69 F9

OEX
BNE SF538
LOA #S02
JMP SF969

WI
save
102
save
get track and
sector number from buffer

calculate parity for block header
and save
90 attempts
wait for SYNC
byte ready?
read data from block header
compare with saved data
not the same, try again
8 bytes read?
no

20, 'read error'

******************************
F556
A9 00
LOA #800
F558
80 05 18
STA S1805
F55B
LOA #S03
A9 03
BIT S1805
F550
2C 05 18
F560
10 Fl
BPL SF553
F562
2C 00 lC
BIT SlCaO
F565
30 F6
B~H SF550
F567
AO 10 lC
LOA SlCOl
F56A
B8
CLV
F56B
AO 00
LOY #SOO
F560
60
RTS
******************************
F56E
C9 10
CMP #$10
243

wait for SYNC
208
start timer
error code
timer run down, then 'read error'
SYNC signal
not yet found?
read byte

command code for 'write'

Anatomy of the 1541 Disk Drive
1"570
1"572

1"0 03
4C 91 1"6

BEO $1"575
JMP $1"691

yes
continue checking command code

******************************
20 E9 ~'5
JSR $F5E9
1"575
F57B
STA $3A
85 3A
F57A
LDA $lCOO
AD 00 lC
F57D
AND #$10
29 10
1"571"
BNE $1"586
DO 05
1"581
LDA #$08
A9 08
F583
4C 69 1"9
JMP $1"969

F586
1"589
F58C
F58E
F590
1"591
1"592
1"594
F596
F599
F59C
F59E
F5AO
F5A3
F5A5
F5A7
F5M
F5AB
F5AO
F5AE
F5AF
F5Bl
F5B3
F5B6
F5B8
F5B9
F5BC
F'5BO
F5BF
F5Cl
F5C3
F5C4
F'5C7
F5C8
F5CA
1"5CC
F5CF
1"5Dl
F5D4
F5D6
f'5D9
F5DC
F50E

20
20
A2
50
B8
CA
DO
A9
8D
AD
29
09
8D
A9
A2
80
B8
50
B8
CA
DO
AO
B9
50
B8
80
C8
DO
B1
50
138
8D
C8
DO
50
AD
09
8D
A9
80
20
A4

81" 1"7
10 1"5
09
FE
FA
FF
03
OC
IF
CO
OC
1"1"
05
01

1C
1C
1C
1C

FE
FA
BB
00 01
FE
01 lC
1"4

30
FE
01 lC
1"5
FE
OC
EO
DC
00
03
1"2

lC
lC
lC
1"5

3F

89 00 00

JSR
JSR
LOX
BVC
CLV
DEX
BNE
LDA
STA
LDA
AND
ORA
STA
LDA
LOX
STA
CLV
BVC
CLV
DEX
BNE
LOY
LOA
BVC
CLV
STA
INY
BNE
LDA
BVC
CLV
STA
INY
BNE
BVC
LDA
ORA
STA
LOA
LOA
JSR
LDY
LDA

$F7AF
$1"510
#S09
$F58E

write data block to disk
calculate parity for buffer
and save
read port B
isolate bit for 'wri te protect'
not set, ok
26, 'write protect'
find block header
byte ready?

$F58E
#SFF
$lC03
SlCOC
#$lF
#$CO

port A (write/read head) to
to output
change PCR to output

~lCOC

#$1"1"
#$05
SlC01

write $FF to disk 5 times

SF5AB

as SYNC characters

SF5AB
#SBB
S0100,y
$F5B6

bytes SlBB to SlFF to disk

SlC01
$F5B3
(S30) , Y
$F5C1

write data buffer (256 bytes)

S lCOl
SF5BF'
SF5CA
$lCOC
#SEO
$lCOC
#SOO
$lC03
Sf'5F2
S3F
SOOOO,y

244

byte ready?
PCR to input again
port A (read/write head) to inpl

Anatomy of the 1541 Disk Drive
F5El
F5E3
F5E6

49 30
99 00 00
4C Bl F3

EOR #$30
STA $OOOO,y
JMP $F3Bl

******************************
F5E9
A9 00
LDA #$00
F5EB
A8
TAY
F5EC
51 30
EOR ($30) ,Y
F5EE
C8
INY
F5EF
DO FB
BNE $F5EC
F5Fl
60
RTS
F5F2
F5F4
F5F6
F5F8
F5FA
F5FC
F5FE
F600
F602
F604
F606
F608
F60A
F60D
F60F
F611
F613
F615
F617
F618
F61A
F61C
F61D
F61F
F6.21
F622
F624
F627
F629
F62B
F62D
F62E
F630
F632
F633
F635
F637
F639
F63A
F63C
F63E
F63F
F641

A9
85
85
85
AS
85
A9
85
85
A9
85
85
20
AS
85
A4
AS
91
C8
AS
91
C8
AS
91
C8
84
20
A4
AS
91
C8
AS
91
CB
FO
AS
91
C8
AS
91
C8
84
DO

00
2E
30
4F
31
4E
01
31
2F
BB
34
36
E6 F7
52
38
36
53
2E
54
2E
55
2E
36
E6 F7
36
52
2E
53
2E
OE
54
2E
55
2E
36
El

LDA
STA
STA
STA
LDA
STA
LDA
STA
STA
LDA
STA
STA
JSF
LDA
STA
LDY
LDA
STA
INY
LDA
STA
INY
LDA
STA
INY
STY
JSF
LDY
LDA
STA
INY
LDA
STA
INY
BEO
LDA
STA
INY
LDA
STA
INY
STY
BNE

#$00
$2E
$30
$4F
$31
S4E
#SOI
$31
$2F
#$BB
S34
$36
$F7E6
$52
$38
$36
$53
(S2E), Y
$ 54
($2E), Y
$55
(S2E) ,Y
$36
$F7E6
$36
$52
C$2E), Y
$53
($2E) ,Y
$F643
S 54
(S2E) ,Y
$55
(S2E) , Y
$36
$F624

245

convert command code 'write'
to 'verify'
calculate parity for data I'uffer

AnatOlllY of the 1541 Disk Drive
F643
F645
F647
F648
F64A
F64C
F64D
F64F
F652
F654
F656
F658
F659
F65B
F650
F65E
F660
F662
F663
F665
F667
F668
F66.A
F66C
F66E
FPO
F672
F674
F'676
F678
F67A
F67C
F67D
F67F
F681
F683
F685
F688
F68A
F68B
F68C
F68E
F690

A5
91
C8
A5
91
C8
84
20
A4
A5
91
C8
A5
91
C8
A5
91
C8
A5
91
C8
84
CO
90
A9
85
A5
85
AO
Bl
91
88
DO
Bl
91
A2
BD
91
C8
E8
DO
86
60

54
30
55
30
36
E6 F7
36
52
30
53
30
54
30
55
30
36
BB
El
45
2E
31
2F
BA
30
2E
F9
30
2E
BB
00 01
30
F7
50

LDA
STA
INY
LDA
STA
INY
STY
JSR
LDY
LOA
STA
INY
LOA
STA
INY
LDA
STA
INY
LDA
STA
INY
STY
CPY
BCC
LDA
STA
LDA
STA
LOY
LDA
STA
DEY
BNE
LDA
STA
LDX
LDA
STA
INY
INX
BNE
STX
RTS

$54
(S30),Y
$55
(S30), Y
S36
SF7E6
536
S52
(S30), Y
S53
(530) ,Y
554
(530) ,Y
555
(530),Y
$36
#SBB
SF64F
#S45
$2E
S31
S2F
iSBA
($30) ,Y
($2E) ,Y
SF678
($30),Y
(S2E),Y
lISBB
$0100,X
(S 30) ,Y
$F685
$50

******************************

F691
F693
F695

C9 20
FO 03
4C CA F6

CMP #$ 20
BE(l $F698
JMP SF6CA

command code for 'verify'?
yes
continue checking command code

F698
F69R
F69D
F6AO
F6A3
F6A5

20 E9 F5

85
20
20
AO
B9

JSR
STA
JSR
JSR
LDY
LOA

calculate parity for data buffer
and save

3A
8F F7
OA f'5
BR
00 01

$F5E9
$3A
$F78F
$F50A
#$BB
$0100,Y
246

find start of data block
data from buffer

Anatomy of the 1541 Disk Drive
FE

F6A8
F6AA
F6AB
F6AE
F6BO
F6Bl
F6B3
F6B5
F6B7
F6B8
F6BB
F6BD
F6BE
F6CO
F6C2

50
B8
4D
DO
CB
DO
Bl
50
B8
4D
DO
C8
CO
DO
4C

F6C5
F6C7

A9 07
4C 69 F9

01 lC
15
F2
30
FE
01 Ie
08
FD
Fl
18 F4

BVC
CLV
EOR
BNE
INY
BNE
LDA
BVC
CLV
EOR
BNE
INY
CPY
BNE
JMP

SF6A8

byte ready?

SlCOl
$F6C5

compare with data from disk
not equal, then eJ:'ror

$F6A5
($30) , Y
SF6B5

data from buffer

SlCOl
$F6C5

compare with data fJ:'om disk
not equal, then error

#SFD
$F6B3
$F4l8

erJ:'oJ:' free termination

LDA #$07
JMP $F969

25, 'write error'

******************************

F6CA
F6CD

20 10 F5
4e 18 F4

J:'ead block header
done

JSR $F5l0
JMP $F4l8

******************************

F6DO
F6D2
F6D4
F6D6
F6D8
F6DA
F6DC
F6DD
F6DE
F6DF
F6EO
F6El
F6E4
F6E5
F6E6
F6E7
F6E9
F6EB
F6ED
F6EE
F6Fl
F6F2
F6F4
F6F5
F6F7
F6F9
F6FB
F6FD
F6FE
F700
F702

A9 00
85 57
85 5A
A4 34
A5 52
29 FO
4A
4A
4A
4A
AA
BD 7F F7
OA
OA
OA
85 56
A5 52
29 OF
AA
BD 7F F7
6A
66 57
6A
66 57
29 07
05 56
91 30
C8
A5 53
29 FO
4A

LDA
STA
STA
LDY
LDA
AND
LSR
LSR
LSR
LSR
TAX
LDA
ASL
ASL
ASL
STA
LDA
AND
TAX
LDA
ROR
ROR
ROR
ROR
AND
ORA
STA
INY
LDA
AND
LSR

#$00
$57
$5A
$34
$52
#$FO
A
A
A
A

isolate hi-nibble
and J:'otate to lower nibble
as index in table

$F77F,X
A
A
A
$56
$52
#$OF
$F77F,X
A
$57
A
$57
#$07
$56
($30), Y
$53
#$FO
A

times 8

isolate lower nibble
as index in table

in buffer
increment buffer
isolate upper nibble

247

Anatomy of the 1541 Disk Drive
F703
F704
F705
F706
F707
F70A
F70B
F70D
F70F
F711
F7l3
F714
F7l7
F7l8
F7l9
F71A
F7lB
F7lD
F7lE
F720
F722
F724
F725
F727
F729
F72A
F72B
F72C
F72D
F72E
F731
F732
F733
F735
F737
F738
F739
F73B
F73D
F73F
F741
F742
F745
F746
F747
F749
F74B
F74D
F74F
F751
F752
F753
F754
F755
F756

4A
4A
4A
AA

BD
OA
05
85
A5
29
AA
BD
2A
2A
2A
2A
85
2A
29
05
91
C8
A5
29
4A
4A
4A
4A
AA
BD
18
6A
05
91
C8
6A
29
85
A5
29
AA
BD
OA
OA
29
05
85
A5
29
4A
4A
4A
4A
AA

7F F7
57
57
53
OF
7F F7

58
01
57
30
54
FO

7F F7
58
30
80
59
54
OF
7F F7
7C
59
59
55
FO

BD 7F'

F7

LSR
LSR
LSR
TAX
LOA
ASL
ORA
STA
LOA
AND
TAX
LDA
ROL
ROL
ROL
ROL
STA
ROL
AND
ORA
STA
INY
LDA
AND
LSR
LSR
LSR
LSR
TAX
LDA
CLC
ROR
ORA
STA
INY
ROR
AND
STA
LDA
AND
TAX
LDA
ASL
ASL
AND
ORA
STA
LDA
AND
LSR
LSR
LSR
LSR
TAX
LDA

A
A
A

shift to upper nibble
as index in table

$F77F,X
A
$57
$57
$53
#$OF
SF77F,X
A
A
A
A
$58
A
#$01
S57
(S30) ,Y
$54
#$FO
A
A
A
A

lower nibble
as index

in buffer
increment buffer
isolate hi-nibble

SF77F,X
A
$ 58
($30) ,Y
A
*S80
$59
$54
#$OF

in buffer
increment buffer pointer

lower nibble
as index

$F77F,X
A
A
#$7C
$59
S59
$55
#$FO
A
A
A
A

isolate hi-nibble
shift to lower nibble
as index in table

$F77F',X
248

Anatomy of the 1541 Disk Drive
F759
F75A
F75C
F75D
F75F
F760
F762
F764
F766
F768
F769
F76B
F76D
F76F
F771
F773
F774
F777
F779
F77B
F77C
F77E

6A
66
6A
66
6A
66
29
05
91
C8
DO
A5
85
A5
29
AA
BO
05
91
C8
84
60

5A
5A
5A
03
59
30
04
2F
31
55
OF
7F F7
5A
30
34

ROR
ROR
ROR
ROR
ROR
ROR
AND
ORA
STA
INY
B:NE
LOA
STA
LDA
AND
TAX
LDA
ORA
STA
INY
STY
RTS

A
$5A
A
$5A
A
$5A
i$03
$59
($30) ,Y
$F76F
$2F
$31
$55
i$OF

in buffer
increll1ent buffer pOinter

lower nibble
as index

$F77F ,X
$5A
($30) ,Y
$34

******************************
F77F OA DB 12 13 OE OF 16 17
F787 09 19 1A 1B 00 10 IE 15
******************************
F78F
A9 00
LOA *$00
F791
85 30
STA $30
F793
85 2E
STA $2E
F795
85 36
STA $36
F797
A9 BB
LDA i$BB
F799
85 34
STA $34
F79B
85 50
STA $50
F790
A5 31
LOA $31
F79F
85 2F
STA $2F
F7A1
A9 01
LOA iS01
F7A3
85 31
STA $31
F7A5
A5 47
LOA $47
F7A7
85 52
STA $52
F7A9
A4 36
LOY $36
F7AB
B1 2E
LOA ($2E).,Y
F7AO
85 53
STA $53
F7AF
C8
INY
F7BO
B1 2E
LOA ($2E),Y
F7B2
85 54
STA $54
F7B4
C8
INY
F7B5
B1 2E
LOA ($2E), Y
85 55
STA $55
F7B7
F7B9
C8
INY
84 36
F7BA
STY $36
F7BC
20 00 F6
JSR $F600
F7BF
A4 36
LOY $36
F7C1
LDA ($2E) ,Y
B1 2E
249

in buffer
increment buffer pointer
and save

Anatomy of the 1541 Disk Drive
F7C3
F7C5
F7C6
F7C8
F7CA
F7CC
F7CD
F7CF
F7D1
F7D2
F7D4
F7D6
F7D7
F7D9
F7DB
F7DD
F7DF
F7E1
F7E3

85
C8
FO
B1
85
C8
B1
85
C8
B1
85
C8
DO
A5
85
A9
85
85
4C

F7E6
F7E8
F7EA
F7EC
F7ED
F7EE
F7EF
F7F1
F7F3
F7F5
F7F6
F7F7
F7F9
F7FA
F7FC
F7FE
F800
F802
F804
F806
F807
F808
F809
F80B
F80D
F80F
F811
F812
F814
F816
FS18
F819
F8lA
F8lB
F8lC

A4
B1
29
4A
4A
4A
85
B1
29
OA
OA
85
C8
DO
A5
85
A4
B1
29
2A
2A
2A
05
85
B1
29
4A
85
B1
29
OA
OA
OA
OA
85

52
11
2E
53
2E
54
2E
55
E1
3A
53
00
54
55
DO F6
34
30
F8

56
30
07
57
06
4E
31
4F
30
CO

57
57
30
3E
58
30
01

59

STA
INY
BEO
LDA
STA
INY
LDA
STA
INY
LDA
STA
INY
BNE
LDA
STA
LDA
STA
STA
JMP
LDY
LDA
AND
LSR
LSR
LSR
STA
LDA
AND
ASL
ASL
STA
INY
BNE
LDA
STA
LDY
LDA
AND
ROL
ROL
ROL
ORA
STA
LDA
AND
LSR
STA
LDA
AND
ASL
ASL
ASL
ASL
STA

$52
$F7D9
($2E},Y
$53
($2E},Y
$54
($2E) ,Y
$55
$F7BA
S3A
S53
#SOO
$54
S55
SF6DO
$34
(S30) ,Y
#$F8
A
A
A
$56
($30) , Y
#$07
A
A
$ 57
$F802
$4E
$31
S4F
($ 30) , Y
lI$CO
A
A
A
S57
$57
(S30) , Y
#$3E
A
S58
(S30) , Y
#$01
A
A
A

A
$59
250

Anatomy of the 1541 Disk Drive
F81E
F81F
F821
F823
F824
F825
F826
F827
F829
F82B
F820
F82F
F830
F832
F833
F835
F837
F838
F839
F83A
F83C
F83E
F840
F842
F844
F845
F846
F848
F84A
F84C
F84D
F84E
F84F
F851
F852
F854
F856
F858
F85A
F85C
F85E
F85F
F860
F861
F862
F864
F866
FB68
F86A
F86C
F86D
F86F
F871
F874
F876

C8
Bl
29
4A
4A
4A
4A
05
85
Bl
29
OA
85
C8
Bl
29
18
2A
2A
29
05
85
Bl
29
4A
4A
85
B1
29
OA
OA
OA
85
C8
DO
AS
85
A4
B1
29
2A
2A
2A
2A
05
85
Bl
29
85
C8
B4
A6
BD

30
FO

59
59
30
OF
SA
30
80

01
SA
SA
30
7C
5B
30
03

5C
06
4E
31
4F
30
EO

5C
5C
30
IF
5D

34
56
AO F8
A6 57
10 CO F8

INY
LOA
AND
LSR
LSR
LSR
LSR
ORA
STA
LOA
AND
ASL
STA
INY
LDA
AND
CLC
ROL
ROL
AND
ORA
STA
LDA
AND
LSR
LSR
STA
LDA
AND
ASL
ASL
ASL
STA
INY
BNE
LOA
STA
LDY
LOA
AND
ROL
ROL
ROL
ROL
ORA
STA
LDA
AND
STA
INY
STY
LOX
LDA
LDX
ORA

($30), Y
jI$FO
A
A
A
A
$59
$59
($30), Y
jI$OF
A
$5A
($30),Y
#$80
A
A
11$01
$5A
$5A
($30),Y
1I$7C
A
A
$5B
($30), Y
1$03
A
A
A
$5C
$F85A
$4E
$31
$4F
($30),Y
II$EO
A
A
A
A
$5C
$5C
($30),Y
#$lF
$5D
$34
$56
SF8AO ,X
$57
$FBCO,X

251

Ana tOllly of the 1541 Disk Drive

FS79
FS7B
FS70
FSSO
FS82
FS85
F8S7
FS89
FS8C
FS8E
FS91
FS93
FS95
FS9S
FS9A
FS90
FS9F

S5
A6
BO
A6
10
S5
A6
BO
A6
10
85
A6
BO
A6
ID
85
60

52
5S
AO
59
CO
53
5A
AO
5B
CO
54
5C
AO
50
CO
55

FS
FS
F8
FS
FS
F8

STA
LDX
LOA
LOX
ORA
STA
LOX
LOA
LOX
ORA
STA
LOX
LOA
LOX
ORA
STA
RTS

S52
S5S
SFSAO,X
S59
SFSCO ,X
S53
S5A
SF8AO,X
S5B
SFSCO,X
S54
S5C
SFSAO ,X
S50
SF8CO,x
S55

******************************
FSM FF FF FF FF FF FF FF FF
FSA8 FF 80 00 10 FF CO 40 50
FaBO FF FF 20 30 FF FO 60 70
F8B8 FF 90 AO BO FF 00 EO FF
F8CO
F8CS
F8DO
F80S

FF
FF
FF
FF

FF
OS
FF
09

FF
00
02
OA

FF
01
03
OB

FF
FF
FF
FF

FF
OC
OF
00

FF
04
06
OE

FF
05
07
FF

******************************
FSEO
A9 00
LOA #SOO
FSE2
S5 34
STA S34
F8E4
STA S2E
85 2E
F8E6
85 36
STA S36
FSE8
A9 01
LDA #SOI
F8EA
85 4E
STA S4E
LDA #SBA
F8EC
A9 BA
S5 4F
FSEE
STA S4F
FSFO
A5 31
LOA S31
FSF2
S5 2F
STA S2F
FSF4
20 E6 F7
JSR $F7E6
F8F7
A5 52
LDA S52
FSF9
85 3S
STA S3S
FSFE!
A4 36
LOY $36
FSFO
A5 53
LOA $53
FSFF
91 2E
STA ($2E),Y
F901
CS
INY
F902
A5 54
LOA $54
F904
91 2E
STA (S2E) ,Y
F906
CS
INY
F907
A5 55
LOA $55
F909
91 2E
STA ($2E) ,Y
F90B
CS
INY
F90C
84 36
STY S36
F90E
20 E6 F7
JSR $F7E6

252

Anatomy of the 1541 Disk Drive
F911
F913
F915
F917
F918
F91A
F91C
F91E
F91F
F921
F923
F924
F926
F928
F929
F92B
F92D
F92F
F931
F-933

A5
91
C8
FO
A5
91
C8
A5
91
C8
A5
91
C8
DO
A5
85
A5
85
60

F934
F936
F938
F93A
F93C
F93E
F940
F942
F944
F946
F948
F94A
F94C
F94E
F950
F953
F955
F957
F959
F9SB
F9S0
F95F
F961
F964
F966
F968

A5
85
A9
85
A9
85
A5
85
A5
85
A5
85
A5
85
20
A5
85
AS
85
A9
85
85
20
A5
85
60

F969
F96B
F96E
F970
F972
F975
F978

A4
99
AS
FO
20
20
A6

A4

36
52
2E

LDY
LDA
STA
INY
BEQ
LDA
STA
INY
LDA
STA
INY
LDA
STA
INY
BNE
LDA
STA
LOA
STA
RTS

$36
$52
($ 2E), Y

31
2F
00
31
24
34
39
52
1A
53
19
54
18
55
DO F6
17
52
16
53
00
54
55
00 F6
2F
31

LOA
STA
LOA
STA
LDA
STA
LDA
STA
LDA
STA
LDA
STA
LDA
STA
JSR
LDA
STA
LDA
STA
LOA
STA
STA
JSR
LOA
STA
RTS

$31
$ 2~'
#$00
$31
#$24
$ 34
$ 39
$52
$IA
$53
$19
$ 54
$18
$55
$F6DO
$17
$52
$16
$S3

3F
00 00
50
03
F2 F5
SF F9
49

LOY
STA
LDA
BEQ
JSR
JSR
LOX

$3F
$OOOO,y
$ 50
$ F'9 7 5
$F5F2
$F98F
$49

11
53
2E
54
2E
55
2E
El
53
3A
2F
31

$F92B
$53
($2E),Y
$54
(S2E),Y
$55
($2E),Y
$F90C
$53
$3A
$2F
$31

*SOD

$54
$55
SF600
$2F
$31

253

get stack pointer back

AnatOllly of the 1541 Disk Drive
F97A
F97B

9A
4C BE F2

F97E
F980
F982
F985
F987
F98A
F98C
F98E

A9
85
AD
09
8D
A9
85
60

AO
20
00 IC
04
00 IC
3C
48

LDA
STA
LDA
ORA
STA
LDA
STA
RTS

i$AO
$20
$ICOO
n04
$ICOO
$3C
$48

F98F
F991
F993
F995
F997
F999
F99B

A6
A5
09
85
A9
85
60

3E
20
10
20
FF
48

LDX
LDA
ORA
STA
LDA
STA
RTS

$3E
$20
#$10
S20
#$FF
$48

F99C
F99F
. F9A2
F9A5
F9A7
F9A9
F9AB
F9AD
F9AF
F9B1
F9B4
F9B6
F9BB
F9BA
F9BC
F9BF
F9C1
F9C3
F9C5
F9C8

AD
8D
. AD
29
C5
85
FO
A9
85
AD
FO
C9
DO
A9
80
FO
85
A9
8D
4C

07
05
00
10
IE
IE
04
01
lC
FE
15
02
07
00
FE
OA
4A
02
FE
2E

02
FA

LDA
STA
LDA
AND
CMP
STA
BEO
LDA
STA
LDA
BEO
CMP
BNE
LDA
STA
BEO
STA
LDA
STA
JMP

$IC07
SlC05
$ICOO
#$10
$1E
$lE
$F9B1
#$01
$IC
$02FE
$F9CB
#$02
$F9C1
#$00
$02FE
$F9CB
$4A
i$02
$02FE
$FA2E

F9CB
F9CD
F9CF
F9D1
F9D2
F9D4
F9D6

A6
30
A5
A8
C9
DO
4C

3E
07
20

$3E
$F9D6
$20

20
03
BE FA

LDX
BMI
LDA
TAY
CMP
BNE
JMP

F9D9
F9DB
F9DD
F9DE
F9EO
F9E2

C6
DO
98
10
29
85

48
ID
04
7F
20

IC
IC
IC

02

02

TXS
JMP $F2BE

DEC
BNE
TYA
BPL
AND
STA

turn drive motor off

write protect?

#$20
$F9D9
SFABE
$48
$F9FA
$F9E4
#$7F
$20
254

Anatomy of the 1541 Disk Drive
F9E4
F9E6
F9E8
F9EB
F9ED
F9FO
F9F2
F9F4
F9F6
F9F8
F9FA
F9FB
F9FD
F9FF

29
FO
AD29
8D
A9
85
A9
85
FO
98
29
DO
4C

FA02

6C 62 00

FA05
FA07
FA09
FAOB
FAOC
FADE
FA10
FA12
FA14
FA16
FA18
FA1A
FA1C
FA1E
FA20
FA22
FA24
FA26
FA28
FA2A
FA2C
FA2E
FA30
FA32
FA34
FA37
FA38

A5
10
49
18
69
C5
80
A9
85
A9
85
DO
E5
ES
85
A5
85
A9
85
A9
85
A5
10
E6
AE
CA
4C

10
12
00 1C
FB
00 1C
FF
3E
00
20
DC
40
03
BE FA

4A
05
FF
01
64
OA
3B
62
FA
63
12
SE
SE
61
5E
60
7B
62
FA
63
4A
31
4A
00 1C
69 FA

AND
BEO
LDA
AND
STA
LDA
STA
LDA
STA
REO
TYA
AND
BNE
JMP

#$10
$F9FA
$lCOO
#$FB
$lCOO
#$FF
$3E
#$00
$20
$F9D6

drive motor on

#$40
$FA02
$FARE

JMP ($0062)
LOA
BPL
EOR
CLC
AOC
CMP
BCS
LDA
STA
LDA
STA
BNE
SBC
SBC
STA
LDA
STA
LOA
STA
LDA
STA
LDA
BPL
INC
LDX
OEX
JMP

#$4A
$FAOE
#$FF
#$01
$64
$FA1C
#$3B
$62
#$FA
$63
$FA2E
SSE
SSE
$61
SSE
$60
#$7B
$62
#$FA
$63
$4A
SFA63
$4A
$lCOO

pointer $62/$63 to $FA3B

pointer S62/S63 to $FA7B
step counter for head transport
increment

SFA69

******************************
FA3B
A5 4A
LOA S4A
FA3D
DO EF
BNE $FA2E
FA3F
A9 4E
LOA #$4E
FA41
85 62
STA S62
FA43
A9 FA
LDA #$FA
FA4S
85 63
STA $63
FA47
A9 OS
LDA #$OS
FA49
85 60
STA $60
FA4B
4C BE FA
JMP $FABE
255

step counter for head tranFport
not yet zero?
pointer $62/$63 to $FA4E
counter to 5

Anatomy of the 1541 Disk Drive

******************************
FA4E
C6 60
DEC $60
BNE $FAFE
FASO
DO 6C
FAS2
AS 20
LDA $20
FAS4
29 BF
AND #$BF
85 20
FA56
STA $20
FAS8
LDA #$05
A9 05
85 62
FASA
STA $62
FASC
A9 FA
LDA #$FA
FASE
85 63
STA $63
FA60
4C BE FA
JMP $FABE
******************************
FA63
C6 4A
DEC $4A
FA6S
LDX $ICOO
AE 00 IC
FA68
E8
INX
8A
TXA
FA69
FA6A
29 03
AND #$03
FA6C
85 4B
STA $4B
FA6E
AD 00 IC
LDA $lCOO
FA7l
29 FC
AND #$FC
05 4B
FA73
ORA $48
FA7S
8D 00 lC
STA $ICOO
FA78
JMP SFABE
4C BE FA
******************************
FA7B
38
SEC
FA7C
AD 07 lC
LOA SlC07
FA7F
E5 5F
SBC $5F
FA8l
80 05 lC
STA $lCOS
FA84
C6 60
DEC $60
FA86
DO OC
RNE SFA94
FA88
A5 SE
LDA SSE
FA8A
85 60
STA S60
FA8C
A9 97
STA .$97
FA8E
85 62
STA $62
FA90
A9 FA
LOA #$FA
85 63
STA $63
FA92
FA94
4C 2E FA
JMP $FA2E

decrement counter
not yet zero?
erase bit 6

pointer $62/$63 to FAOS

step counter for head transport

stepper motor off

decrement counter
not yet zero?

pointer $62/$63 to $FA97

******************************

FA97
FA99
FA9B
FA9D
FA9F
FAAI
FAA3

C6
DO
A9
85
A9
85
DO

61
F9
AS
62
r'A
63
EF

DEC
RNE
LDA
STA
LDA
STA
BNE

$61
SFA94
.SA5
$62
.$FA
$63
$FA94

pointer 562/$63 to $FAA5

******************************
FAA5
AD 07 lC
LDA $IC07
FAA8
CLC
18
FAA9
65 5F
ADC $SF
FAAB
80 05 IC
STA $lC05

256

Anatomy of the 1541 Disk Drive

FAAE
FABO
FAB2
FAB4
FAB6
FAB8
FABA
FABC
FABE
FAC1
FAC3
FAC6

C6
DO
A9
85
A9
85
A9
85
AD
29
8D
60

60
E2
4E
62
FA
63
05
60
OC 1C
FD
OC 1C

DEC
BNE
LDA
STA
LDA
STA
LDA
STA
LDA
AND
STA
RTS

decrement counter
not yet zero?

S60
SFA94
#S4E
$62
#SFA
563
#S05
560
51COC
#5FD
SlCOC

pointer $62/S63 to SFA4E
counter to 5
erase bit 1

******************************

FAC?
FAC9
FACB
FACD
FACF
FAD1
FAD3
FAD5
FAD?
FAD9
FADB
FADE
FAEO
FAE3
FAE5
FAE8
FAEA
FAED
FAEF
FAF2

A5 51
10 2A
A6 3D
A9 60
95 20
A9 01
95 22
85 51
A9 M
85 4A
AD 00
29 FC
8D 00
A9 OA
8D 20
A9 AO
8D 21
A9 OF
8D 22
4C 9C

J~IP

$51
$FAF5
$3D
#$60
$20,X
#$01
$22,X
S51
#$M
$4A
SlCOO
#$FC
SlCOa
#SOA
$0620
#S40
S0621
#SOF
$0622
$F99C

FAF5
FAF?
FAF9
FAFB
FAFD

AO
D1
FO
91
4C

00
32
05
32
9C F9

LDY
CMP
BEO
STA
JMP

#$00
(S32), Y
SFBOO
(532) , Y
SF99C

FBOO
FB03
FB05
FBO?
FB09

AD
29
DO
A9
4C

00 lC
10

LDA
AND
BNE
LDA

$lCOO
#SlO
SFROC
#$08
SFDf'3

05

FBOC
FBOF
FB12
FB14
FBl?
FB1A
FBID
FB20

20
20
A9
8D
20
20
20
A9

A3
C3
55
01
C3
00
56
40

1C
1C
06
06
06
F9

08
D3 (,'D
FD
FD
lC
FD
FE
F'5

LDA
BPL
LDX
LDA
STA
LDA
STA
STA
LDA
STA
LDA
AND
STA
LDA
STA
LDA
STA
LDA
STA

J~IP

formatting
track number
fomatting already in progress
drive number
flag for head transport
set
set destination track
running track # for format
164
step counter for head tran~port
stepper motor on
10
error counter
S621/$622 = 4000
initialize track capacity
4000 < capacity < 2*4000 bytes
back in job loop

to job loop
write protect?
no
26, 'write protect on'

JSR $FDA3
JSR SFDC3
LDA #$55
STA $lC01
JSR $FDC3
JSR SFEOO
JSR $F556
LOA #$40

write SFF to disk 10240 times
code (S621/$622) times to disk
555
to write head
and (S621/S622) times to disk
switch to read
set timer, find SFF (SYNC)

257

Anatomy of the 1541 Disk Drive

FB22
FB25
FB28
FB2A
FB20
FB2F
FB32
FB35
FB37
FB39
FB3C
FB3E
FB41
FB43
FB46
FB49
FB4B
FB4E
FB4F
FBSI
FB52
FB54
FB55
FBS7
FBS9

00
80
A9
80
A9
80
80
AO
A2
2C
30
2C
10

OB
OB
62
06
00
07
05
00
00
00
FB
00
FB
AD 04
2C 00
10 11
AD 00
OA
10 F5
E8
DO EF
C8
DO EC
A9 02
4C D3

FBSC
FBSE
FB60
FB62
FB64
FB67
FB6A
FB6C
FB6F
FB70
FB72
FB73
FB75
FB76
FB78
FB7A

86
84
A2
AO
AD
2C
30
AD
OA
10
E8
00
C8
00
A9
4C

FB70
FB7E
FB7F
t'B81
FB82
FB84
FB85
FB87
FB88
FB8A
FB8C
FB8E

38
8A
E5
AA
85
98
E5
A8
8S
10
49
A8

18
18
18
18
18
lC
lC
18
lC
18

FD

71
72
00
00
04 18
00 IC
11
00 18
FS
EF
EC
02
03 FO

71
70
72
71
OB
FF

ORA
STA
LOA
STA
LOA
STA
STA
LOY
LDX
BIT
BMI
BIT
BPL
LDA
BIT
BPL
LDA
ASL
BPL
INX
BNE
INY
BNE
LDA
JMP

$180B
$180B
#$62
$1806
#SOO
S1807
S1805
#$00
#SOO
SICOO
SFB39
SlCOO
SFB3E
S1804
SlCOO
SFB5C
$1800
A
SFB46

S.FB43
#$02
SFDD3

overflow, then error
20, 'read error'

STX
STY
LDX
LDY
LOA
BIT
BMI
LOA
ASL
BPL
INX
BNE
INY
BNE
LOA
JMP

S71
S72
#SOO
#SOO
S1804
SlCOO
SFB70
S1800
A
SFB67

counter to zero again
reset timer 1 interrupt flag
SYNC found?
yes
interrupt-flag register
timer flag to bit 7
no, wait until timer run down

SFB64

increment counter

SFB64
#S02
$FOD3

overflow, then error
20, , read error'

$71

difference between counter

SEC
TXA
SBC
TAX
STA
TYA
SBe
TAY
STA
BPL
EOR
TAY

timer 1 free running
98 cycles, about 0.1 ms

start timer
counter to zero
SYNC found?
no, wait
SYNC found?
wait for SYNC
reset interrupt flag timer
SYNC found?
not SYNC (SS5)?
interrupt flag register
shift timer flag
timer not run down yet?
increment counter

$FB43
increment hi-byte of counter

$70
and value for SFF-storage
$72
bring to $70/S71
$71
SFB97
#SFF

difference positive?

258

Anatomy of the 1541 Disk Drive

FB8F
FB90
FB92
FB93
FB94
FB96
FB97
FB98
FB9A
FB9C
FB9E
FBAO
FBA2
FBA3
FBA5
F8A8
FBAB
FBAO
FBBO
FBB3
FBB6
FBB8
FBBA
FBBB
FBBE
FBCO
FBC2
FBC3
FBC4
FBC6
FBC7
FBC9
FBCB
FBCE
FBCF
FBDO
FB03
FBD4
FBD5
FB08
FBDA
FBDO
~'BEO

FBE2
FBE5
FBE7
FBE9
FBEA
FBEB
FBEE
FBFO
FBFl
FBF2

8A
49 FF
AA

E8
DO
C8
98
DO
EO
90
06
26
18
A5
60
8D
A5
6D
80
4C
A2
AO
B8
AD
10
50
B8
E8
DO
C8
DO

01
04
04
18
70
71

70
21
21
71
22
22
OC

06
06
06
06
FB

00
00

TXA
EOR #SFF
TAX
INX
BNE SFB97
INY
TYA
BNE SFB9E
CPX *S04
BCC SFBB6
ASL $70
ROL S71
CLC
LOA S70
AOC S0621
STA S0621
LDAS71
AOC S0622
STA S0622
JMP SFBOC

F2
A9 03
4C 03 FO

LOX
LOY
CLV
LOA
BPL
BVC
CLV
INX
BNE
INY
BNE
LOA
JMP

8A
OA
80
98
2A
80
A9
20
80
A9
80
A6
AO
98
18
6D
90
C8
C8
CA

TXA
ASL
STA
TYA
ROL
STA
LOA
AND
STA
LDA
STA
LOX
L.OY
TYA
CLC
AOC
BCC
INY
INY
DEX

00 1C
OE
59
F5

25 06
24
BF
OB
OB
66
26
43
00

06
18
18
06

26 06
01

calculate abs. val of difference

difference less than 4
yes

*

0.1 ms

double difference

add to 4000

repeat until diff

< 4 * 0.1 ms

*$00
#$00

counter to zero

SlCOO
$FBCE
SFBBB

SYNC?
no
byte ready?

SFBBB

increment counter

SFBBB
#$03
SFD03

overflow, then error
21, read error

A
S0625

double counter

A
S0624
*SBF
S180B
S180B
#S66
S0626
S43
#$00

and to S624/$625 as track cap.

102
number of sectors in this track

S0626
SFBn

259

Anatomy of the 1541 Disk Drive
FBF3
FBFS
FBF7
FBF8
FBFA
FBFB
FBFE
FCOO
FC03
FC04
FCOS
FC07
FC08
FCOA
FCOB
FCOE
FC10
FC12

DO
49
38
69
18
6D
BO
CE
AA
98
49
38
69
18
6D
10
A9
4C

FC1S
FC16
FC17
FCl9
FCIA
FCIC
FCIE
FCIF
FC21
FC22
FC24
FC27
FC29
FC2B
FC2D
FC30
FC31
FC33
FC36
FC38
FC3B
FC3D
FC3F
FC41
FC44
FC45
FC46
FC49
PC4C
FC4D
FC4P
FC52
F'CS3
PC55
PC58
FC59

A8
SA
A2
38
E5
BO
88
30
E8
DO
8E
EO
BO
A9
4C
18
65
8D
A9
8D
AO
A6
A5
99
C8
C8
AD
99
C8
A5
99
C8
B5
99
C8
B5

F5
FF
00
25 06
03
24 06
FF
00
24 06
05
04
D3 FD

00
43
03
03
F'5
26 06
04
05
05
D3 FD
43
27 06
00
28 06
00
3D
39
00 03
28 06
00 03
51
00 03
13
00 03
12

BNE
EOR
SEC
ADC
CLC
ADC
BCS
DEC
TAX
TYA
EOR
SEC
ADC
CLC
ADC
BPL
LDA
JMP
TAY
TXA
LDX
SEC
SBC
BCS
DEY
BMI
INX
BNE
STX
CPX
BCS
LDA
JMP
CLC
ADC
STA
LDA
STA
LDY
LDX
LDA
STA
INY
INY
LDA
STA
INY
LDA
STA
INY
LDA
STA
INY
LDA

calculate # of bytes

$FBEA
#$FF
#$00
$0625
$FC03
$0624
#$FF
#$00
$0624
$FC15
#$04
$FDD3

resul t

in A/X

22, 'read error'

#$00
total divided by number
of sectors ($43)

$43
$FC21
SFC24
$FCI9
$0626
#$04
$FC30
#$05
$FDD3

compare no. of bytes per interva
with minimum value
ok
23, 'read error'
remainder of division
plus number of sectors
save

$43
$0627
11$00
$0628
#$00
$3D
$39
$0300,y

counter for sectors
counter 10
drive number
constant 8, marker for heacer
in buffer

$0628
$0300,y

sector number
in buffer

$51
$0300,y

track number
in buffer

$13,x
$0300,y

ID 2

$12,X

ID 1

260

in huffer

Anatomy of the 1541 Disk Drive
FC5B
FC5E
FC5F
FC61
FC64
FC65
FC68
FC69
FC6B
FC6E
FC7l
FC74
FC77
FC7A
FC7D
FC80
FC82
FC84
FC85
FC86
FC87
FC88
FC8B
FC8C
FCBE
FC90
~'C92

FC95
FC96
FC97
FC98
FC9B
FC9E
FCAO
FCA2
FCA5
FCA7
FCAA
FCAC
FCAE
FCBl
FCB3
FCB6
FCB8
FCBA
FCBB
FCBC
FCBE
FCCO
FCC2
FCC4
FCC5
FCCS
FCCS
FCCC

99
C8
A9
99
C8
99
C8
A9
59
59
59
59
99
EE
AO
C5
90
98
48
E8
8A
90
EB
00
A9
85
20
68
A8
88
20
20
A9
85
20
85
20
A9
85
20
A9
8D
A2
50
88
CA
00
A2

00 03
OF
00 03
00 03
00
FA
FB
FC
FD
F9
28
28
43
BB

02
02
02
02
02
06
06

00 05
FA
03
31
30 FE

E5
F5
05
31
E9
3A
8F
00
32
OE
FF
01
05
FE

FD
FD
F5
F'7

FE
lC

FA
OA
A4 32
50 FE
B8
B9 00 03
SO 01 lC
C8
CA

STA
INY
LOA
STA
INY
STA
INY
LOA
EOR
EOR
EOR
EOR
STA
INC
LOA
CMP
BCC
TYA
PHA
INX
TXA
STA
INX
BNE
LOA
STA
JSR
PLA
TAY
OEY
JSR
JSR
LOA
STA
JSR
STA
JSR
LOA
STA
JSR
LOA
STA
LOX
BVC
CLV
DEX
BNE
LOX
LOY
BVC
CLV
LOA
STA
INY

S0300,Y

in buffer

#$OF
$0300,y

15
in buffer

$0300,y

15 in buffer

#800
$02FA,Y
$02FB,Y
S02FC,Y
S02FD,Y
$02F9,Y
$0628
$0628
843
$FC3F

generate checksum
increment counter
counter
compare with no. of sectors
smaller, then continue

$0500,X
SFC88
lI$03
$31
SFE30

buffer pointer to $300

$FOE5
$FOF5
lI$05
$31
$F5E9
$3A
$F78F
#$00
$32
$FEOE
#$FF
SlCOl
#$05
SFCB8

copy buffer data
copy data in buffer

to write head
write $FF 5 times
byte ready

SFCB8
#$OA
$32
$FCC2

10 times
buffer pointer
byte ready?

$0300,y
$lC01

data from buffer
write

buffer pointer to 8500
calculate parity for data buffer
and save

10 data written?

DEX

261

Anatomy of the 1541 Disk Drive
FCCD
~~CCF

FCD1
FCD3
FCD4
FCD6
FCD9
FCDA
FCDC
FCDE
FCEO
FCE2
FCE3
FCE6
FCE7
FCE9
FCEB
FCED
FCEE
FCFl
FCF4
FCF5
FCI-'7
FCF9
FCFB
FCFC
FCFE
FOOl
FD02
FD04
f'D06
FD09
FDOB
FDOC
FDOF
FDIO
FD12
FD14
FD15
FD17
FD19
FDIC
FDIE
FD20
FD21
FD23
FD24
FD27
FD29
FD2C
FD2E
FD30
FD32
FD34
FD36

DO
A2
50
B8
A9
8D
CA
DO
A9
A2
50
B8
80
CA
DO
A2
50
B8
BD
80
E8
DO
AO
50
B8
Bl
8D
C8
DO
A9
AE
50
B8
8D
CA
DO
AS
18
69
85
CE
DO
50
B8
50
B8
20
A9
8D
A9
85
A9
85
AS
80

F3

09
FE
55
01 lC
F5
FF
05
FE
01 lC
F7
BB
FE
00 01
01 lC
F4
00
FE
30
01 lC
F5
55
26 06
FE
01 lC
F7
32
OA
32
28 06
93
FE
FE
00 FE
C8
23 06
00
30
03
31
43
28 06

BNE
LOX
BVC
CLV
LDA
STA
DEX
BNE
LDA
LDX
BVC
CLV
STA
DEX
BNE
LDX
BVC
CLV
LOA
STA
INX
BNE
LDY
BVC
CLV
LDA
STA
INY
BNE
LOA
LOX
BVC
CLV
STA
DEX
BNE
LOA
CLC
ADC
STA
DEC
BNE
BVC
CLV
BVC
CLV
JSR
LDA
STA
LDA
STA
LOA
STA
LDA
STA

SFCC2
#S09
SFCD1

9 times
byte ready?

#S55
SlCOl

S55
write

SFCDI
#SFF
#S05
SFCEO

9 times?
SFF
5 times
byte ready?

SlC01

to wri te head

SI-'CEO
#SBB
SFCEB
SOlOO,X
SlC01

area SIRB to SIFF
save

SFCEB
#SOO
SFCF9

byte ready?

(S30), Y
SlCOl

256 bytes of data
write byte to disk

SFCF9
#$55
S0626
SFD09

S55
(S626) times

SlCOl

write

SFD09
S32
jlSOA
S32
S0628
SFCBl
SFD1E

decrement sector number

$FD21

byte ready?

SFEOO
HC8
$0623
#$00
S30
#S03
$31
S43
S0628

switch to reading
200

plus 10

byte ready?

buffer pointer to $200
number of sectors per track

262

Anatomy of the 1541 Disk Drive
FD39
FD3C
FD3E
FD40
FD42
FD43
FD46
FD48
FD4A
FD4B
F'D4C
FD4E
FD4F
FDSI
FDS3
FDS5

20
A2
AO
50
B8
AD
Dl
DO
C8
CA
DO
18
A5
69
85
4C

FD58
FDSB
FD5D
FD5F

56 F5
OA
00
FE

SF556
#$OA
#SOO
SFD40

wait for SYNC
10 data

SlCOl
(S30) ,Y
SFD58

read byte
compare with data in buffer
not equal, error

30
OA
30
62 FD

JSK
LDX
LDY
BVC
CLV
LDA
CMP
BNE
INY
DEX
BNE
CLC
LDA
ADC
STA
JMP

CE
DO
A9
4C

23 06
CF
06
D3 FD

DEC
BNE
LDA
JMP

S0623
SFD2C
#S06
SFDD3

decrement counter for attempts
not yet zero?
else error
24, Iread error l

FD62
FD65
FD67
FD69
FD6A
FD6D
FD70
FD72
FD73
FD7S
FD77
FD79
FD7A
FD7D
FD80
FD82
FD83
FD84
FD86
FD89
FD8B
FD8D
FD8F
FD91
FD93

20
AO
50
B8
AD
D9
DO
C8
DO
A2
50
B8
AD
D9
DO
C8
CA
DO
CE
DO
E6
A5
C9
BO
4C

56 F5
BB
FE

SF556
#SBB
SFD67

wait for SYNC

SlCOI
S0100,y
$FDS8

read byte
compa re with buffer contents
not equal, error

SFD67
#$FC
$FD77

next byte

SlCOl
S0500,y
$FD58

read byte
compare wi th buffer contents
not equal, then error

28 06
AE
51
51
24
03
9C F9

JSR
LDY
BVC
CLV
LDA
CMP
BNE
INY
BNE
LDX
BVC
CLV
LDA
CMP
BNE
INY
DEX
BNE
DEC
BNE
INC
LDA
CMP
BCS
JMP

FD96
FD98
FD9A
FD9C
FD9E
FDAO

A9
85
A9
85
A9
4C

FF
51
00
50
01
69 F9

LDA
STA
LDA
STA
LDA
JMP

01 lC
30
OE
F2

01 lC
00 01
E6
F2
FC
l"E
01 lC
00 OS
D6
F'l

byte ready?

$FD40
S30
#$OA
S30
$FD62

increment pointer by 10

byte ready?

byte ready?

next byte
$FD77
S0628
$F'D39
$Sl
$51
#S24
SFD96
$F99C

decrement sector counter
not yet zero?
increment track number
compare with 36, highest trkjf +1
greater, then formatting done
continue

#SFF
S51
#SOO
S50
#$01
SF969

track number to $FF

ok

263

Anatomy of the 1541 Oisk Orive

******************************
FDA3
FDA6
FDA8
FDAA
FDAD
FDAF
FDB2
FOBS
FDB7
FDB9
FOBB
FDBC
FDBD
FDBF
FDCO
FDC2

AO
29
09
80
A9
8D
80
A2
AO
50
B8
88
DO
CA
DO
60

OC
IF
CO
OC
FF
03
01
28
00
FE

IC
IC
IC
IC

FA
F7

LOA
AND
ORA
STA
LOA
STA
STA
LOX
LOY
BVC
CLV
DEY
BNE
DEX
BNE
RTS

$ICOC
#$lF
#$CO
$ICOC
#$FF
$lC03
$ICOl
#$28
#$00
$FDB9

switch PCR to writing

port A(read/write head) to outp\
write $FF to disk
40
byte ready?

$FD89
$FD89

******************************
FDC3
FDC6
FOC9
FDCB
FOCC
FOCD
FOCF
FOOO
F002

AE
AC
50
B8
CA
00
88
10
60

21 06
22 06
FE
FA
F7

LOX
LOY
BVC
CLV
DEX
BNE
DEY
BPL
RTS

$0621
$0622
$FDC9

AO
84
C8
84
4C

F'F
51
50
69 F9

LDY
STY
INY
STY
JMP

read/write ($621/$622) times
byte ready?

$FDC9
$FOC9

******************************
FD03
CE 20 06
DEC $0620
FDD6
FO 03
BEO $FDDB
FDDS
4C 9C F9
JMP $F99C

FDDB
FDDD
FDDF
FDEO
FDE2

write $FF 10240 times

attempt counter for formatting
decrement number of attempts
zero, then error
continue

#SF'F
$51

flag for end of formatting

$50
$f'969

error termination

******************************

FDE5
FDE8
FDEB
F'DEC
FDEE
FDFl
FDF4

B9
99
88
DO
AD
8D
60

00 03
45 03
F7
00 03
45 03

LDA
STA
DEY
BNE
LDA
STA
RTS

$0300,y
$0345,Y
copy buffer contents
$FDES
$0300
$0345

******************************

FDFS
FDF7
FDFA
FDFC
FDFD

AO
B9
91
88
10

44
BB 01
30
F8

LOY
LDA
STA
DEY
BPL

#$44
$OlBB,Y
($30),Y
$FDF7
264

SlBB to $lFF
write in buffer $30/$31

Anatomy of the 1541 Disk Drive
FDFF

60

RTS

******************************
FEOO
AD OC lC
LDA SlCOC
FE03
09 EO
ORA jl$EO
FE05
8D OC lC
STA SlCOC
FE08
A9 00
LDA #SOO
FEOA
80 03 lC
STA SlC03
FEOD
60
RTS
******************************
FEOE
AD OC lC
LDA SlCOC
29 IF
FEll
AND flSlF
09 CO
FEl3
ORA jlSCO
FE15
80 OC lC
STA $lCOC
FE18
A9 FF
LOA jI$FF
80 03 lC
FEIA
STA $lC03
FEID
A9 55
LDA #$55
FElF
80 01 lC
STA $lCOI
FE22
A2 28
LDX #$28
FE24
AO 00
LDY #$00
50 FE
FE26
BVC $FE26
FE28
B8
CLV
FE29
88
DEY
FE2A
DO FA
BNE $FE26
FE2C
CA
DEX
FE2D
DO F7
BNE $FE26
FE2F
60
RTS
******************************
FE30
A9 00
LOA #$00
FE32
85 30
STA $30
FE34
85 2E
STA $2E
FE36
85 36
STA $36
FE38
A9 BB
LOA #$BB
FE3A
85 34
STA $34
FE3C
LOA S31
A5 31
FE3E
85 2F'
STA $2F
A9 01
FE40
LOA #$01
FE42
85 31
STA $31
FE44
A4 36
LDY S36
FE46
B1 2E
LOA ($2E), Y
FE48
85 52
STA $52
FE4A
C8
INY
Bl 2E
FE4B
LOA ($2E), Y
85 53
STA S53
FE4D
FE4F
C8
INY
FE50
LDA ($2E) ,Y
B1 2E
FE52
85 54
STA S54
~'E54
C8
INY
FE55
B1 2E
LOA (S2E) ,Y
FE57
85 55
STA S55
FE59
C8
INY
FO 08
FE5A
BEO $FE64
FE5C
84 36
STY $36

265

switch to reading
switch PCR to reading
port A to input
write S55 10240 times
switch PCR to writing
port A to output (write head)
%01010101
to port A (write head)
byte ready for write electronics
10240 times

Anatomy of the 1541 Disk Drive
FE5E
FE61

02 DO F6
4C 44 FE

JSR $F6DO

FE64

4C DO F6

JMP $F6DO

'******************************
FE67
FE68
FE69
FE6A
FE6B
FE6C
FE6F
FE7l
FE73
FE76
FE79
FE7A
FE7C
FE7F
FE80
FEBI
FE82
FE83
FE84

48
8A
48
98
48
AD
29
FO
20
AD
OA
10
20
68
A8
68
AA
68
40

00 18
02
03
53 E8
00 Ie
03
BO F2

PHA
TXA
PHA
TYA
PHA
LOA
AND
BEQ
JSR
LOA
ASL
BPL
JSR
PLA
TAY
PLA
TAX
PLA
RTI

interrupt routine
save registera

$1800
*$02
$FE76
$E853
$lCOD
A
$FE7F
$F2f\0

interrupt from serial bus
no
serve serial bus
interrupt from timer I?
no
IRQ routine for disk controller
get register 'back

******************************
FE85 12
FE86 04
FE87 04
FE88 90

constants for disk format
18, track for BAM and directory
start of BAM at position 4
4 bytes in BAM for each track
$90 = 144, end of BAM, disk nam.

***********.******************
FE89 56 49 44 40 42 55
FE8F 50 26 43 52 53 4E

table of command words
'V', 'I',)'D', 'M', 'B', 'u'
'p'., '&', 'C', 'R', IS', 'N'

**************************'****

lo-bytes' of command addresses

FE95 84 05 Cl F8 IB 5C
FE9F 07 A3 FO 88 23 00

******************************

hi-bytes of command addresses

FEAI ED DO C8 CA CC CB
FEA7 E2 E7 C8 CA C8 EE
******************************
FEAD 51 DO lC 9E lC

bytes for syntax check

******************************

file control methods

FEB2 52 57 41 40
******************.************
FEB6 44 53 50 55 4C

******************************
FEBB 44 53 50 55 52

file types

'D', 'sot, 'P', 'u', 'L'

names of file types
1st letters '0', 'S', 'P',

266

'U'.

'R'

Anatomy of the 1541 Disk Drive
FECO 45 45 52 53 45
FEC5 4C 51 47 52 4C

2nd letters 'E', 'E', 'R', 'S', 'E'
3rd letters 'L', '0', 'G', 'R', 'L'

******************************

FECA 08 00 00
******************************
FECD 3F 7F BF FF

roasks for bit command

******************************
FED1 11 12 13 15

number of sectors per track
17, 18, 19, 21

******************************
FED5 4A
FED6 04
FED7 24
FED8 IF 19 12

contants for disk format
'A' marker for 1541 format
4 track numbers
36, highest track number + 1
31, 25, 18 tracks with change of
number of sectors

******************************
FEDB 01 FF FF 01 00

******************************
FEEO 03 04 05 06 07

control bytes for head position
addresses of buffers
high bytes

******************************
FEE5 07 OE
******************************
FEE7
6C 65 00
JMP ($0065)

for UI command

******************************
FEEA
8D 00 lC
STA $lCOO
8D 02 IC
FEED
STA $IC02
FEFO
4C 7D EA
JMP $EA7D

for diagnostic routine
turn LED on
port to output
back to diagnostic routine

******************************
FEF3
8A
TXA
FEF4
A2 05
LOX #$05
FEF6
CA
DEX
FEF7
DO FD
BNE $FEF6
FEF9
AA
TAX
FEFA
60
RTS

delay loop for serial bus

******************************

data output to serial bus
CLOCK OUT hi
DATA OUT 10

FEFB
FE FE

20 AE E9
4C 9C E9

JSR SE9AE
JMP $E99C

******************************
FFOI
AD 02 02
LOA $0202
FF04
C9 2D
CMP #S2D
FF06
FO 05
BEC) $FFOD
FF08
38
SEC
FF09
E9 2B
SBC #$2B
FFOB
DO OA
BNE SFEE7

267

about 40 microseconds

ur

vector

'-'
'+'

indirect jump over ($65)

Anatomy of the 1541 Disk Drive
FFOD
FFOF

85 23
60

STA $23
RTS

******************************
FFIO AA •• ,
FFEI ••• AA
******************************
FFE2 52 53 52 AA
FFE6 C6 CB 8F F9
******************************

FFEA
FFEC
FFEE
FFFO
FFF2
FFF4
FFF6
FFFB
FFFA

SF
97
00
03
06
09
OC
OF
01

CD
CD
05
05
05
05
05
05
FF'

USER vectors
UA, Ul, $CD5F
UB, U2, $CD97
UC, U3, $0500
UD, U4, $0503
UE, U5, $0506
UF, U6, $0509
UG, U7, $050C
UH, UB, $050F
UI, U9, $FFOI
(NMI vector not used)

******************************
FFFC OA EA
FFFE 67 FE

268

hardware vectors
$EAAO
RESET and UJ (U:) vectc
$FE67
IRQ vector

Anatomy of the 1541 Disk Drive
Chapter 4:

4.1

Programs and Tips for the 1541 Disk Drive

utility Programs

4.1.1

Displaying all File Parameters

The directory contains several important pieces of
information about each file. Some information is not kept in
the directory, such as the starting address of a program.
These and other file parameters can be easily found ard
displayed by the following program. The number and kind of
file parameters are naturally dependent on the file type. A
relative file, for instance, has no starting address. The
following table presents the parameters displayed by this
program.
FILE TYPE

PARAMETER

: DEL : SEO : PRG : USR : REL :
File closed?
File protected?
Allocated blocks
Side-sector blocks
Data blocks
Records
Start address

X
X
X

: Free blocks, disk
: Allocated bl. disk :

X
X

X

X
X

X
X
X

X
X
X

X
X
X
X
X
X

X
X

X
X

X
X
X

x
X

This program is documented in detail so that the serious
programmer can get a good overview of the file parameters.
In addition, the variables used by the program are
explained.
Variables used in the program:
Numerical Variables
T

-

Track of the actual block of the file entry in the
directory
S - Sector of the actual block of the file entry in the
directory
FL - Flag, set if the file name read from the diskette does
not agree with the searched-for file
TY - File type of the given file (byte 0 of the entry)

269

Anatomy of the 1541 Disk Drive
FT - nybble of the file type (bits 0-3), contains the
actual file type
LB - Low byte of the starting address
HB - High byte of the starting address
BL - Number of allocated blocks in the file
RL - Record length of a relative file
DT - Track of the first data block of a program file, which
contains the starting address
DS - sector of the first data block of a program file
SA - Starting address of a program file
BF - Number of free blocks on a disk
BA - Number of allocated blocks on a disk
BS - Number of side-sector blocks in a relative file
RC - Number of records in a relative file
String variables
F$ FF$FT$CL$-

Name of the file to search for
Contains the actual file name from the directory
File type
Indicates whether the file is closed or not
(contains "YES" or "NO")
PR$- Indicates whether the file is protected or not
(contains "YES· or "NO")
RES- contains CHR$(l8), REVERSE ON
RA$- contains CHR$(l46), REVERSE OFF

Program Documentation:
110
120 210 250 280 500 540 600 620 640 -

Set the color code of the screen
200 Program heading
230 Asks if the names should be listed out.
sets flag FL to 1 and executes the routine at
280-490.
no Input the filename. Asks for new input if the
filename if greater than 16 characters.
490 Reads the file name from the directory and either
displays it (FL=l) or compares it to the desired
filename.
530 Reads byte 0 (file type) of the file entry of the
desired file and stores it in TY. Also, the right
half-byte is stored in FT.
590 Checks the file type and saves the text in FT$,
and checks for invalid file type.
610 Checks bit 7 of the file type byte (file closed?)
and saves the result in CL$.
630 Checks bit 6 of the file type byte (file
protected?) and saves the result in PR$.
690 Reads the number of allocated blocks in the file
from bytes 28 and 29 of the file entry and saves
it in BL.

270

Anatomy o£ the 1541 Disk Drive

700 - 730 If it is relative file, the record length is read
from byte 21 and saved in RL
740 - 880 If it is a program file, the starting address of
the file is taken from the first data block and
stored in SA.
890 - 980 Free blocks on the disk are calculated by reading
the first byte of the track-marked BAM section
and added to BF. The allocated blocks are calculated by BA = 664 - BF
990 -1020 Here the number of side-sector blocks (BS) of a
relative file is calculated with the help of the
record length (RL) and the number of allocated
blocks in the file (RC).
1040-1230 Here the data can be sent to the screen or the
printer as one chooses. The file parameters are
shown in REVERSE.
1240-1280 The parameters of another file can be output.
The program is written for a CBM 64. In spite of this, it
can be run without major changes on a VIC 20. only line 110,
where the color of the screen is set, need be changed for
the VIC 20.
BASIC Listing of the program:
100
110
120
130
140
150
160
170
180
200
210
220
230
240
250
260
270
280
290
300
310
320
325
330
340
350
360
370
380
390

CLR
POKE 53280,2:POKE5328l,2:PRINTCHRS(158);CHR$(147);
PRINT TAB(6);"==========================="
PRINT TAB(6) ;"DISPLAY ALL FILE PARAMETERS"
PRINT TAB(6);"==========================="
PRINT:PRINT
PRINT"WITH THIS PROGRAM, ALL PARAMETERS OF A"
PRINT"FILE CAN BE OUTPUT TO THE SCREEN OR TO"
PRINT"A PRINTER AT YOUR OPTION."
PRINT:PRINT
PRINT"LIST FILENAMES (YIN)?"
GETX$:IFXS<>"Y"ANDX$<>"N"THEN220
IF XS="Y"THENFL=1:GOSUB280
FL=O
INPUT"NAME OF THE FILE: ";FS
IFLEN(F$)<=16THEN280
PRINT"FILENAME TOO LONG!":GOT0250
OPEN 15,8,15,"IO":OPEN2,8,2,"I"
T=lB:S=l
PRINTI15,"B-R";2;0;T;S
PRINTI15,"B-P";2;0
GETI2,X$:IFXS=""THENXS=CHR$(0)
T=ASC(X$)
GETX$:IFX$=""THENX$=CHR$(O)
S=ASC(X$)
FORX=OT07
PRINT#15,"B-P";2;X*32+5
FF$=""
FOR¥=OT015
GETI2,X$:IFX$=""THENX$=CHR$(0)
271

Anatomy of the 1541 Disk Drive
400
410
420
430
440
450
460
470
4BO
4B5
490
500
510
520
530
540
550
560
570
5BO
590
600
610
620
630
640
650
660
670
680
690
700
710
720
730
740
750
760
770
780
790
800
BI0
820
830
840
850
860
B70
8RO
890
900
910
920
930

IF ASC(XS)=160THEN430
FFS=FFS+X$
NEXT Y
IFF$=FFSTHEN490
IFFLTHENPRINTFFS
NEXT X
IF T=O THEN 4BO
GO TO 300
CLOSE2:CLOSEI5
IFFL=OTHENPRINT"FILENAME NOT FOUND!":GOT0210
IFFLTHENRETURN
PRINTI15,"B-P";2;X*32+2
GETi2,X$:IFX$=""THENX$=CBRS(0)
TY=ASC(XS)
FT=TYAND15
IFFT=OTHENFT$="DELETED"
IFFT=lTHENFT$="SEOUENTIAL"
IFFT=2THENFTS"'''PROGRAM"
IFFT=3THENFT$="USER"
IFFT=4THENFT$="RELATIVE"
IFFT>4THENPRINT"INVALID FILE TYPE!":GOT0200
IFTYAND128THENCLS"'''YES'':GOT0620
CLS="NO"
IFTYAND64THENPR$="YES":GOT0640
PRS="NO"
PRINTI15,"B-P";2;X*32+30
GET.2,X$:IFXS=""THENXS-CHRS(0)
LB"'ASC(X$)
GET,2,X$:IFX$=""THENX$-CHRS(0)
HB=ASC(X$)*256
BL=LB+HB
IFFT<>4THEN740
PRINTI15,"B-P";2;X*32+23
GETi2,XS:IFXS=""THENXS=CHR$(0)
RL=ASC(X$)
IFFT<>2THENB90
PRINTI15,"B-P";2;X*32+3
GETi2,X$:IFX$=""THENX$-CHR$(0)
DT=ASC (X$)
GETI2,X$:IFX$-""THENX$=CHR$(0)
DS=ASC(X$)
OPEN3,8,3,","
PRINT'15,"B-R";3;0;DT;DS
PRINTI15,"R-P";3;2
GET#3,X$:IFX$=""THENX$=CHRS(0)
LB=ASC(X$)
GET.3,X$:IFX$=""THENX$=CHR$(0)
HR=ASC(X$)*256
SA=LR+HB
CLOSE3
PRINTi15,"R-R";2;0;18;0
BF=O
FORI-4TOI40STEP4
IFI-72THEN960
PRINTi15,"B-P";2;I
272

Anatomy of the 1541 Disk Drive
940 GET#2,XS:IFX$=""THENX$=CHRS(O)
950 BF=ASC(X$)+BF
960 NEXT
980 BA=664-BF
990 IFFT<>4THENl040
1010 BS=BL/12l:IFBS<>INT(BS)THENBS=INT(BS+1)
1020 RC=INT«(BL-BS)*254)/RL)
1040 PRINTCHRS(147);"SCREEN OR PRINTER (S/P)?"
1050 GETXS:IFXS<>"S"ANDXS<>"P"THENl050
1060 RES=CHRS(18):RA$=CHRS(146)
1070 IFXS="S"THENOPENl,3:PRINTI1,CHR$(147)
1080 IFXS="P"THENOPENl,4
1090 PRINT'l,"FILE PARAMETERS
";RE$;FS;ROS
1100 PRINT#l,"------------------------------------"
1110 PRINTil,"FILE TYPE:
";RES ;FT$ ;RAS :PRINTjll
1120 PRINTil,"FILE CLOSED:
";RE$;CL$;RAS:PRINT'l
1130 PRINTi1,"FILE PROTECTED:
";RE$;PRS;RA$:PRINTll
1140 PRINTil,"ALLOCATED BLOCKS:
";RES;BL;RAS:PRINTll
1150 IFFT<>4THEN1200
1160 PRINTJI 1, "RECORD LENGTH:
";RES;RL;RA$:PRINTil
1170 PRINTil,"SIDE-SECTOR BLOCKS:
";RES;BS;RAS:PRINTII
1180 PRINTl1,"DATA BLOCKS:
";RE$;BL-BS;RA$:PRINTil
1190 PRINTi1,"RECORDS:
";RE$;RC;RA$:PRINTjll
n:
1200 IFFT=2THENPRINTi1,"START ADDRESS:
RES;SA;RAS:PRINTil
";RES;BF;RA$:PRINTU
1210 PRINTi1,"FREE BLOCKS (DISK):
1220 PRINTil,"ALLOCATED BLOCKS (D):";RE$;BA;RA$:PRINTII
1230 CLOSEI
1240 PRINT"MORE (Y/N)?"
1250 CLOSE2:CLOSE15
1260 GETX$:IFX$<>"Y"ANDX$<>"N"THEN1260
1270 IFXS="Y"THEN100

4.1.2

Scratch-protect Files - File Protect

As already mentioned, it is possible to protect files on the
VIC-IS4l diskette and save this information in the
directory. A file's type is contained in byte 0 of the file
entry. Bit 6 denotes a protected file. If this bit is set to
1, the file can no longer be deleted with the SCRATCH
command. But because the DOS has no command to set this bit
an alternative way must be used to protect a file.
with the following program, you can:
* display all files on the disk
* protect files
* unprotect files
* erase files
This program can delete protected files as well as
unprotected files. If you wish to delete a protected file,
273

Anatomy of the 1541 Disk Drive
you must confirm it. This program is also documented with a
variable usage and descriptions so that you can use these
techniques in your own programs.
List of variables:
OF
FL
FT
T
S
TT
SS
FFS
F$

- Flag, set in the routine "read/search file" if the
desired filename is found
- Set i f the routine "read/search file" is only to be
used for listing files
- variable for storing the filetype
Track of the actual block of the file entry
- Sector of the actual block of the file entry
- Track, in which the file entry block of the desired
file is found
- Sector, in which the file entry block of the desired
file is found
.
- last filename read from the directory
- filename to search for

Program Documentation:
100
Set the screen color
110 - 230 Program header and option menu
240 - 260'Read the menu choice and call the appropriate
subroutine
270
Back to the option menu
280 - 350 Subprogram "list all files"
310 Erase screen
320 Set flag FL to list files in the subroutine
"read/search file"
350 Reset the flag and jump back
360 - 600 Subroutine "protect file"
390 Call subroutine "input filename"
400 Call the subroutine "read/search file"
410 - 450 Test if the file is found
460 - 480 Read file type and store in FT
490 - 500 Test if the file is already protected
510 Protect file (bit 6 to 1)
520 - 550 Transfer the file type to the buffer and write the
block to disk
560 Close the channel
570 - 600 Message "File protected" and jump back
610 - 850 Subroutine "unprotect file"
640 Call subroutine "input filename"
650 Call subroutine "read/search file"
660 - 700 Test if file is found
710 - 730 Read file type and store in FT
740 - 750 Test if the file is already unprotected
760 Unprotect the file (bit 6 to 0)
770 - 800 Transfer the file type to the buffer and write
the block to the disk
810 Close the file
820 - 850 End the subroutine
274

Anatomy of the 1541 Disk Drive
860 -1170
890
900
910 - 950
960 - 980
990
1000-1030
1040-1060
1070
1080-1110
1120
1130
1140-1170
1190-1560
1220
1230-1240
1250-1320

1330
1340-1350
1360-1390
1400-1530
1540-1560

Subroutine "erase a file"
Call the subroutine "input filename"
Call the subroutine "read/search file"
Test if the file is found
Read the file type and save in FT
Test if the file is protected
Indicate that the file is protected, with the
possibility to erase it anyway
Ask if the file should really be erased
Bit 6 set back, if protected
Transfer the file type to the buffer and write
the block to the disk
Initialize the diskette
Erase the file
End the subroutine
Subroutine "read/search file"
open the command and data channels
Read directory and set buffer pointer
Test if the disk contains a write protect. For
this purpose, the directory is written back to the
disk unchanged (line 1250). If the disk has a
write protect tab on it, the error message 26,
WRITE PROTECT ON will occur.
Initial values for the track and sector variab1e~
are set
Read the file entry block and position the buffer
pointer to the first byte
Read the address of the next file entry block
Loop to read filenames. The names are then either
listed on the screen or compared to the desired
filename, based on the value of flag FL
If the variable T (track) contains zero, no more
file entry blocks follow and the subroutine ends.

BASIC Listing of the Program:
100
110
120
130
140
150
160
180
190
200
210
220
230
240
250
260
270
280
290

POKE 53280,2:POKE53281,2:PRINTCHR$(158);CHR$(147);
PRINTTAB(8);"===================-==="
PRINTTAB(8);"ERASE AND PROTECT FILES"
PRINTTAB(8);"======================="
PRINT:PRINT
PRINT"WITH THIS PROGRAM, FILES CAN BE"
PRINT"PROTECTED, ERASED, AND UNPROTECTED"
PRINT:PRINT
PRINTTAB(6);" -1- LIST ALL FILES":PRINT
PRINTTAB(6);" -2- PROTECT A FILE":PRINT
PRINTTAB(6);" -3- UNPROTECT A FILE":PRINT
PRINTTAB(6);" -4- ERASE A FILE":PRINT
PRINTTAB(6);" -5- END THE PROGRAM":PRINT
GETX$: I FX$= ''''ORVAL (X$ ) (lORVAL( X$) >5THEN240
IFVAL(X$)=5THENEND
ONVAL(X$)GOSUB280,360,610,860
GaTO 100
REM -------------REM LIST ALL FILES
275

Anatomy of the 1541 Disk Drive
300
310
320
330
340
350
360
370
380
390
400
410
420
430
440
450
460
470
480
490
500
510
520
530
540
550
560
570
580
590
600
610
620
630
640
650
660
670
680
690
700
710
7 20
730
740
750
760
770
780
790
800
810
820
830
840

REM -------------PRINTCHR$(147)
FL=I:GOSUBI190
PRINT:PRINT"RETURN FOR MORE"
INPUTX$
FL=O: RETURN
REM -------------REM PROTECT A FILE
REM -------------GOSUB1580
GOSUB1l90
IFDF=ITHEN460
PRINT"FILE NOT FOUND!":PRINT
PRINT"RETURN FOR MORE"
INPUTX$:CLOSE2:CLOSEI5
RETURN
PRINT.15,·B-P"~2~X*32+2

GETII2,X$:IFX$="ITHENX$=CHR$(O)
FT=ASC(X$)
IF(FT AND 64)=0 THEN 510
PRINT"FILE IS ALREADY PROTECTED!":PRINT:GOT0430
FT=(FT OR 64)
PRINTtI5,"B-P"~2~X*32+2
PRINT'2,CHR$(FT)~
PRINT'15,·B-P"~2~0
PRINTII15,·U2";2;0;TT~SS

CLOSE2:CLOSE15
PRINT"FILE PROTECTED."
PRINT"RETURN FOR MORE"
INPUTX$
CLOSE2:CLOSEI5:RETURN
REM ---------------REM UNPROTECT A FILE
REM ---------------GOSUB158o
GOSUB1l90
IFDF=lTHEN710
PRINT"FILE NOT FOUND!":PRINT
PRINT"RETURN FOR MORE"
INPUTX$:CLOSE2:CLOSE15
RETURN
PRINTII15,"B-P":2;X*32+2
GET# 2 ,X$: I FX$=" "THENX$=CHR$ (0)
FT=ASC(X$)
IF (FT AND 64)=64THEN760
PRINT"FILE IS ALREADY UNPROTECTED!":PRINT:GOT0680
FT=(FTAND255-64)
PRINT#15,"B-P":2:X*32+2
PRINTII2,CHR$(FT);
PRINTlII5,"B-P";2;0
PRINT#15,"U2";2;0;TT;SS
CLOSE2:CLOSEI5
PRINT"FILE UNPROTECTED."
PRINT"RETURN FOR ~lORE"
INPUTX$
276

Anatomy of the 1541 Disk Drive
850 RETURN
860 REM -----------870 REM ERASE A FILE
880 REM -----------890 GOSUB1580
900 GOSUB1l90
910 IFDF=lTHEN960
920 PRINT"FILE NOT FOUND!":PRINT
930 PRINT"RETURN FOR MORE"
940 INPUTX$:CLOSE2:CLOSE15
950 RETURN
960 PRINTI15."B-P";2;X*32+2
970 GET.2.X$:IFX$= .... THENX$=CHR$(0)
980 FT=ASC(X$)
990 IF(FT AND 64)=OTHENI040
1000 PRINT"WARNING! FILE IS PROTECTED!"
1010 PRINT"UNPROTECT AND ERASE (YIN)?"
1020 GETX$:IFX$<>"Y"ANDX$<>"N"THENI020
1030 IFX$="N"THENl170
1040 PRINT"ARE YOU SURE (YIN)?"
1050 GETX$:IFX$<>"y"ANDX$<>"N"THENI050
1060 IFX$="N"THENl170
1070 FT=(FT AND 255-64)
1080 PRINTI15."B-P":2;X*32+2
1090 PRINT,2.CHR$(FT);
1100 PRINT,15."B-P";2;0
1110 PRINTI15."U2";2;0;TT;SS
1120 PRINT,15."IO"
1130 PRINTI15."S:"+F$
1140 PRINT"FILE ERASED."
1150 PRINT"RETURN FOR MORE"
1160 INPUTX$
1170 CLOSE2:CLOSEI5:RETURN
1180 REM
1190 REM -----------------1200 REM READ I SEARCH FILE
1210 REM -----------------1220 OPENI5.8.15 ... IO .. :OPEN2.8.2 ......
1230 PRINTI15."B-R":2;0:18;0
1240 PRINTI15."B-P";2;0
1250 PRINTI15."U2";2;O;18;0
1260 INPUTI15.Xl$
1270 IF VAL(Xl$)<>26 THEN 1330
1280 PRINT"PLEASE REMOVE THE WRITE PROTECT TAB FROM"
1290 PRINT"THE DISKETTE BEFORE USING THIS PROGRAM."
1300 PRINT"RETURN FOR MORE"
1310 INPUTXS
1320 CLOSE2:CLOSE15:RETURN
1330 T=18:S=I:TT=18:SS=1
1340 PRINTI15."B-R";2;0;T;S
1345 TT=T:SS=S
1350 PRINTI15."B-P";2;O
1360 GETI2.X$:IFXS= .... THENX$=CHR$(0)
1370 T=ASC(X$)
1380 GET.2.X$:IFX$= .... THENX$=CHR$(0)
277

Anatomy of the 1541 Disk
1390
1400
1410
1420
1430
1440
1450
1460
1470
1480
1490
1500
1510
1520
1530
1540
1550
1560
1570
1580
1590
1600
1610
1620
1630
1640
1650
1660

Dri~e

S=ASC(X$)
FORX=OT07
PRINTilS,"B-P";2;X*32+2
GET,2,X$:IFX$=""THENX$=CHR$(0)
IFASC(X$)=OTHENlS30
PRINTI15,"B-P";2;X*32+5
FF$=""
FORY=OTOI5
GET'2 ,X$: IFXS=" "THENX$=CHR$ (0)
IFASC(X$)=160THEN1500
FF$=FF$+X$
NEXTY
IFFLTHENPRINTFF$:GOTOI530
IFF$=FF$THENDF=1:GOT01570
NEXTX
IFT<>OTHENI340
CLOSE2:CLOSEIS
IFFL=OTHENPRINT"FILENAME NOT FOUND!":FORI=lT02000:
NEXT
RETURN
REM -------------REM INPUT FILENAME
REM -------------PRINT:PRINT
INPUT"FILENAME:";F$
IFLEN(F$)<=16THEN1650
PRINT"FILENAME TOO LONG!":GOT01620
DF=O:FL=O
RETURN

This utility program was written for the CBM 64. This
version can also be run on the VIC 20. Only line 100 which
sets the screen color on the CBM 64 need be changed or
ignored. If you value perfect video output, lines 110-230
can also be changed to accommodate the VIC 20's smaller
screen size.

4.1.3

Backup Program - Copying a Diskette

The VIC 1541 disk drive does not allow disks to be
duplicated since it is a single drive, as the double drives
permit with the COpy or BACKUP commands of BASIC 4.0. With
the 1541, each program to be copied must be transferred
through the computer.
Here's an example of how you might copy a diskette using a
single disk drive:
First, the BAM as well as the names and IDs of the disk to
be copied are read into the computer. From the information
in the BAM, you can determine which blocks of the original
diskette are used. In order to save time, only the allocated
278

Anatomy of the 1541 Disk Drive

blocks are copied. Then a direct access file is opened and
the first 169 (as many as will fit in the memory of t~e
Commodore 64) allocated blocks are read. Then the user is
asked to put a new diskette in the drive. The new diskette
is then formatted with the name and ID of the original
diskette. Now the previously read blocks are written to the
diskette. The next 169 blocks of the original diskette are
read into memory and written out to the destination
diskette. This ends after four disk swaps, at which time the
entire diskette will have been copied.
The program is written in BASIC except for the portion which
reads and writes the direct access file. This part is
written in machine language which is considerably faster
than a GET# loop in BASIC. Because of the nature of the
program, the number of diskette changes is dependent on the
free storage in the computer. A VIC 20 with a 16K expansion
requires 11 changes of original and destination diskettes.
Here is a time comparison between this program and
duplication on a double drive with the same capacity. Our
program requires about 20 minutes, while the CBM 4040 does
it in about 3 minutes.
Duplicating a diskette with this program is quite simple.
You need only follow the messages on the screen to insert
the original or destination diskette. The program does the
rest for you.
100
110
120
130
140
150
160
170
180
190
200
210
220
230
240
250
260
270
280
290
300
310
320
330
340

REM BACKUP PROGRAM C64 - VIC 1541
REM
POKE56,23:CLR:GOSUB640
OPENl,8,l5
DIM B%(35,23),S%(35),Z(7),A$(1l
A$ (0) ="DESTINATION" :A$ (1) ="ORIGINAL": R=l
AD=23*256:GOSUB590
POKE250,0:POKE251,AD/256
GOSUB530:GOSUB290
PRINTNS"BLOCKS TO COPY":PRINT
T=l:S=O
FORI=lT04:TT=T:SS=S:R=1:IFI=lTHEN240
IFR=OANDI=lTHENGOSUB450:GOT0240
GOSUB590
POKE251,AD/256:FORJ=lT0169
IFB%(T,S)=OTHENGOSUB570
S=S+1:IFS=S%(T)THENT=T+l:S=0:IFT=36THENJ=169
NEXT:IFRTHENR=O:T=TT:S=SS:GOT0220
NEXT:GOT0510
T=18:S=0:GOSUB570
NS=0:FORT=lT035:S=0
NS=NS+S%(T)-PEEK(AD+4*T)
FORJ=lT03
B=PEEK(AD+4*T+J)
FORI=OT07
279

Anatomy of the 1541 Disk Drive
340
350
360
370
380
390
400
410
420
430
440
450
460
470
480
490
500
510
520
530
540
550
560
570
580
590
600
610
620
630
640
650
660
670
680
690
700
710

FORI=OT07
B%(T,S)=B AND Z(I):S=S+l
NEXT I,J
FOR S=S%(T)T023
B%(T,S)=-l : NEXT S,T
FOR I=OT015
A=PEEK(AD+144+I)
IFA<>160THENN$=N$+CHR$(A)
NEXT
I$=CHR$(PEEK(AD+162»+CHR$(PEEK(AD+163»
PRINTNS,I$:RETURN
PRINT"PLEASE INSERT NEW DISKETTE"
PRINT"AND PRESS RETURN":PRINT:POKE198,0:CLOSE2
GETA$:IFAS<>CHR$(13)THEN470
PRINT#I,"NO:"NS","I$
INPUTlIl,A ,B$,C, D: IFATHENPRINTA" , "BS" , "c" , "D: END
GOT0630
CLOSE2:CLOSEl:END
REM SECTORS PER TRACK
FORT=lT035
S%(T)=21:IFT>17THENS%(T)=19:IFT>24THENS%(T)=18:
IFT>30THENS%(T)=17
NEXT
FORI=OT07:Z(I)=2'tI:NEXT:RETURN
IFRTHENPRINT#l,"Ul 2 0"T1S:SYSIN:RETURN
PRINT#l,"B-P 2 0":SYSOUT:PRINT#1,"U2 2 0"T1S:RETURN
CLOSE2:PRINT"PLEASE INSERT "A$(R)" DISKETTE."
PRINT"AND PRESS RETURN":PRINT:POKE198,0
GETA$:IFA$<>CHR$(13)THEN610
PRINT#I,"IO"
OPEN2,8,2,"#":RETURN
FOR I = 828 TO 873 : REM READ MACHINE LANG. PROGRAM
READ X : POKE I,X : S=S+X : NEXT
DATA 162, 2, 32,198,255,160, 0, 32,207,255,145,250
DATA 200,208,248,230,251, 32,204,255, 96,198, 1,162
DATA
2, 32,201,255,160, 0,177,250, 32,210,255,200
DATA 208,248,230,251, 32,204,255,230, 1, 96
IF S<>7312 THEN PRINT "ERROP IN DATA!!":END
IN=828:0UT=849:PETURN

4.1.4

Copying Individual Files to another Diskette

The following program permits you to copy individual files
from one diskette to another. The files can be programs
(PRG), sequential files (SEO) or user files (USP). Relative
files cannot be copied with this program1 these can be
copied with a ~ASIC program that reads all data records into
a string array and then writes them back again into a new
file.
In the first pass, the program reads the complete file into
the memory of the Commodore 64. Then the destination
280

Anatomy of the 1541 Disk Drive

Next the complete file is written on the second disk. The
computer has 49 Kbytes for data storage; you can handle up
to 196 blocks on the diskette.
For reasons of speed, the reading and writing of the data is
performed by a machine language program, which is stored in
DATA statements.
The program is suited for copying sequential files as
already mentioned, as well as programs of all kinds; the
start address (of a machine language program) is not
relevant.
100 REM FILE COPIER PROGRAM C64
llO REM
120 POKE 56,12 : CLR
130 GOSUB 1000
140 INPUT"FILENAME ";NS
150 PRINT"FILE TYPE ";
160 GETT$:IFT$<>"S"ANDT$<>"P"ANDT$<>"U"THENI60
170 PRINTT$:PRINT
180 PRINT"PLEASE INSERT ORIGINAL DISK"
190 PRINT"AND PRESS A KEY":PRINT
200 GETA$:IFA$=""THEN200
210 OPEN 2,8,2,N$+","+T$
220 POKE 3,0:POKE 4,12:SYS 866
230 CLOSE 2
240 PRINT"PLEASE INSERT DESTINATION DISK"
250 PRINT"AND PRESS A KEY":PRINT
260 GETA$:IFA$=""THEN260
270 OPEN 2,8,2,N$+","+T$+",W"
280 POKE 3,0:POKE 4,12:SYS 828
290 CLOSE 2 : END
1000 FOR I = 828 TO 898
1010 READ X : POKE I,X : S=S+X : NEXT
1020 DATA 162, 2, 32,201,255,198, 1,160, 0, 56,165, 3
1030 DATA 229, 5,165, 4,229, 6,176, 13,177, 3, 32,210
1040 DATA 255,230, 3,208,236,230, 4,208,232,230, 1, 76
1050 DATA 204,255,162, 2, 32,198,255,160, 0, 32,207,255
1060 DATA 145, 3,230, 3,208, 2,230, 4, 36,144, 80,241
1070 DATA 165, 3,133, 5,165, 4,133, 6, 76,204,255
1080 IF S<>8634 THEN PRINT "ERROR IN DATA !!":END
1090 RETURN

4.1.5

Reading the directory from within a program

Sometimes applications programs store user data in a file
under a desired name. If you want to use this file again,
but you cannot remember the fi Ie name, then you have a
problem. If this happens, you must exit the program, search
for the name in the directory, reload the program and start
281

Anatomy of the 1541 Disk Drive

again. To avoid this, you can include a directory listing
routine in your program. If you forget the filename, you can
display the directory with a function key, for example,
without ·the need to leave the program. Here is a sample of
such a routine:
100
110
120
130
140
150
160
170
180
190
200
210
220
230
240
250
260
270
280
290
300
310
320
330
340

PRINTCHR$(147);
OPEN15,8,15,"IO":OPEN2,8,2,"JI"
T-18:S=1
PRINT'15,"B-R";2;0;T;S
PRINT'15,"B-P";2;0
GET.2,X$:IFXS=""THENX$=CHR$(0)
T=ASC(X$)
GET,2,X$:IFX$=""THENX$=CHR$(0)
S=ASC(X$)
FORX=OT07
PRINT'15,"B-P";2;X*32+5
FF$=·..•
FORY=OT015
GET'2,X$:IFX$=""THENXS=CHRS(0)
IFASC(X$)=160THEN270
FF$=n'S+X$
NEXTY
IFA=OTHENA=1:PRINTFF$;:GOT0290
A=0:PRINTTAB(20);FF$
NEXTX
IFT<>OTHEN130
CLOSEl:CLOSE2
PRINT"RETURN FOR MORE"
INPUTX$
END:REM IF SUBROUTINE, THEN RETURN HERE

In order to select the filename, the directory is printed on
the screen. Should this program be used as a subroutine
(called with GOSUB) line 340 must contain RETURN instead of
END.
We used this routine in the utility programs in sections
4.1.1 and 4.1.2.

282

Anatomy of the 1541 Disk Drive
4.2

The utility Programs on the TEST/DEMO Disk

There are many 1541 owners that know little about the
programs contained on the Test/Demo disk. The main reason is
that these programs are largely undocumented. The following
descriptions of these programs should help you:

4.2.1

DOS 5.1

The DOS 5.1 simplifies the operation of the VIC-1541 OOS. It
can run on the VIC-20 or Commodore 64. To load DOS 5.1 on
the VIC-20, give the commands
LOAD"VIC-20 WEDGE",8
RUN
This is the loader for DOS 5.1 for the VIC 20.
If you want to use
commands:

it on the Commodore 64,

give

the

LOAD"C-64 WEDGE",8
RUN
This loads DOS 5.1 into the CBM 64.
What does this DOS 5.1 offer? It allows you to send
convenient commands to the 1541 disk drive. If, for example,
you want to display the directory on the screen, you use the
DOS 5.1 command @$ or >$. This does not erase the program in
memory.
The individual commands of the DOS 5.1
Command

Function

@$ or >$
@V or >V
@C: ••• or >C: •••
cfile or /file
@ or >
@N: ••• or >N: •••
@I or >1
@R: ••• or >R: •••
@S: ••• or >S: •••
@#n
or >lIn

Display the directory
Same function as "VALIDATE"
Copy files (COPY)
Load program
Read and display error message
Format a diskette
Intitialize the disk
Rename a file (RENAME)
Erase a file (SCRATCH)
Change disk device to n

283

Anatomy of the 1541 Disk Drive
4.2.2

COPY/ALL

With the program COPY/ALL files can be copied between disk
drives with different addresses. A drive must be changed
from device address 8 with the program DISK ADDR CHANGE
before this can occur. After starting the program, the
message:
disk copy all

jim butterfield

from unit? 8
appears on the screen. Here you give the device address of
the disk drive from which you wish to get the files. If this
address is 8, just press RETURN. After this you give the
corresponding drive number of this unit (always 0 for single
drives). In this manner you also give the device address of
the destination drive. Once this has occurred, the program
asks
want to new the output disk
?n
You are being asked if the destination diskette should te
formatted. You answer with 'y' (yes) or 'n' (no).
Then you can choose the files you want to copy with the
wildcard (*). If all files are supposed to be copied, just
give the asterisk.
Now the program gives the message
hold down 'y' or 'n' key to select
The program displays the files on the original disk, which
you can select with the 'y' key (yes) or 'n' (no). The files
by which you pressed 'y' will be copied.
If, during the copying process, asterisks (***) appear behind
the files, it means that an error has occurred.
If there is not enough room on the destination disk, "***
output disk full" and "do you have a new one" appears. The
remaining files can be put on another formatted diskette. To
do this, answer 'y' when ready.
At the the conclusion of the copying process, the number of
free blocks on the destination disk is displayed.

4.~.3

DISK ADDR CHANGE

with this program, the device address of a disk drive can tee
changed through software. After starting the program, turn
all drives off except for the one you wish to change. Now
enter the old and new device addresses.

284

Anatomy of the 1541 Disk Drive
After this, the address is
be turned back on.

changed and the other drive can

The following drives can be changed with this program:
2031
2040
4040
4040
8050
8050
8250

4.2.4

DOS
OOS
DOS
OOS
DOS
OOS
DOS

V2.6
Vl.l
V2.l
V2.7
V2.5
v2.7
V2.7

DIR

This is a small
possibil i tes:

help

program

with

the

following

d - display the directory on the screen
> - With this character, a disk command can be given
in shortened form (for example, >N:TEST,KN to
format a diskette)
q - exit the program
s - display the error channel
These possibilities are also found
other commands.

4.2.5

in DOS 5.1, along with

VIEW BAM

With this utility program you can view the usage
blocks on the screen. This table displays the
columns and the tracks in rows. Crosses indicate
and reverse crosses indicate allocated blocks.
that these blocks do not exist on the track.

of diskette
sectors in
free blocks
'n/a' means

After outputting the table, the diskette name and the number
of free blocks is displayed.

4.2.6

CHECK DISK

The utility program CHECK DISK tests every block on the
diskette by writing to and reading from it. The current
285

Anatomy of the 1541 Disk Drive
block and the total number of tested blocks is displayed on
the screen.

4.2.7

DISPLAY T&S

If you are interested in the construction of the individual
blocks of the disk and want to display these on the screen,
this utility program will help you. After starting the
program you give the desired track and sector. This will
then be sent to the printer or screen. The DISK-MONITOR
contained in this book is a easier to use, because it allows
you to change blocks and save them again.

4.2.8

PERFORMANCE TEST

This program makes it possible to test the mechanics of the
VIC-1541 disk drive. To accomplish this, all the access
commands are executed, in the following order:
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.

Disk is formatted
A file is opened for reading
Data are written to this file
The file is closed again
This file is opened for reading
The data are read
The file is closed again
The file is erased
Track 35 is written
Track 1 is written
Track 35 is read
Track 1 is read

After each access of the disk the error channel is
displayed. In this manner, it can be established which
access of the disk is not executed properly.
When using this program, use only diskettes containing no
important data because the entire diskette is erased during
the testing.

286

Anatomy of the 1541 Disk Drive
4.3

BASIC-Expansion and Programs for easy Use of the 1541

4.3.1

Input strings of desired length from the disk

Reading data from the disk with the INPUT# statement has one
major disadvantage - only data items having fewer than 88
characters can be read. This is because the input buffer of
the computer is limited. In addition, not all characters can
be read with the INPUT# statement. If a record contains a
comma or colon, BASIC views it as a separating character and
the remainder of the input is assigned to the next variable.
If the INPUT# statement has only one variable, the remainder
is ignored and the next INPUT# statement continues reading
past the next carriage return (CHRS(13». The alternative,
to read the input with a GET# statement but results in much
slower input.
To avoid these disadvantages, we can use a small machine
language routine.
We will change the INPUT# statement, so that we can specify
the number of characters to be read. To distinguish it from
the normal INPUT# statement, we name the command INPUT*. The
syntax looks like this:
INPUT* Ifn, len, var
Lfn is the logical file number of the previously OPENed
file, len is the number of characters to be read, and var is
the string variable into which the characters are to be
read. A program excerpt might look like this:
100 OPEN 2,8,2,"FILE"
110 INPUT* 2,100,A$
This reads a string of 100 characters from the opened file
into AS. This procedure is especially suited for relative
files, because a complete record can be read with one
command after positioning the record pointer. The
partitioning of record into fields can be accomplished with
the MIDS function. An elegant method of creating"records is
described in the next section.
With this procedure it is no longer necessary to end a
record with a carriage return. You can especially make use
of the maximum record length with relative files:
100
110
120
130
140

OPEN 1,8,15
OPEN 2,8,2, "REL-FILE,L,"+CHRS(20)
PRINT#l, "P"+CHR$(lO)+CHR$(O)+CHR$(l)
PFINT#2, "12345678901234567890":
PRINT#l, "P"+CHR$(lO)+CHF$(O)+CHRS(l)
287

Anatomy of the 1541 Disk Drive
150 INPUT* 2,20,A$
160 PRINT A$
12345678901234567890
Here is the assembler listing for the machine language
program. It resides in the cassette buffer just lik.e a
loader program in BASIC for the Commodore 64 and VIC 20.
110:

033C

,
150:
160:
170:
180:
190:

033C
033C
033C
033C
033C

210:
220:
380:
390:
400:
410:
420,
430:
440:
450:
460 :
470:

033C
033C
033C
033C
033C
033C
033C
033C
033C
033C
033C
033C

INPliT
STAR
BASVEC
CHRGET
CHRGOT

,

033C
033C
033C
033C
033C
033C
033C
033C
033C
033C

1

033C
033C
033C

530
540
550
560
570

033C
033C
033E
0340
0343

$EllE
$E1l2
$AEFD
$A7AE
$A7E7
$ABBF
$B08B
$B475
$B6A3
$B79E

EOli
EOli
EOli
EOli
EOli
EOli
EOli
EOli
EOli
EOli

$EllB
$EIOF
$CEFD
$C7AE
$C7E7
$CBBF
$008B
$D475
$D6A3
$D79E

COMMON LABELS

VARADR
CLRCH
PARA
A9
An
8D
8C

EOli
EOU
EOli
EOli
EOli
EOli
EOli
EOli
EOli
EOli

VIC 20 VERSION

CHKIN
BASIN
CHKCOM
INTER
EXECOLO
INPliTOLO
FINOVAR
STRRES
FRESTR
GETBYT

.

$85
$AC
$308
$73
CHRGET + 6

C64 VERSION

CHKIN
BASIN
CHKCOM
INTER
EXECOLD
INPUTOLO
FINOVAR
STRRES
FRESTR
GETBYT
1

490:
500:
510:

EOli
EOli
EOli
EOli
EOli

,

1

,
240:
250:
260:
270:
280:
290:
300:
310:
320:
330 :

INPliT* LFN,LEN,A$

47
INIT
03
08 03
0<) 03
288

EOli
EOli
EOli

$49
$FFCC
$61

ORG
LOA
LOY
STA
STY

828
#TEST
BASVEC
BASVEC+1

Anatomy of the 1541 Disk Drive
580:

0346 60

600:
610 :
620:
630 :
640:

0347
034A
034C
034E
0351

650:
660:

0354 20 73 00 FOUND
0357 C9 AC

670:
680 :
680:
690:

0359
035B
035E
0361

FO
20
4C
20

700:
710:
720:
730 :
730:
740:
750:

0364
0367
036A
036D
036E
036F
0372

760:
760:
770:
780:
790:
800:
810:
820:
830 :
840:
850:
860:
870:
880:
890:
900:
910:
910:

,

JSR
CMP
BEQ
JSR
JMP

CHRGET
#INPUT
FOUND
CHRGOT
EXECOLD

JSR
CMP

CHRGET
#STAR

06
BF AB
AE A7
9B B7 OKSTAR

BEO
JSR
JMP
JSR

OKSTAR
INPUTOLD
INTER
GETBYT-3

20
20
20
8A
48
20
20

IE El
FD AE
9E B7

JSR
JSR
JSR
TXA
PHA
JSR
JSR

CHKIN
CHKCOM
GETBYT

0375
0377
0379
037C
037D

85
84
20
68
20

49
4A
A3 B6

STA
STY
JSR
PLA
JSR

VARADR
VARADR+l
FRESTR

0380
0382
0385
0387
0388
038A
038B
038E
0390
0391
0393
0395
0398

AO
B9
91
88
10
C8
20
91
C8
C4
DO
20
4C

02
61 00 STORE
49

LDY
LDA
STA
DEY
BPL
INY
JSR
STA
INY
CPY
BNE
JSR
JMP

#2
PARA,Y
(VARADR) ,Y

20
C9
FO
20
4C

73 00 TEST
85
06
79 00
E7 A7

RTS

FD AE
8B BO

75 B4

F8
12 El FETCH
62
61
F6
CC FF
AE A7

TO THE OLD
ROUTINE
NEW INPUT
ROUTINE

GET FILE
NUMBER
LENGTH
NOTICE

CHKCOM
FINDVAR

SEARCH FOR
VARIABLE

LENGTH
RESERVE PLACE
FOR STRING

STRRES

STORE
Y=O
BASIN
(PARA+l) ,Y
PARA
FETCH
CLRCH
INTER

;TO INTERPRETER
LOOP

Here are the BASIC programs for entering
language program for the INPUT* statement.
INPUT*

,

the

machine

64 Version

100 FOR I = 828 TO 922
110 READ X : POKE I,X
S=S+X : NEXT
3,141, 8,
3,140,
120 DATA 169, 71,160,
289

9,

3, 96, 32

Anatomy of the 1541 Disk Drive
130
140
150
160
170
180
190
200
210

DATA 115, 0,201,133,240, 6, 32,121, 0, 76,231,167
DATA 32,115, 0,201,172,240, 6, 32,191,171, 76,174
DATA 167, 32,155,183, 32, 30,225, 32,253,174, 32,158
DATA ~83,138, 72, 32,253,174, 32,139,176,133, 73,132
DATA 74, 32,163,182,104, 32,117,180,160, 2,185, 97
DATA
0,145, 73,136, 16,248,200, 32, 18,225,145, 98
DATA 200,196, 97,208,246, 32,204,255, 76,174,167
IF S <> 11096 THEN PRINT "ERROR IN DATA!!" : END
SYS 828 : PRINT ·OK."

'INPUT· , VIC 20 VERSION
100
110
120
130
140
150
160
170
180
190
200
210

FOR I = 828 TO 922
READ X : POKE I,X : S=S+X : NEXT
DATA 169, 71,160, 3,141, 8, 3,140, 9, 3, 96, 32
DATA 115, 0,201,133,240, 6, 32,121, 0, 76,231,199
DATA 32,115, 0,201,172,240, 6, 32,191,203, 76,174
DATA 199, 32,155,215, 32, 27,225, 32,253,206, 32,158
DATA 215,138, 72, 32,253,206, 32,139,208,133, 73,132
DATA 74, 32,163,214,104, 32,117,212,160, 2,185, 97
DATA
0,145, 73,136, 16,248,200, 32, 15,225,145, 98
DATA 200,196, 97,208,246, 32,204,255, 76,174,199
IF S <> 11442 THEN PRINT "ERROR IN DATA!!" : END
SYS 828 : PRINT ·OK."

4.3.2

Easy preparation of 'Data Records

If you have worked with relative files before, you know that
a definite record length must be established. This record is
usually divided into several fields which likewise begin at
a definite position within the record, and have a set
length.
If you create a new record, for example, a separate INPUT
statement is generally used for each field. Befora the
complete record can be written, it must be assembled
properly. Each field must be checked for proper length. If
it is longer than then the planned length of the
corresponding data field, the remainder must 'be truncated to
the proper length. Here are two new BASIC commands that are
excellently suited for this task. These new commands are
written in machine language and are initialized with a SYS
command. You can then use them as any other BASIC commands.
The first command has the name !STR$ and serves to create a
string with the length of the data record.
A$

=

!STR$(100,· ")

290

Anatomy of the 1541 Disk Drive
creates a string with 100 blanks and puts it in the variable
A$.
The next command places our data field in the previously
created string. For example, if you want to assign the
variable N$ containing the last name as a field of 25
characters at position 1 in the string A$, our new command
looks like this:
MID$ (A$,1,25)

= N$

Here the MID$ command is used as a so-called pseudo-variable
on the left side of the assignment statement. What happens
here is as follows:
The variable N$ replaces the first 25 characters of A$. If
the variable N$ is longer than 25 characters, only the first
25 characters are replaced and the rest are disregarded. If
N$ is shorter than 25 characters, only as many characters
are replaced as N$ contains. The original characters in P$
remain (blanks, in our case). That is exactly as we wanteC!.
Now we can program the following:
200
210
220
230
240
250
260
270
280
290
300
310
320
330

INPUT "LAST NAME
INPUT "FIRST NAME
INPUT "STREET
INPUT "CITY
INPUT "STATE
INPUT "ZIP CODE
A$ = !STR$ (92, "
MID$ (A$,1,25)
MID$ (A$,26,20)
MID$ (A$,46,20)
MID$ (A$,66,15)
MID$ (A$,81,2)
MID$ (A$,83,9)
PRINT*2, A$

",H,

."",,.
;

U)

".,

L$
F$
S$
C$
T$
Z$

L$
F$
S$
C$
't$
Z$

Here is the machine language program for the Commodore 64
135:
140:
150:
160:
170:
180:
190:
200:
205:
210 :
220:
226 :
229:
230:
231:

C800
C800
C800
C800
C800
C800
C800
C800
C800
C800
C800
C800
C800
C800
C800

CHKOPEN
CHKCLOSE
CHKCOM
FRMEVL
CHKSTR
FRESTR
YFAC
CHRGET
CHRGOT
GETBYT
INTEGER
DESCRPT
STRADR
ADR2
291

ORG
EOU
EOU
EOU
EOU
EOU
EQU
EOU
EOU
EOU
EQU
EQU
EOU
EOU
EOU

$C800
$AEFA
$AEF7
$AEFD
$AD9E
$AD8F
$B6A3
$B3A2
$73
CHRGET+6
$B79B
$B1AA
$64
$62
$FB

Anatomy of the 1541 Disk Drive
232:
233:
234:
235:
236:
237:
238:
240:
241 :
242:
243:
245:
248:
248:
248:
248:
248:
250:
250:
250:
251 :
251:
251:
251 :
252:
252:
252:
253:

C800
C800
C800
C800
C800
C800
C800
C800
C800
C800
C800
C800
C800
C802
C804
C807
C80A
C80D
C80F
C8ll
C814
C816
C818
C81B
C81E
C821
C823
C825

ADRI
LENI
LEN2
NUMBER
START
TYPFLAG
STRCODE
ILLOUAN
SYNTAX
POSCODE
VECTOR
TEMP
A9
AO
8D
8C
4C
A9
85
20
C9
FO
20
4C
20
C9
FO
4C

OD
C8
OA
OB
6B
00
OD
73
21
06
79
8D
73
C4
03
08

03
03
C8
TESTIN
00
00
AE
00 TEST2
AF

EOU
EOU
EOU
EOU
EOU
EOU
EOU
EOU
EOU
EOU
EOU
EOU
LDA
LDY
STA
STY
JMP
LDA
STA
JSR
CMP
BEO
JSR
JMP
JSR
CMP
BEO
JMP

$FB+2
3
4
5
6
13

$C4
$B248
$AF08
$B9
$30A
LEN1
#TESTIN
VECTOR
VECTOR+1
MIDSTR
#0
TYPFLAG
CHRGET
# I'! ..
TEST2
CHRGOT
$AE8D
CHRGET
#STRCODE
STRING
SYNTAX

STRING$ FUNCTION
;

900:
900:
910:
920 :
920:
930:
940:
950:
960:
970:
980:
990:
1000:

C828
C82B
C82E
C831
C832
C833
C836
C839
C83B
C83D
C840
C842
C844

20
20
20
8A
48
20
20
24
30
20
A5
DO
A5

1010:
1020:

C846 4C 52 C8
C849 20 82 B7 STR

JMP
JSR

1030:
1040:
1050:
1060:
1070:
1080:

C84C
C84E
C850
C852
C854
C855

BEO
LDY
LDA
STA
PLA
JSR

FO
AO
B1
85
68
20

73 00 STRING
FA AE
9E B7
FD AE
9E AD
OD
OC
AA Bl
64
24
65

lA
00
22
03

JSR
JSR
JSR
TXA
PHA
JSR
JSR
BIT
BMI
JSR
LDA
BNE
LDA

STR2

7D B4

292

CHRGET
CHKOPEN
GETBYT+3

;OPEN PAREN

,NOTICE LENGTH
CHKCOM
FRMEVL
TYPFLAG
,STRING
STR
INTEGER
DESCRPT
,HIGH BYTE
ILL
>255
DESCRPT+l ; LOW BYTE,
LENGTH
STR2
$B782
;SETSTR
TYPFLAG TO
NUMERIC
ILL
;LENGTH 0
#0
($22) ,Y
,FIRST CHAR
TEMP
;LENGTH
$B47D
,FRESTR

AnatOJ1lY of the 1541 Disk Drive
A8
FO 07
A5 03
88
91 62

TAY
BEO
LDA
DEY
STA

1090:
1100 :
1110:
ll20 :
ll20:

C858
C859
C85B
C85D
C85E

1130 :
1140 :

C860 DO FB
C862 20 CA B4 STR3

BNE
JSR

1150:
1160 :

C865 4C F7 AE
C868 4C 48 B2 ILL

JMP
JMP

LOOP

;
;
;
;

STR3
TEMP
(STRADR) ,Y ; CREATE
STRING
LOOP
$B4CA
;BRING STRING
IN DESCRIPTOR STACK
CHKCLOSE
ILLQDAN

MID$(STRINGVAR,POS,LEN) = STRING EXP
MID$(STRINGVAR,POS) = STRING EXP

200:
210:

C86B
C86B

MIDconE
EXECUT

EOU
EOD

240:
250:
255:
260:
270:
280:
290:
325:
330:
355:
360:
370:
372:
375:
378 :

C86B
C86B
CB6B
C86B
CB6B
C86B
C86B
CB6B
C86B
0003
0004
0005
0007
0007
0007

EXECOLD
VARNAM
VARADR
DESCRPT
TESTSTR
GETVAR
SETSTR
TEST
GETBYT

EOU
EOU
EOU
EOD
EQD
EOU
EOD
EOU
EQU
ORG
DST
DST
DST
EOU
EQU

400:
410:
420:
430:
440:
450:
460:
470:
480:
490:

C86B
C86D
C86F
C872
C875
C876
C879
C87B
C87D
C880

A9
AO
8D
8C
60
20
C9
FO
20
4C

76
MIDSTR
C8
08 03
09 03

500
505
510
520
530
535
535
540
545
545

C883
C886
C889
C88C
C88E
C890
C892
C894
C897
C899

20
20
20
85
84
85
84
20
AO
B1

73
FA
8B
64
65
49
4A
A3
00
64

LENGTH
POSITION
VARSTR
cmlP
POINT2

73 00 MIDTEST
CA
06
79 00
E7 A7

LDA
LDY
STA
STY
RTS
JSR
CMP
BEO
JSR
JMP

00 MID
AE
BO

JSR
JSR
JSR
STA
STY
STA
STY
JSR
LDY
LDA

B6

293

$CA
$308 ;VECTOR FOR
STATEMENT EXECUTE
$A7E7
$45
$49
$64
SAD8F
$B08B
$AA52
$AEFF
$B79E
3
1
1
2
SB2
$50
#rnDTEST
EXECUT
EXECUT+l
CHRGET
#MIDCODE
;CODE FOR MID$
MID
;?
YES
CHRGOT
EXECOLD
;EXECUTF.
NORt1AL STATEMENT
CHRGET
;NEXT CHAR
CHKOPEN
;OPEN PAREN
GETVAR
;GET VAR
DESCRPT
DESCRPT+1
VARADR
VARADR+l
FRESTR
#0
(DESCRPT) , Y

Anatomy of the 1541 Disk Drive
545:
545:
550:

CB9B 4B
CB9C FO 2E
CB9E 20 52 AA

PHA
BEO
JSR

560:
560:
560:
570:
570:
570:
600:
610:
620:
630:
650:
650:
660:
660:

CBAI
CBA3
CBA5
CBA7
CBAB
C8AA
CBAC
CBAF
C8B2
C8B3
CBB5
CBB6
CBBB
CBBB

AO
Bl
B5
CB
Bl
B5
20
20
BA
FO
CA
B6
20
C9

01
49
05

LDY
LDA
STA
INY
LDA
STA
JSR
JSR
TXA
BEO
DEX
STX
JSR
CMP

665:
665 :
665:
670:
670 :
6BO:
690:
700:
710:
715 :
715:
715:
717:
717:
717:
720 :
730:
770:
7BO:
790:
BOO:
800:
BOO:
800 :
800:
800:
810:
BI0:
820:
840 :
B50:
860:
870:
B80:
B80:
910:

CBBD
CBBF
CBCl
CBC3
CBC6
C8C9
CBCA
C8CC
C8CF
CBDI
C8D2
CBD3
CBD5
C8D7
C8D9
C8DB
CBDE
CBEO
CBE3
CBE6
CBE9
CBES
CBED
CBEF
C8FO
C8F2
C8F4
C8F5
C8F7
C8F9
C8FB
C8FD
C8FF
C90l
C902
C904

DO
A9
DO
20
20
BA
DO
4C
B5
6B
3B
E5
C5
BO
85
20
A9
20
20
20

04
FF
OC
FD AE NEXT
9E B7

49
06
FD AE
9E B7
17
04
79 00
29

03
4B B2 ILL
STORE
03

04
03
02
03
F7
B2
FF
9E
A3
AD 02
Bl 64
85 51
88
Bl 64
85 50
BB
Bl 64
f'O D3
C5 03
80 02
85 03
AS 05
18
65 04
B5 05

AE OK
AE
AD
B6

OKI

BNE
LDA
BNE
JSR
JSR
TXA
BNE
JMP
STA
PLA
SEC
SBC
CMP
BCS
STA
JSR
LDA
JSR
JSR
JSR
LDY
LDA
STA
DEY
LDA
STA
DEY
LDA
BEO
CMP
BCS
STA
LDA
CLC
ADC
STA
294

; LENGTH
ILL
SETSTR

; PUT STRING IN
RAM

#1
(VARADR) ,Y
VARSTR
;VAR ADDR
(VARADR), Y
VARSTR+l
CHKCOM
GETBYT
;GET POS
ILL
POSITION
CHRGOT
II") "
; END OF
EXPRESSION?
NEXT
jI$FF
;MAX LENGTH
STORE
CHKCOM
GETBYT
;GET LEN
*+5
ILLOUAN
LENGTH
POSITION
LENGTH
OK
LENGTH
CHKCLOSE ;CLOSE ·PAREN
#COMP
TEST
FRMEVL
;GET EXP
FRESTR
#2
(DESCRPT),Y
POINT2+1
(DESCRPT),Y
POINT2
(DESCRPT),Y
ILL
;0 THEN ERROR
LENGTH
OKI
LENGTH
VARSTR
POSITION
VARSTR

Anatomy of the 1541 Disk Drive
910:
920 :
940:
950:
950:

C906
C908
C90A
C90C
C90D

90 02
E6 06
A4 03
88
B1 50

960:
970:
970:
980:

C90F
C911
C913
C915

91
CO
DO
4C

05
00
F7
AE A7

LOOP

BCC
INC
LDY
DEY
LDA
STA
CPY
BNE
JMP

*+4
VARSTR+1
LENGTH
(POINTl) ,Y ,TRANSFER
CHARS FROM STRING
(VARSTR) ,Y IEXP TO VAR
#0
LOOP
$A7AE ,TO INTERPRETER
LOOP

For those who have no monitor or assembler for the Commodore
64, we have written a loader program in BASIC.
100
110
120
130
140
150
160
170
180
190
200
210
220
230
240
250
260
270
280
290
300
310
320
330
340
350
360
370

FOR I = 51200 TO 51479
READ X : POKE I,X : S=S+X : NEXT
DATA 169, 13,160,200,141, 10, 3,140, 11, 3, 76,107
DATA 200,169, 0,133, 13, 32,115, 0,201, 33,240, 6
DATA 32,121, 0, 76,141,174, 32,115, 0,201,196,240
DATA
3, 76, 8,175, 32,115, 0, 32,250,174, 32,158
DATA 183,138, 72, 32,253,174, 32,158,173, 36, 13, 48
DATA 12, 32,170,177,165,100,208, 36,165,101, 76, 82
DATA 200, 32,130,183,240, 26,160, 0,177, 34,133, 3
DATA 104, 32,125,180,168,240, 7,165, 3,136,145, 98
DATA 208,251, 32,202,180, 76,247,174, 76, 72,178,169
DATA 118,160,200,141, 8, 3,140, 9, 3, 96, 32,115
DATA
0,201,202,240, 6, 32,121, 0, 76,231,167, 32
DATA 115, 0, 32,250,174, 32,139,176,133,100,132,101
DATA 133, 73,132, 74, 32,163,182,160, 0,177,100, 72
DATA 240, 46, 32, 82,170,160, 1,177, 73,133, 5,200
DATA 177, 73,133, 6, 32,253,174, 32,158,183,138,240
DATA 23,202,134, 4, 32,121, 0,201, 41,208, 4,169
DATA 255,208, 12, 32,253,174, 32,158,183,138,208, 3
DATA 76, 72,178,133, 3,104, 56,229,. 4,197, 3,176
DATA
2,133, 3, 32,247,174,169,178, 32,255,174, 32
DATA 158,173, 32,163,182,160, 2,177,100,133, 81,136
DATA 177,100,133, 80,136,177,100,240,211,197, 3,176
DATA
2,133, 3,165, 5, 24,101, 4,133, 5,144, 2
DATA 230, 6,164, 3,136,177, 80,145, 5,192, 0,208
DATA 247, 76,174,167
IF S <> 31128 THEN PRINT "ERROR IN DATA!!" : END
SYS 51200 : PRINT ·OK."

4.3.3

Spooling - Printing Directly from the Disk

If you have a printer connected to your computer in addition
to the disk drive, you can use a special characteristic of
the the serial bus.
It

is possible to send files
295

directly

from disk to the

Anatomy of the 1541 Disk Drive
printer, without the need to transfer it byte by byte with
the computer. For example, if you have text saved as a
sequential file, and you want to print it on the printer,
the following program allows you to do so:
100
110
120
130
140
150

OPEN 1,4 : REM PRINTER
OPEN 2,8,2, "O:TEST" : REM TEXT FILE
GET#2, AS : IF ST = 64 THEN 140
PRINT#l, ASl : GOTO 120
CLOSE 1 : CLOSE 2
END

Characters are sent from the disk to the printer until the
end of file is recognized. Then the two files are closed apd
the program ended.
The following is done when spooling:
First both files are opened again. Then a command to receive
data (Listen) is sent to the printer, while the disk drive
receives the command to send data (Talk). Data are sent
automatically from the disk to the printer until the end of
file is reached. During this time, the computer can be used
without interferring with the transfer of data. Only the use
of peripheral devices is not possible during this time.
In practice, this is done with a small machine language
program.
When you want to start printing, you call the
program and give the name of the file which you want to
send.
SYS 828. "TEXTOPENs the file TEXT on the diskette and sends it to the
printer. As soon as the transfer is begun, the computer
responds with READY. again and you can use it, as long as no
attempt is made to access the serial bus. You can prove that
the computer is no longer needed for transfer by pulling out
the bus cable to the disk, so that the diskette is connected
only to the printer. When the spooling is done, the disk
file is still open (the red LED is still lit). You can CLOfE
the file and turn the printer off and then back on, and give
the SYS command without a filename (the cable to the disk
must be attached, of course).
SYS 828
Wi th same command you can stop a transfer in progress. The
machine language program in the form of a loader program for
the Commodore 64 and the VIC 20 is found at the end.
Here are some hints for use:
We have successfully used the printer spooling with a
Commodore 64 and a VIC 20 with a printer such as the the VIC
296

Anatomy of the 1541 Disk Drive
1525. Attempts using an Epson printer with a VIC interface
as well as the VIC 1526 did not succeed. The serial bus, in
contrast with the parallel IEEE bus, appears to be capable
of spooling only with limitations. This is why it is
necessary to turn the printer off after spooling, because it
still blocks the bus. we would be happy if you would inform
us of your experience with other printers.
~
~

110:
130 :
140:
142 :
144:
160:
170:
175:
180 :
190,
200:
202 :
204 :
230:
240:
260:
280:

033C
033C
033C
033C
033C
033C
033C
033C
033C
033C
033C
033C
033C
033C
033C
033C
033C

300:
310 :
320:
330:
340,
350:
360:
370:
380:
390:
400:
410:
411:
412:
413:
420
430
435
435
435
510
520
530
540
550
560

033C
033C
033F
0341
0344
0347
0349
034B
034D
034F
0351
0354
0357
0359
035C
035F
0361
0364
0367
036A
036D
036F
0371
0373
0374
0376

1541 - 64 SPOOL

CHRGOT
LISTEN
ATNRES
CLOCK
DATA
CLOSE
CLALL
SETFIL
GETNAME
OPEN
CHKIN
UNTALK
UNLISTEN
FNLEN
INDEV
NMBFLS
ERROR
20
FO
20
20
A6
FO
A9
A2
AO

79
33
E7
54
B7
38
02
08
02
BA
CO
04
Bl
BE
02
C6
BE
85
97
00
99
98

20
20
A9
20
20
A2
20
20
20
20
A9
85
85
60
A9 01
85 98

00
FF
E2

FF
FF
FF
ED
FF
ED
EE
EE

OFF

297

EOU
EOU
EOU
EOU
EOU
EOU
EOU
EOU
EOU
EOU
EOU
Eon
EOU
EOU
EOU
EOU
EOU

$79
$FFBI
$EDBE
$EE85
$EE97
$FFC3
$FFE7
$FFBA
$E254
$FF'CO
$FFC6
$FFAB
$FFAE
$87
$99
$98
$AF08

ORG
JSR
BEO
JSR
JSR
LDX
BEO
LDA
LDX
LOY
JSR
JSR
LOA
JSR
JSR
LOX
JSR
JSR
JSR
JSR
LDA
STA
STA
RTS
LOA
STA

828
CHRGOT
OFF
CLALL
GETNAME
FNLEN
SYNTAX
#2
#8
#2
SETFIL
OPEN
#4
LISTEN
ATNRES
#2
CHKIN
ATNRES
CLOCK
DATA
#0
INDEV
NMBFLS
#l
NMBFLS

~ATN

HI

HI
;DATA HI
~CLOCK

;GET FILENAME

; INPUT DEVICE
;NO. OF FILES
; SYNTAX ERROR
;MORE CHARS
;SPOOL DONE

;OPEN FILE
,PRINTER
,DISK

Anatomy of the 1541 Disk Drive
570:
580:
620:
630 :
640:

0378
037B
037E
0380
0383

20
20
A9
4C
4C

AE
AB
02
C3
08

FF
FF
FF
AF SYNTAX

JSR
JSR
LDA
JMP
JMP

UNLISTEN
UNTALK
*2
CLOSE
ERROR

Here is the BASIC loader program for the Commodore 64.
100
110
120
130
140
150
160
170
180
190
200

FOR I = 828 TO 901
READ X : POKE I,X : S=S+X : NEXT
DATA 32,121, 0,240, 51, 32,231,255, 32, 84,226
DATA 166,183,240, 56,169,
2,162, 8,160, 2, 32
DATA 186,255, 32,192,255,169,
4, 32,177,255, 32
DATA 190,237,162, 2, 32,198,255, 32,190,237, 32
DATA 133,238, 32,151,238,169, 0,133,153,133,152
DATA 96,169,
1,133,152, 32,174,255, 32,171,255
DATA 169, 2, 76,195,255, 76, 8,175.
IF S <> 9598 THEN PRINT "ERROR IN DATA I!" : END
PRINT "OK."

For the VIC 20, use the following program:
100
110
120
130
140
150
160
170
180
190
200

FOR I = 828 TO 901
READ X : POKE I,X : S=S+X : NEXT
DATA 32,121, 0,240, 51, 32,231,255, 32, 81,226
DATA 166,183,240, 56,169,
2,162, 8,160,
2, 32
DATA 186,255, 32,192,255,169, 4, 32,177,255, 32
DATA 197,238,162, 2, 32,198,255, 32,197,238, 32
DATA 132,239, 32,160,228,169, 0,133,153,133,152
DATA 96,169, 1,133,152, 32,174,255, 32,171,255
DATA 169, 2, 76,195,255, 76, 8,207
IF S <> 9648 THEN PRINT "ERROR IN DATA!!" : END
PRINT "OK."

298

Anatomy of the 1541 Disk Drive
4.4 Overlay Technique and Chaining Machine Language Programs

A proven programming technique involves the creation of a
menu program which then loads and executes other programs
based on the user's choice. There are two variations:
preserving or clearing the old variables in the chained
program.
It is possible to pass the old variables if the calling
program is as large or larger than the chained program. If a
program is chained from another program, the pointer to the
end of the previous program remains intact, and the new
program loads over the old.
In this example, we would get the following result:
100
: 110
120
130

I,

REM PROGRAM 1
REM THIS PROGRAM IS LARGER THAN THE SECOND
A = 1000
LOAD "PROGRAM 2",8

100 REM PROGRAM 2
110 PRINT A
1000
If the chained program is larger than the original program,
part of the variables are overwritten and contain
meaningless values. Moreover, when the variables that the
program destroyed are assigned new values, part of the
program is also destroyed.
There are two characteristics of passing variables from the
previous program that should be noted - for strings and for
functions.
Any string variables that are defined as constants enclosed
in quotes in the first program, will have a problem. The
string variable pointer points to the actual text in the
program. If, for example, a string is defined in the first
program with the following assignment
100 AS = "TEXT"
the variable pointer points to the actual text within line
number 100. When chaining, the next program does not chan~:e
this pointer. New text is now at the original location, so
the variable has unpredictable contents. We can easily work
around this, however. We need only ensure that the text is
copied from the program into string storage where text
variables are normally stored. You can do this as follows:
100 AS = "TEXT" + ""

299

Anatomy of the 1541 Disk Drive

By concatenating an empty string, you force the contents of
the variable to be copied to the string storage area.
Similar considerations apply to function definitions,
because here also the pointer points to the definition
within the program. Here you must define the function again
in the second program, for example:
100 DEF FN A(X)

= 0.5 *

EXP (-X*X)

If you want to chain a program, you can continue to use the
old variables provided the second program is not longer than
the first. If the chained program is longer, and we do not
want to preserve the old variables, there is a trick we can
use.
We need only set the end-of-program pointer to the end of
the new program immediately after loading. This can be done
with two POKE commands:
POKE 45, PEEK(174) : POKE 46, PEEK (175)

: CLR

The CLR command is absolutely necessary. This line should be
the first line in the chained program. This allows us to
chain a large program without transfer of variables.
Another, not so elegant method involves writing the load
command in the keyboard buffer so the program will
automatically be loaded in the direct mode. To do this, we
write the LOAD and RUN commands on the screen and fill the
keyboard buffer with 'HOME' and carriage returns. An END
statement must come after this in the program. The control
system then gets the contents of the keyboard buffer in the
direct mode and reads the LOAD and RUN commands that control
the loading and execution of the program. Because this
occurs in the direct mode, the end address of the program is
automatically set, the variables are erased and the program
is started with the RUN. The disadvantage of this method is
that since the LOAD command must appear on the video screen,
any display will be destroyed. In practice it looks like
this:
1000
1010
1020
1030
1040
1050

PRINT CHR$(147) "LOAD"CHR$(34) "PROGRAM 2"CHR$(34)",8"
PRINT : PRINT : PRINT : PRINT
PRINT "RUN"
POKE 632,13
POKE 633,13
POKE 631,19
POKE 634,13
POKE 635,13
POKE 636,13
POKE 198,6
END

You can see that this procedure is more complicated than .the
previous one; it is only mentioned for the sake of
completeness. With the first procedure, only the LOAD
command need be programmed in line 1000:
1000 LOAD "PROGRAM 2",8

300

Anatomy of the 1541 Disk Drive

There is another technique for chaining machine language
programs.
If a machine language program is to be used from a BASIC
program, it must usually be loaded at the beginning of the
BASIC program. You must take note of two things:
First of all, you must make sure that the machine language
program loads to a specific place in memory. If you load a
program without additional parameters, the control system
treats it as a BASIC program and loads it at the starting
address of the BASIC RAM, generally at 2049 (Commodore 64).
Machine language programs can only be run, however, when
they are loaded at the address for which they were written.
This absolute loading can be accomplished by adding the
secondary address 1:
LOAD "MACH-PRG",8,1
But remember that when loading a program from within another
program, BASIC attempts to RUN the program from the
beginning. This leads to an endless loop when loading
machine language programs, because the operating system
thinks that a new BASIC program has been chained:
100 LOAD "MACH-PRG",8,1
Here we can make use of the fact that the variables are
preserved when chaining. If we program the following, we
have reached our goal:
100 IF A=O THEN A=l
110

LOAD "MACH-PRG",8,1

When the program is started with RUN, A has the value zero
and the assignment after the THEN is executed, A contains
the value 1 and the machine language program is then LOADed.
When the program begins again after LOADing the program
MACH-PRG, A has the value 1 so the next line is executed.
The procedure is similar
language programs to load.
100 IF A=O THEN A=l
110 IF A=l THEN A=2
120 IF A=2 THEN A=3

if

you

have

several

machine

LOAD "PROG 1",8,1
LOAD "PROG 2",8,1
LOAD "PROG 3",R ,1

130

The first time through, PROG 1 will be loaded, the next
time, PROG 2, and so on. Once all the programs are loaded,
execution continues with line 130.

301

Anatomy of the 1541 Disk Drive
4.5

Merge - Appending BASIC Programs

Certainly you have thought about the possibility of
combining two separate BASIC programs into one. without
further details this is not possible, because loading the
second program would overwrite the first. With the knowledge
of how BASIC programs are stored in memory and on the
diskette, you can develop a simple procedure to accomplish
this task.
BASIC programs are stored in memory as follows:

NL NH
LL LH
XX yy ZZ

00

pointer to the next program line, 10 hi
line number, 10 hi
••••• tokenized BASIC statements
end-of-line marker

At the end of the program are two additional zero bytes:
00 00
a total of 3 zero bytes
Programs are also saved in this format. Where the program
starts and ends lies in .two pointers in page zero:
PRINT PEEK(43) + 256

*

PEEK(44)

gives the start of BASIC, 2049 for the Commodore 64,
PRINT PEEK(45) + 256

*

PEEK(46)

points to the byte behind the three zero bytes.
Because a program is always loaded at the start of BASIC,
contained in the pointer at 43/44, one can cause a second
program to load at the end of the first. In practice, we
must proceed as follows:
First we load the first program into memory.

Now get the value of the ending address of the program.
A

=

PEEK(45) + 256

*

PEEK(46)

This value is decremented by two so that the two zero bytes
at the end of the program are known.
A

=A

-

2

Now, note the original value of the start of BASIC.
PRINT PEEK(43), PEEK(44)
Next, set the start of BASIC to this value.

·302

Anatomy o£ the 1541 Disk Drive

POKE, A AND 255 : POKE 44, A /

256

Now, LOAD the second program.
LOAD "PROGRAM 2",8
If you set the start of BASIC back to the original value, 1
and 8 for the Commodore 64 (as shown above with the PRINT
commands), you have the complete program in memory and can
view it with LIST or save it with SAVE.
POKE 43,1 : POKE 44,8
The following should be noted when using this method:
The appended program may contain only line numbers that are
greater than the largest line number of the first program.
Otherwise these line numbers can never be accessed with GOTO
or GOSUB and the proper program order cannot be guaranteed.
This procedure is especially well suited for constructing a
subroutine library for often used routines, so they need not
be typed in each time. It will work out best if you reserve
specific line numbers for the subroutines, such as 2000025000, 25000-30000, and so on. If you want to merge several
programs in this manner, you must first load the program
with smallest line numbers, and then the program with the
next highest numbers, etc.

303

Anatomy of the 1541 Disk Drive
4.6

Disk Monitor for the Commodore 64 and VIC 20

In this section we present a very useful tool for working
with your disk drive, allowing you to load, display, modify,
and save desired blocks on the diskette.
For reasons of speed, the program is written entirely in
machine language. The following commands are supported:

*

*
*
*
*
*
*

Read a block from the disk
Write a block to the disk
Display a block on the screen
Edit a block on the screen
Send disk commands
Display disk error messages
Return to BASIC

The program announces its execution (automatically by the
BASIC load program) with
DISK-MONITOR Vl.O

>
and waits for your input. If you enter '@', the error
message from the disk will be displayed, for example
00, ok,OO,OO
If you want to send a command to the disk,
followed by the command.
You can initialize a diskette with

enter an '@'

>@I
YOU can send complete disk commands in this manner, that you
would otherwise send with

OPEN 15,8,15
PRINT# 15," command n
CLOSE 15
For example, you can erase files, format disks, and so on.
The most important function of the disk monitor is the
direct access of any block on the diskette. For this, you
use the commands Rand W. R stands for READ and reads a
desired block, W stands for WRITE and writes a block to the
diSk. YOU need only specify the track and sector you want to
read. These must be given in hexadecimal, exactly as the
output is given on the screen. If, for example, you want to
read track 18, sector 1 (the first directory block), enter
the following command:
)R 12 01

304

Anatomy of the 1541 Disk Drive
Each input must be given as a two-digit hex
separated from each other with a blank.

number,

In order to display the block, use the command M. We receive
the following output:
DISK-MONITOR Vl.O
>M
>:00 12 04 82 11
> :08 46 49 4B 20
>:10 53 52 43 AO
>: 18 00 00 00 00
>:20 00 00 82 13
>: 28 4F 54 2E 53
>:30 AO AO AO AD
>:38 00 00 00 00
>:40 00 00 82 13
>:48 4F 54 2E 53
>:50 AD AO AO AO
> :58 00 00 00 00
> : 60 00 00 82 13
> :68 2E 53 52 43
>:70 AD AO AO AO
>:78 00 00 00 00
) : 80 00 00 82 13
):88 2E 4F 42 4A
etc.

01
41
AO
00
00
52
AO
00
03
52
AO
00
09
AO
AO
00
08
AO

47
49
00
00
48
43
00
00
56
43
00
00
4D
AO
00
00
4D

52 41
44 2E
00 00
15 00
50 4C
AO AO
00 00
05 00
50 4C
AO AO
00 00
09 00
45 4D
AO AO
00 00
06 00
45 4D
AD AO AO

••••• GRA

FIX AID.
SRC

................

••••• HPL
OT.SRC

................
. " •• VPL
OT.SRC

................
••.•• MEM
.SRC

................
••.•• MEM
.OBJ

Let's take a closer look at the output. The first hex number
after the colon gives the address of the following 8 bytes
in the block, 00 indicates the first byte in the block (the
numbering goes from 00 to FF (0-255». 8 bytes follow the
address (4 on the VIC 20). In the right half are the
corresponding ASCII characters. If the code is not printable
($00 to $lF and $80 to $9F), a period is printed. When you
give the command M, as above, the entire block is displayed.
Because the block does not fit on the screen completely, it
is possible to display only part of it. You can give an
address range that you would like to display. If you only
want to see the first half, enter:
)M 00 7F
The second half with:
>M 80 FF
With the VIC 20, you can view quarters of the block. If you
now wish to change some data, you simply move the cursor to
the corresponding place, overwrite the appropriate byte, and
press RETURN. The new value is now stored and the right half
is updated with the proper ASCII character.
To write the modified block back to the diskette, you use
the command W. Here also you must give the track and sector
305

Anatomy of the 1541 Disk Drive
numbers in hexadecimal.
>W 12 01
writes the block back to track 18, sector 1, from where we
had read the block previously.
If you want to get back to BASIC, enter X and the computer
will respond with READY •• If you then want to use the disk
monitor again, you need not load it again. Just type SYS
49152 for the C64 or SYS 6690 for the VIC 20.
A warning:
Be sure to make a copy of any diskette that you work with in
this way. Should you make an error when editing or writing a
block, you can destroy important information on the disk so
that it can no longer be used in the normal manner. You
should make it a rule to only work with a copy.
Here you find an issembler listing of the program. After
this are the BASIC loader programs for the Commodore 64 and
VIC 20.
disk monitor vic 20 /

II>

190:
200:

COOO
COOO

PROMPT
NCMDS

EOU
EOU

210:
220:
230:
240:
250:
260:
270:
280:
290:
300:
310:
320:
330:
340:
350:
360:
370:
380:
390:
400:
410:

COOO
COOO
COOO
COOO
COOO
COOO
COOO
COOO
COOO
COOO
COOO
COOO
COOO
COOO
COOO
COOO
COOO
COOO
COOO
COOO
0200

INPUT
TALK
SECTALK
IEEEIN
UNTALK
LISTEN
SECLIST
IEEEOUT
UNLIST
WRITE
OPEN
CLOSE
SETPAR
SETNAM
CHKIN
CKOUT
CLRCH
CR
OUOTE
OUOTFLG

EOU
EOU
EOU
EQU
EOU
EQU
EOU
EOU
EOU
E(lU
EOU
EOU
EOU
EOU
EOU
EOU
EOU
EOU
EOU
EOU
ORG

$FFCF
$FFB4
$FF96
$FFA5
$FFAB
$FFBI
$FF93
$FFAB
$FFAE
$FFD2
$FFCO
$FFC3
$FFBA
$FFBD
$FFC6
$FFC9
$FFCC

420:
430:
440:

0201
0202
0203

SAVX
WRAP
BAD

BYT
BYT
BYT

a
0
a

306

cbm 64

II

6

;NUMBER OF
COMMANDS

13

$22
$D4
$200

; BASIC INPUT
BUFFER

Anatomy of the 1541 Disk Drive
450
460
470
480

0204
0205
0205
0205

490:
500:
510:

0205
0205
0205

520:
610:
620:
630:
640:
650:
660:
670:
680:
690:
700:
710:
710:
710:
720:
730:
740:
750:
760:
770:

0205
COOO
COOO
COOO
C002
C005
C008
C009
COOB
COOD
COOF
COll
C014
C016
COl9
COlC
COlE
C020
C022
C024

780:
790:
800:
840:
850:
860:
870:
880:
890:
900:
910 :

FROM
STATUS
SA

BYT
BYT
EOU
EOU

0
0
$90
$B9

FA
FNADR
FNLEN

EOU
EOU
EOU

$BA
$BB
$B7

TMPC
COUNT
READY
INIT
A2 00
BD 85 C2 MSGOUT
20 D2 FF
E8
EO 12
DO F5
START
A2 OD
A9 3E
20 EB CO
A9 00
8D 01 02
20 33 Cl STI
C9 3E
FO F9
C9 20
FO F5
A2 05
sO

EOU
EOU
EOU
LDX
LDA
JSR
INX
CPX
BNE
LDX
LDA
JSR
LDA
STA
JSR
CMP
BEO
CMP
BEO
LOX

$97
8
;t OF BYTES PER LINE
$E37B
;$E467 FOR VIC
to
MESSAGE,X
WRITE

C026
C029
C02B
C02E
C03l

DD 6A CO Sl
DO OC
8E 00 02
BD 70 CO
48

CMP
BNE
STX
LDA
PHA

C032
C035
C036
CO 37
C038
C03A

BD 76 CO
48
60
CA
S2
10 EC
4C OD CO

LDA
PHA
RTS
DEX
BPL
JMP

TO

C03D 85
C03F 20
C042 B9

990:
1000
1000
1000
1010
1020

C045
C048
C049
C04B
C04E
COSO

20
C8
DO

EE
C6
00

tASCDMP-MESSAGE
MSGOUT
tCR
tPROMPT
WRTWHR
#0
WRAP
RooC ;READ INPUT LINE
tPROMPT
STl
t- Il ;READ OVER BLANK
STI
tNCMDS-l ;COMPARE WITH.
COMMAND TABLE
CMDS,X
S2
SAVX ;# OF CMDS IN TABLE
AD~H,X

;JUMP ADDR TO
STACK
ADRL,X

Sl
; LOOP OF ALL CMDS
START

SUBROUTINE TO DISPLAY
THE DISK CONTENTS
97
DM
STA TMPC
62 CO DMI
JSR SPACE
EO C2
LDA BUFFER,y ;GET BYTE FROM
BUFFER
DC CO
JSR WROB
INY
03
BNE DM2
01 02
INC WRAP
97
DM2
DEC TMPC
ED
BNE DMI
;

960:
970:
980:

; SECONDARY
ADDRESS
;DEVICE t
; FILENAME ADR
;LEN OF
FILENAME

307

Anatomy of the 1541 Disk Drive

1030:

C052 60

RTS
READ BYTES AND WRITE TO MEMORY
C053 20 FE CO BYT
JSR RDOB
BCC BY3
C056 90 03
; BLANK?
C058 99 EO C2
STA BUFFER,Y ;WRITE BYTE IN
BUFFER
BY3
C05B C8
INY
DEC TMPC
C05C C6 97
C05E 60
RTS
C05F 20 62 CO SPAC2
JSR SPACE
C062 A9 20
SPACE
LDA II" n
BYT $2C
C064 2C
CRLF
LDA #CR
C065 A9 OD
JMP WRITE
C067 4C D2 FF
;

1060:
1070:
1080:
1090:
1100 :
1110:
1120 :
1130:
1140 :
1150:
1160:

;
1

1190 :
1200:
1210:
1220:
1230:
1240:
1250:
1260:
1270:
1280:
1290:
1300 :
1310:
13 20:
1330:
1340 :
1350:
1360 :
1370:
1380 :
1370:
1370 :
1370 :
1370 :
1370:
1380 :

C06A
C06B
C06C
C06D
C06E
C06F
C070
C07l
C072
C073
C074
C075
C076
C077
C078
C079
C07A
C07B
C07C
C07E
C081
C082
C085
C088
C08A
C08C

3A
57
52
4D
40
58
CO
Cl
Cl
CO
Cl
E3
CO
90
90
7B
3E
7A
AO
8C
88
8C
20
C9
FO
20

1390
1400
1410
1410
1410
1420
1430
1440
1450
1460
1470
1470

C08F
C091
C094
C097
CD99
C09B
CD9E
COM
COA3
COA6
COA9
COAC

90
8D
20
C9
FO
20
90
8D
AC
20
20
98

00
03 02
04 02
CF FF
OD
17
FE CO
12
03
CF
OD
08
FE
03
04
03
C6
D6

COMMAND AND
CMDS
ASC
ASC
ASC
ASC
ASC
ASC
ADRH
EOU
EOU
EOU
EOU
EOU
EOU
ADRL
EOU
EOU
EOU
EQU
EOU
EOU
DSPLYM
LDY
STY
DEY
STY
JSR
CMP
BEO
JSR

02
FF
CO
02
02 DSPI
C2 DSP2
C2

BCC
STA
JSR
CMP
REO
JSR
BCC
STA
LDY
JSR
JSR
TYA
308

ADDRESS TABLE
1: I
lEDIT MEM CONTENTS
;WRITE BLOCK
'w'
'R'
lREAD BLOCK
'M'
lDISLPAY BYTES
'@'
;DISK COMMAND
'X'
lEXIT
>ALTM-l
>DIRECT-l
>DIRECT-l
>DSPLYM-l
>DISK-l
>READY-l
DAOR
SETNAM
OPEN
•#
.13
CLOSE
#15
CLOSE
#'0

;HEX i TO ASI

UO
NUMB2
NUMBl
.$3B

~

'9' + 1

Anatomy of the 1541 Disk Drive
3390:
3400 :
3410:

3430:
3440:
3440:
3440:
3450:
3460:
3470:
3480:
3490:
3500:
3510:
3520:
3530:
3540:
3550:
3560 :
3570:
3570:
3580:
3580:
3590:
3600:
3610 :
3620:
3620 :
3630:
3640:
3650:
3660:
3660:
3660:
3670:
3680:
3690:
3700 :
3730:

C284 60
C285 OD
C286 44 49
4B 2D
4F 4E
54 4F
20 56
2E 30
C297 98
C298 38
C299 E9 08
C29B A8
C29C 20 62
C29F A9 12
C2Al 20 D2
C2M A2 08
C2A6 B9 EO
C2A9 29 7F
C2AB C9 20
C2AD BO 04
C2AF A9 2E
C2B1 DO 03
C2B3 B9 EO
C2B6 20 D2
C2B9 A9 00
C2BB 85 D4
C3BD C8
C2BE CA
C2BF DO E5
C2Cl A9 92
C2C3 4C D2
C2C6 AD 01
C2C9 DO 06
C2CB CC 04
C2CE BO 01
C2DO 60
C2D1 68
C2D2 68
C2D3 4C OD
C2D6 20 65
C2D9 A9 3A
C2DB A2 3E
C2DD 4C EB
C2EO

MESSAGE
53
4D
49
52
31
ASCDMP

CO
FF
C2 AC2

C2 AC3
FF AC4

FF
02 TESTEND
02
ENDErliD
CO
CO ALTRIT
CO
BUFFER

RTS
EOU
ASC

TYA
SEC
SBC
TAY
JSR
LDA
JSR
LDX
LDA
AND
CMP
BCS
LDA
BNE
LDA
JSR
LDA
STA
INY
DEX
BNE
LDA
JMP
LDA
BNE
CPY
BCS
RTS
PLA
PLA
JMP
JSR
LDA
LDX
JMP
DST

CR
'DISK-MONITOR Vl.0'

#COUNT
SPACE
U8
WRITE
#COUNT
BUFFER,Y
#$7F
#'
AC3
#' •
AC4
BUFFER,Y
WRITE
#0
OUOTFLG
AC2
U46
WRITE
WRAP
ENDEND
TO
END END

:RVS ON

;RVS OFF

START
CRLF
#' :
#PROMPT
WRTWHR
256
;256 BYTE BUFFER
FOR BLOCK

Here is the BASIC program for entering the disk monitor if
you do not have an assembler.

313

Anatomy of the 1541 Disk Drive
DISK-MONITOR,
100
110
120
130
140
150
160
170
180
190
200
210
220
230
240
250
260
270
280
290
300
310
320
330
340
350
360
370
380
390
400
410
420
430
440
450
460
470
480
490
500
510
520
530
540
550
560
570
580
590
600
610

C64 VERSION

FOR I : 49152 TO 49887
READ X : POKE I,X : S:S+X : NEXT
DATA 162, 0,189,133,194, 32,210,255,232,224, 18,208
DATA 245,162, 13,169, 62, 32,235,192,169,
0,141,
1
DATA
2, 32, 51,193,201, 62,240,249,201, 32,240,245
DATA 162,
5,221,106,192,208, 12,142, 0,
2,189,112
DATA 192, 72,189,118,192, 72, 96,202, 16,236, 76, 13
DATA 192,133,151, 32, 98,192,185,224,194, 32,220,192
3,238, 1, 2,198,151,208,237, 96, 32
DATA 200,208,
3,153,224,194,200,198,151, 96, 32
DATA 254,192,144,
DATA 98,192,169, 32, 44,169, 13, 76,210,255, 58, 87
DATA 82, 77, 64, 88,192,193,193,192,193,227,192,144
0,140,
3,
2,136,140,
4
DATA 144,123, 62,122,160,
2, 32,207,255,201, 13,240, 23, 32,254,192,144
DATA
DATA 18,141, 3,
2, 32,207,255,201, 13,240, 8, 32
3,141, 4,
2,172, 3,
2, 32,198
DATA 254,192,144,
DATA 194, 32,214,194,152, 32,220,192, 32, 98,192,169
8, 32, 61,192, 32,151,194, 76,166,192, 76, 13
DATA
DATA 192, 32,254,192,144,248,168,169, 8,133,151, 32
DATA 51,193, 32, 51,193, 32, 83,192,208,248, 32,151
DATA 194, 76, 13,192, 72, 74, 74, 74, 74, 32,244,192
DATA 170,104, 41, 15, 32,244,192, 72,138, 32,210,255
2,105, 6,105
DATA 104, 76,210,255, 24,105,246,144,
0,141,
2,
2, 32, 51,193,201, 32
DATA 58, 96,169,
DATA 208,
9, 32, 51,193,201, 32,208, 15, 24, 96, 32
DATA 40,193, 10, 10, 10, 10,141, 2,
2, 32, 51,193
2,
2, 56, 96,201, 58, 8, 41
DATA 32, 40,193, 13,
DATA 15, 40,144,
2,105,
8, 96, 32,207,255,201, 13
DATA 208,248,104,104, 76, 13,192, 32,207,255,201, 13
DATA 208, 39,169,
0,133,144, 32,101,192,169,
8,133
DATA 186, 32,180,255,169,111,133,185, 32,150,255, 32
DATA 165,255, 36,144,112, 5, 32,210,255,208,244, 32
8
DATA 171,255, 76, 13,192,201, 36,240, 29, 72,169,
DATA 133,186, 32,177,255,169,111,133,185, 32,147,255
DATA 104, 32,168,255, 32,207,255,201, 13,208,246, 32
DATA 174,255, 76, 13,192, 32, 51,193, 32,254,192,144
DATA 245,141, 39,194, 32, 51,193, 32,254,192,144,234
0,
2,201,
1,240
DATA 141, 42,194, 32, 73,194,173,
DATA 30,169, 49, 32,237,193,162, 13, 32,198,255,162
0, 32,207,255,157,224,194,232,208,247, 32,204
DATA
DATA 255, 32,110,194, 76, 13,192, 32, 44,194,162, 13
DATA 32,201,255,162,
0,189,224,194, 32,210,255,232
DATA 208,247, 32,204,255,169, 50, 32,237,193, 76,201
DATA 193,141, 32,194,162, 15,173, 39,194, 32,120,194
DATA 142, 39,194,141, 40,194,173, 42,194, 32,120,194
DATA 142, 42,194,141, 43,194,162, 15, 32,201,255,162
DATA
0,189, 31,194, 32,210,255,232,224, 13,208,245
DATA 76,204,255, 85, 49, 58, 49, 51, 32, 48, 32, 0
DATA
0, 32,
0,
0,162, 15, 32,201,255,162, 0,189
DATA 65,194, 32,210,255,232,224,
8,208,245, 76,204
DATA 255, 66, 45, 80, 32, 49, 51, 32, 48,169, 15,168
DATA 162, 8, 32,186,255,169,
0, 32,189,255, 32,192
314

Anatomy of the 1541 Disk Drive
620
630
640
650
660
670
680
690
700
710
720
730
740
750

DATA 255,169, 13,168,162, 8, 32,186,255,169, 1,162
DATA 109,160,194, 32,189,255, 76,192,255, 35,169, 13
DATA 32,195,255,169, 15, 76,195,255,162, 48, 56,233
DATA 10,144, 3,232,176,249,105, 58, 96, 13, 68, 73
DATA 83, 75, 45, 77, 79, 78, 73, 84, 79, 82, 32, 86
DATA 49, 46, 48,152, 56,233, 8,168, 32, 98,192,169
DATA 18, 32,210,255,162, 8,185,224,194, 41,127,201
DATA 32,176, 4,169, 46,208, 3,185,224,194, 32,210
DATA 255,169, 0,133,212,200,202,208,229,169,146, 76
DATA 210,255,173, 1, 2,208, 6,204, 4, 2,176, 1
DATA 96,104,104, 76, 13,192, 32,101,192,169, 58,162
DATA 62, 76,235,192
IF S <> 90444 THEN PRINT "ERROR IN DATA !!" : END
SYS 49152

DISK-MONITOR,

VIC 20 VERSION

In order to allow this program to be run on the VIC 20, it was
split into two parts. Enter each program separately, saving the
first under the name "DOS LOADER.l" and second under "DOS
LOADER.2". To load the disk monitor, load the first program and
start it with RUN. If all data are correct, the second program
will automatically be loaded and the disk monitor started.
100
105
110
120
130
140
150
160
170
180
190
200
210
220
230
240
250
260
270
280
290
300
310
320
330
340
350
360

POKE 55, 6690 AND 255 : POKE 56, 6690 / 256 : CLR
FOR I = 6690 TO 7056 : REM DOS LOADER.l
READ X : POKE I,X : S=S+X : NEXT
DATA 162, 0,189,164, 28, 32,210,255,232,224, 18,208
DATA 245,162, 13,169, 62, 32, 7, 27,169, 0,141, 1
DATA
2, 32, 79, 27,201, 62,240,249,201, 32,240,245
DATA 162, 5,221,140, 26,208, 12,142, 0, 2,189,146
DATA 26, 72,189,152, 26, 72, 96,202, 16,236, 76, 47
DATA 26,133,151, 32,132, 26,185, 0, 29, 32,248, 26
DATA 200,208, 3,238, 1, 2,198,151,208,237, 96, 32
DATA 26, 27,144, 3,153, 0, 29,200,198,151, 96, 32
DATA 132, 26,169, 32, 44,169, 13, 76,210,255, 58, 87
DATA 82, 77, 64, 88, 26, 27, 27, 26, 27,228,223,175
DATA 175,157, 90,102,160, 0,140, 3, 2,136,140, 4
DATA
2, 32,207,255,201, 13,240, 23, 32, 26, 27,144
DATA 18,141, 3, 2, 32,207,255,201, 13,240, 8, 32
DATA 26, 27,144, 3,141, 4, 2,172, 3, 2, 32,229
DATA 28, 32,245, 28,152, 32,248, 26,169, 4, 32, 95
DATA 26, 32,182, 28, 76,200, 26, 76, 47, 26, 32, 26
DATA 27,144,248,168,169, 4,133,151, 32, 79, 27, 32
DATA 117, 26,208,248, 32,182, 28, 76, 47, 26, 72, 74
DATA 74, 74, 74, 32, 16, 27,170,104, 41, 15, 32, 16
DATA 27, 72,138, 32,210,255,104, 76,210,255, 24,105
DATA 246,144, 2,105, 6,105, 58, 96,169, 0,141, 2
DATA
2, 32, 79, 27,201, 32,208, 9, 32, 79, 27,201
DATA 32,208, 15, 24, 96, 32, 68, 27, 10, 10, 10, 10
DATA 141, 2, 2, 32, 79, 27, 32, 68, 27, 13, 2, 2
DATA 56, 96,201, 58, 8, 41, 15, 40,144, 2,105, 8
315

Anatomy of the 1541 Disk Drive
370
380
390
400
410
420
430
440

DATA 96, 32,207,255,201, 13,208,248,104,104, 76, 47
DATA 26, 32,207,255,201, 13,208, 39,169,
0,133,144
DATA 32,135, 26,169,
8,133,186, 32,180,255,169,111
DATA 133,185, 32,150,255, 32,165,255, 36,144,112, 5
DATA 32,210,255,208,244, 32,171,255, 76, 47, 26,201
DATA 36,240, 29, 72,169, 8,133
IF S <> 35614 THEN PRINT "ERROR IN DATA ! ! II : END
LOAD "oos LOADER.2",8

100
110
120
130
140
150
160
170
180
190
200
210
220
230
240
250
260
270
280
290
300
310
320
330
340
350
360
370
380
390
400
410
420
430
440

eLR : FOR I = 7057 TO 7422 : REM OOS LOADER. 2
READ X : POKE I,X : s=s+x : NEXT
DATA 186, 32,177,255,169,111,133,185, 32,147,255,104
DATA 32,168,255, 32,207,255,201, 13,208,246, 32,174
DATA 255, 76, 47, 26, 76, 47, 26, 32, 79, 27, 32, 26
DATA 27,144,245,141, 70, 28, 32, 79, 27, 32, 26, 27
DATA 144,234,141, 73, 28, 32,104, 28,173, 0,
2,201
1,240, 30,169, 49, 32, 12, 28,162, 13, 32,198
DATA
DATA 255,162, 0, 32,207,255,157,
0, 29,232,208,247
DATA 32,204,255, 32,141, 28, 76, 47, 26, 32, 75, 28
DATA 162, 13, 32,201,255,162, 0,189, 0, 29, 32,210
DATA 255,232,208,247, 32,204,255,169, 50, 32, 12, 28
DATA 76,232, 27,141, 63, 28,162, 15,173, 70, 28, 32
DATA 151, 28,142, 70, 28,141, 71, 28,173, 73, 28, 32
DATA 151, 28,142, 73, 28,141, 74, 28,162, 15, 32,201
DATA 255,162,
0,189, 62, 28, 32,210,255,232,224, 13
DATA 208,245, 76,204,255, 85, 49, 58, 49, 51, 32, 48
DATA 32,
0, 0, 32,
0,
0,162, 15, 32,201,255,162
DATA
0,189, 96, 28, 32,210,255,232,224, 8,208,245
DATA 76,204,255, 66, 45, 80, 32, 49, 51, 32, 48,169
DATA 15,168,162, 8, 32,186,255,169, 0, 32,189,255
DATA 32,192,255,169, 13,168,162,
8, 32,186,255,169
DATA
1,162,140,160, 28, 32,189,255, 76,192,255, 35
DATA 169, 13, 32,195,255,169, 15, 76,195,255,162, 48
DATA 56,233, 10,144, 3,232,176,249,105, 58, 96, 13
DATA 68, 73, 83, 75, 45, 77, 79, 78, 73, 84, 79, 82
DATA 32, 86, 49, 46, 48,152, 56,233, 4,168, 32,132
DATA 26,169, 18, 32,210,255,162,
4,185, 0, 29, 41
DATA 127,201, 32,176,
4,169, 46,208, 3,185, 0, 29
DATA 32,210,255,169, 0,133,212,200,202,208,229,169
DATA 146, 76,210,255,173, 1,
2,208, 6,204,
4, 2
DATA 176, 1, 96,104,104, 76, 47, 26, 32,135, 26,169
7,
76,
DATA 58,162, 62,
27
IF S <> 39496 THEN PRINT "ERROR IN DATA !! .. : END
SYS 6690

316

Anatomy of the 1541 Disk Drive
Chapter 5:

5.1

The Larger CBM Disks

IEEE-Bus and Serial Bus

Standard Commodore 64's and VIC 20's have a serial bus over
which they communicate with peripheral devices such as the
VIC 1541 disk drive as well as printers and plotters.
The principle of the bus makes it possible to chain
peripherals. Each device has its own device address over
which one can communicate with it. The standard address of
the disk is a, a printer is usually 4. The device address is
identical to the primary address in the OPEN command. For
instance,
OPEN .1,4
opens a channel to the printer. In order to open several
disk files at once, another address, the secondary address,
serves to distinguish them. The disk has 16 secondary
addresses at its disposal, from 0 to 15. Three secondary
addresses are reserved, while the other 13 can be freely
used:
Secondary address 0 is used for loading programs.
secondary address 1 is used for saving programs.
Secondary address 15 is the command and error channel.
The secondary addresses from 2 to 14 can be used for opening
files as desired.
The transfer of information between the Commodore 64 and the
VIC 1541 occurs serially over this bus. Serial means that
the the data is sent a bit at a time over just one wire.
Data within the computer and disk drive are stored and
manipulated in 8 bit groups called bytes. When a byte is
sent serially, each individual bit must be sent over the
data line. In order that the sender and receiver can stay in
step, a so-called 'handshake' line is needed. If we look at
the pin-out of the serial bus, we find 6 wires:
Pin
1

2
3

4
5

6

Function
SRQ IN
ground
ATN
CLCK
DATA
RESET

If the computer wants to send data to the disk drive, the
317

Anatomy of the 1541 Disk Drive
ATN (attention) line is set. When this signal is high, all
peripherals on the bus stop their work and read the next
byte. The data is sent bit-wise over the DATA line. So that
the receivers know when the next bit comes. a signal is also
sent along the CLCK (clock) line. This transmitted byte is
the device address. If this value does not correspond with
the device address of a receiving peripheral, the rest of
the data is ignored. If, however, the device is addressed, a
secondary address may be transmitted. Along with the device
address (0 to 31), the device is informed by means of the
other three bits whether it is supposed to receive data
(LISTEN) or send data (TALK). Following this, data is sent
from the computer or from the addressed device.
The RESET line resets all attached devices when the computer
is turned on. Over the SRO IN (service request) line,
peripheral devices can inform the bus controller (in our
case, the computer), if data is ready, for example. However,
this line is not checked by the control system in the
Commodore computers.
If one wants to attach several disk drives to the same
computer, each must have a different peripheral address. If
this is done only occasionally, the program DISK'ADDR CHARGE
can be used, as described in section 4.2.3. The new address
(9 for example), remains only until the device is turned
off. If the change should be permanent, it can be, changed
with DIP switches in the drive.
The principle of transfer of data over th'e IEEE 488 bus is
similar to the serial bus function. The important difference
is that the data is transmitted over 8 data lines in
parallel, not serial. In addition, more handshake lines are
needed, so the IEEE bus requires a 24-line cable. The main
advantage of the IEEE 488 bus is its ability to transmit a
byte at a time, resulting in a higher rate of transfer.
Measurements indicate that the IEEE-bus is about 5 times
faster than the serial bus: 1.8 Kbyte/second vs. 0.4
Kbyte/second. Loading a 10K program with the VIC 1541 takes
about 25 seconds: on the identical 2031, it takes less than
6. This reason alone is enough to warrant outfitting your
computer with an IEEE bus.
At the same time, it is possible to use all the other
peripherals that the large CBM computers can access.

318

Anatomy of the 1541 Disk Drive
5.2

Comparison of all CBM Disk Drives

In the following table you find the technical data of all
CBM disk drives compared.
The Technical Data of all Commodore Disk Drives
Model

1541

2031

4040

8050

8250

DOS version(s)

2.6

2.6

2.1/
2.7

2.5/
2.7

2.7

Drives
Heads per drive

1
1

1
1

2
1

2
1

2

Storage capacity
Sequential files
Relative files

170 K
168 K
167 K

170 K
168 K
167 K

340 K
168 K
167 K

1. 05 M
521 K
183 K/
518 K

2.12 M
1.05 M
1,04 M

Buffer storage (KB)

2

2

4

4

4

Tracks
Sectors per track
Bytes per block
Free blocks
Directory and BAM
(track)
Directory entries

35
17-21
256
664
18

35
17-21
256
664
18

35
17-21
256
1328
18

77

77

23-29
256
4104
38/39

23-29
256
8266
38/39

144

144

144

224

224

Transfer rate (KB/s)
internal
40
over ser./IEEE bus 0.4

40
1.8

40
1.8

40
1.8

40
1.8

Access time (ms)
Track to track
Average time

30
360

30
360

30
360

5
125

5
125

Revolutions/minute

300

300

300

300

300

Overview of the Illarge

ll

2

CBM drives

The VIC 1541 disk drive has the smallest storage capacity of
the CBM disks, but it is also the only drive that can be
connected directly to the Commodore 64 and VIC 20 over the
serial bus.
The functions, construct ion, and operation are identical to
those of the CBM 2031 drive. The only difference from the
VIC 1541 is the parallel IEEE bus instead of the serial bus.
319

Anatomy of the 1541 Disk Drive
This results in an increase in the transfer rate to the
computer of a factor of 5. To connect a Commodore 64 or VIC
20, one needs an IEEE interface, as with all other CBM
drives. The storage format of the 2031 is compatible to the
1541; both have l70K per disk. Diskettes can be written with
one device and read with the other. This is true for the
next drive in the line, the CBM 4040. The 4040 is a double
driVe with l70K per drive.
The advantage of a double drive lies not only in the
increased storage capacity, but also in the ability to
transfer data from drive to drive. It is possible to copy
complete programs and files using the existing 1541 command.
OPEN 1,8,15, "Cl:TEST=O:TEST"

or

COpy "TEST",DO TO "TEST",Dl
copies the file TEST from drive 0 to drive 1 with the same
name. In this manner one can concatenate several files on
di£ferent drives. The most important capability of double
driv€s is the ability to duplicate entire diskettes. This
is accomplished by a command from the computer; the drive
automatically formats the disk and then makes a track ty
track copy from one drive to the other. The command to do
this is worded:
OPEN 1,8,15, "01=0"

or

BACKUP DO TO Dl
The process takes less than 3 minutes on the 4040; during
this time the computer may be used since the disk drive
performs the entire operation by itself.
The two other CBM drives, the CBM 8050 and the CBM 8250
operate in double density (77 tracks). Disks written with
the 1541 or 4040 are not compatible with the 8050/8250.
Programs and data can be copied with the COPY/ALL program,
which transfers from one format to another. This is the
reason these drives have greater storage capacity: 1 MB for
the 8050 and 2 MB for the 8250. The doubled capacity of the
8250 comes about because both sides of the disk are used
(double-sided); it has two reads/write heads per drive. In
order to be able to use the whole capacity for relative
files (see section 3.4), a so-called 'super side-sector' was
introduced, which contains pointers to 127 groups of 6 sidesector blocks each. Through this, a relative file can
(theoretically) hold 23 MB of data. These drives can be
connected to a Commodore 64 or VIC 20 over an IEEE bus, ~-o
that these computers can also access several megabytes.
An additional advantage of the large CBM drives is their
larger buffer storage. It is possible to have more files
open simultaneously than on the VIC 1541. Up to 5 sequential
320

Anatomy of the 1541 Disk Drive
files or 3 relative files may be open at anyone time, as
well as combinations of the two, of course.
with the 8050/8250 format, tracks 38 and 39 are used for the
BAM and directory. The disk name and format marker are in
track 39 sector O.
>:00
>:08
>:10
>:18

26
4E
AD
30

00
20
AD
31

43
38
AD
AD

00
30
AD
32

00
35
AD
43

00
30
AD
AD

43
AD
AD
AD

42
AD
AD
AD

&. C ••• CB
M 8050

01 2C

The track/sector pointer to the first BAM block (track 38
sector 0) is in bytes 0 and 1.
Byte 2 contains the format
marker 'C'. Bytes 3 through 5 are unused. The disk name is
in 6 to 21, filled with shifted spaces, in our case CBM
8050. Bytes 24 and 25 contain the id '01', while bytes 26
and 27 contain the DOS format 2e.
The BAM no longer occupies just one block, but is dispersed
over track 38; sectors 0 and 3 are used in the 8050, the
8250 used sectors 6 and 9 in addition. Because more sectors
are use per track, the BAM entry for each track has been
enlarged to 5 bytes. The first byte still contains the
number of free sectors per track and the following bytes
contain the bit model of the free and allocated sectors (0 =
sector allocated, 1 = sector free). Here we have the
contents of track 38 sector 0
>:00
>:08
>:10
>:18
>:20
>:28
>:30
> : 38
>:40
>:48
>:50
>:58
>:60
>:68
>:70
>:78
>:80
>:88
>:90
>:98

>:AO

>:A8
>: 80
> :B8

> :CO
> :C8

26
FF
ID
FF
FF
IF
FF
ID
FF
FF
IF
FF
10
FF
FF
IF
FF
10
FF
FF
IF
FF
00
00
F4
IF

03
FF
FF
IF
FF
ID
FF
FF
IF
FF
ID
FF
FF
IF
FF
ID
FF
FF
IF
FF
ID
FF
00
00
93
00

43
IF
FF
ID
FF
FF
IF
FF
10
FF
FF
IF
FF
ID
FF
FF
IF
FF
ID
FF
FF
IF
00
00
46
00

00
1D
FF
FF
IF
FF
ID
FF
FF
IF
FF
ID
FF
FF
IF
FF
ID
FF
FF
IF
FF
18
00
00
lA
00

01
FF
IF
FF
ID
FF
FF
IF
FF
In
FF
FF
IF
FF
ID
FF
FF
IF
FF
10
FF
FC
00
00
18
00

33
FF
ID
FF
FF
IF
FF
ID
FF
FF
IF
FF
ID
FF
FF
IF
FF
ID
FF
FF
IF
F3
00
00
6C
00

ID
FF
FF
IF
FF
ID
FF
FF
IF
FF
ID
FF
FF
IF
FF
ID
FF
FF
IF
FF
ID
EF
00
00
FB
00

FF
IF
FF
ID
FF
FF
IF
FF
10
FF
FF
IF
FF
ID
FF
FF
IF
FF
ID
FF
FF
IF
00

OF
FF
00

321

Anatomy of the 1541 Disk Drive
>:00
>:08
>:EO
> :E8
>:FO
> :F8

00
05
FF
FF
07
FF

00
00
07
FF
1B
F~

00
00
1B
FF
FF
07

00
40
FF
07
FF
1B

00
04
FF
1B
FF
FF

00
1B
FF
FF
07
FF

00
FF
07
FF
1B
FF

00
FF
1B
FF
FF
07

Bytes 0 and 1 point to the next BAM block, track 38 sector
3. Byte 2 contains the format marker 'e' again. The track
numbers belonging to this BAM section are in bytes 4 and 5:
here tracks 1 through 51. At position 6 we find the 5 byte
entry for each track. The next BAM block is constructed
similarly. The last BAM block always points to the first
directory block: track 39 sector 1.
Four BAM blocks are needed for the 8250: track 38 sector 0
contains the tracks 1 to 51, track 38 sector 3 contains 52
to 100, track 38 sector 6 contains track 101 through 150 and
track 38 sector 9 pertains to tracks 151 to 154.
The directory track, track 39, contains 28 free blocks: up
to 28*8=224 directory entries can be stored, in contrast to
144 f,or the 1541/4040. The construction of the directory is
a1 ike for all formats. The f'ollowing table illustrates the
track/sector layout:
1541 /

4040

8050 /

8250

-----------------------------------------------------0 - 28
sectors
Tracks 1 - 17
0 - 20
1 - 39
18- 24
0 - 18
40 - 53
0 - 26
54 - 64
0 - 24
25- 30
0 - 17
65 - 77
0 - 22
0 - 16
31- 35
78
117
131
142
Blocks
Free blocks

683
664

8250 only
0
-116
-130
0
0
-141
0 -154

-

20R3

2052

322

4186
4133

28
26
24
22

Anatomy of the 1541 Disk Drive
OTHER BOOKS AVAILABLE:
The Anatomy of the Commodore 64 - is our insider's guide to
your favorite computer. This book is a must for those of you
who want to delve deep into your micro. This 300+ page book
is full of information covering all aspects of the '64.
Includes fully commented listing of the ROMs so you can
investigate the mysteries of the BASIC interpreter,
kernal and operating system. It offers numerous examples of
machine language programming and several samples that make
your programming sessions more enjoyable and useful.
ISBN# 0-916439-00-3

Available now:

S19.95

The Anatomy of the 1541 Disk Drive - unravels the mysteriEs
of working the the Commodore 1541 disk drive. This 320+ page
book starts by explaining program, sequential and relative
files. It covers the direct access commands, diskette
structure, DOS operation and utilties. The fully commented
ROM 1 ist ings are presented for the real "hackers". Includes
listings for several useful utilities including BACKUP,
COPY, FILE PROTECTOR, DIRECTORY. This is the authoritive
source for 1541 disk drive information.
ISBN# 0-916439-01-1

Available now:

S19.95

Tricks & Tips for the Commodore 64 - presents a collection
of easy-to-use programming techniques and hints. Chapters
cover advanced graphics, easy data entry, enhancements for
advanced BASIC, CP/M, connecting to the outside world and
more. Other tips include sorting', variable dumps, and POKEs
that do tricks. All-in-all a solid set of useful features.
ISBN# 0-916439-03-8

Available June 29th:

$19.95

Machine Language Book of the Commodore 64 - is aimed at the
owner who wants to progress beyond BASIC and write faster,
more memory efficient programs in machine language. The book
is specifically geared to the Commodore 64. Learn all of the
6510 instructions as they apply to the '64. Access PCM
routines, I/O, extend BASIC, more. Included are listings of
three full length programs: an ASSEMBLER; a DISASSEMBLER;
and an amazing 6510 SIMULATOR so the reader can ·see"the
operation of the '64.
ISBN# 0-916439-02-X

Available now:
Optional program diskette:

OTHER TITLES COMING SOON!!!

323

S14.95
$14.95

FREE CATALOG Ask for a listing of other
AbaCus SOftware for Commodo....64orVlc-20
1III11IIIUTORS
llutllrlblla:

""""'"

lBNuwictlAve

AocII~.Lancs

m·,.....

.... ..,..,:

-, --IfIItr.SIrW:at
AYGuilauIMSi

147AYenut~

""lCJO.lIeII1um
2-.,441

,."."..

......:

AIIInIII::

DATA BECKER
T1Al TRADING
Merowingerslr:ll P0516
4OOO0usseId0rf 343OO~mhult
02111312085
476-12304

*

RIIIIII~.FGnce

CW ELECTRONICS
416~.. 1!oId
1IrIsbInII, Queens.
07.0397-0eD8

DEALER INQUIRIES INVITED

c..dI~:

raNG r.tCROWARE lTD.

=:r~=~lZ6

514/737-9336
IIIW ZMIIMI:
VlSCOI.lITElECTfIONICS
306-308 CftuFCII Street

........

PaImerstonNOrth

AVAILABLE AT COMPUTER STORES, OR WRITE:

Abacus _ Software
P.O. BOX 7211 GRAND RAPIDS, MICH. 48510 IIti!III
For postage & handfing, add $2.50 (U.S. and Canada), add $5.00

.1!Ia!J

~; =~c:~e(~1:;~ ~~~e:"~ bl:s~~~ :~)y order
FOR QUICK SERVICE PHONE 616-241-551D



Source Exif Data:
File Type                       : PDF
File Type Extension             : pdf
MIME Type                       : application/pdf
PDF Version                     : 1.3
Linearized                      : No
XMP Toolkit                     : Adobe XMP Core 4.2.1-c043 52.372728, 2009/01/18-15:56:37
Create Date                     : 2013:09:17 12:17:26-08:00
Modify Date                     : 2013:09:17 13:58:15-07:00
Metadata Date                   : 2013:09:17 13:58:15-07:00
Producer                        : Adobe Acrobat 9.55 Paper Capture Plug-in
Format                          : application/pdf
Document ID                     : uuid:8ba32e43-ee30-354b-aefe-c942603df129
Instance ID                     : uuid:b59026d6-e2dc-4b41-8793-938c0774eb10
Page Layout                     : SinglePage
Page Mode                       : UseNone
Page Count                      : 336
EXIF Metadata provided by EXIF.tools

Navigation menu