Difference between revisions of "OSWORD &7F"

From BeebWiki
Jump to: navigation, search
(Added Special Registers and Drive Status result)
 
m (Specification)
 
(20 intermediate revisions by 3 users not shown)
Line 1: Line 1:
 
[[Category:OSWORD]]
 
[[Category:OSWORD]]
{{#customtitle:OSWORD &7F (127) - Perform floppy disk operation}}
+
{{PageTitle|OSWORD &7F (127) - Floppy disk operation}}
 
__TOC__
 
__TOC__
 
==Specification==
 
==Specification==
Line 16: Line 16:
 
| align="center" | XY?&06  || Command                  ||  
 
| align="center" | XY?&06  || Command                  ||  
 
|- align="left" valign="top"
 
|- align="left" valign="top"
| align="center" | XY+7...  || Parameters              ||  
+
| align="center" | XY+&07...  || Parameters              ||  
 
|- align="left" valign="top"
 
|- align="left" valign="top"
 
| align="center" | XY?(7+n) ||                          || Result
 
| align="center" | XY?(7+n) ||                          || Result
Line 22: Line 22:
  
 
No contents of the control block should be relied upon on exit other than
 
No contents of the control block should be relied upon on exit other than
the result byte. Some systems update the control block, some systems do not.
+
the result byte. Some systems update the control block, some systems do not,
 +
though code universally expects the '''number of parameters''' to remain so
 +
the result can be found after the call with XY?(XY?5+7).
  
 
{| cellpadding="0" cellspacing="0"
 
{| cellpadding="0" cellspacing="0"
Line 111: Line 113:
 
DFS 2.xx in the Master MOS 3.20 ROM incorrectly passes the density bit in b3
 
DFS 2.xx in the Master MOS 3.20 ROM incorrectly passes the density bit in b3
 
to the drive control register b3 instead of b5, so OSWORD &7F cannot access
 
to the drive control register b3 instead of b5, so OSWORD &7F cannot access
double density disks without patching the DFS
+
double density disks without patching the DFS<ref>http://mdfs.net/ROMs/Filing/Disk</ref>.
<ref>http://mdfs.net/ROMs/Filing/Disk</ref>.
 
  
 
===Data Address===
 
===Data Address===
Line 118: Line 119:
  
 
===Track===
 
===Track===
This is the logical track to transfer data to or from. This may be different from
+
This is the logical track to transfer data to or from. This may be different
the physical track number if the drive has previously been stepped to the correct
+
from the physical track number if the drive has previously been stepped to
physical track.
+
the correct physical track.
  
 
===Sector===
 
===Sector===
This is the logical sector number to start data transfer from. Sectors can be
+
This is the logical sector number to start data transfer from. Sectors can
numbered anything from &00 to &FF, but single-density DFS-formatted disks use
+
be numbered anything from &00 to &FF, but single-density DFS-formatted disks
&00-&09 and double-density DFS and ADFS disks use &00-&0F.
+
use &00-&09 and double-density DFS and ADFS disks use &00-&0F.
  
 
===Size + Count===
 
===Size + Count===
Line 181: Line 182:
  
 
* b7-b6: always zero (1770 DFS returns 11 if command unrecognised)
 
* b7-b6: always zero (1770 DFS returns 11 if command unrecognised)
* b5: deleted data found
+
* b5: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; deleted data found
* b4-b3: completion type: 00=no error, 01=recoverable error, 10=unrecoverable error, 11=failure
+
* b4-b3: completion type: 00=no error, 01=data error, 10=disk error, 11=media error
 
* b2-b1: completion code
 
* b2-b1: completion code
* b0: always zero
+
* b0: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; always zero (used by extensions)
  
 
This gives the following result values:
 
This gives the following result values:
Line 190: Line 191:
 
{| cellpadding="0" cellspacing="0"  
 
{| cellpadding="0" cellspacing="0"  
 
| &nbsp;type&nbsp; || &nbsp;code&nbsp; || &nbsp;Result&nbsp; || &nbsp;Meaning
 
| &nbsp;type&nbsp; || &nbsp;code&nbsp; || &nbsp;Result&nbsp; || &nbsp;Meaning
 +
|| &nbsp;Result&nbsp; || &nbsp;Meaning
 
|- align="center"
 
|- align="center"
 
| 00 || 00 || &00 || align="left" | Successful completion
 
| 00 || 00 || &00 || align="left" | Successful completion
Line 201: Line 203:
 
| 01 || 00 || &08 || align="left" | Clock error
 
| 01 || 00 || &08 || align="left" | Clock error
 
|- align="center"
 
|- align="center"
| 01 || 01 || &0A || align="left" | Late DMA ** / Late ISR
+
| 01 || 01 || &0A || align="left" | Late DMA ** / Late ISR / Abort, eg Escape
 
|- align="center"
 
|- align="center"
| 01 || 10 || &0C || align="left" | ID CRC error
+
| 01 || 10 || &0C || align="left" | ID CRC error / Bad sector ID
 
|- align="center"
 
|- align="center"
 
| 01 || 11 || &0E || align="left" | Data CRC error
 
| 01 || 11 || &0E || align="left" | Data CRC error
Line 215: Line 217:
 
| 10 || 11 || &16 || align="left" | Write error
 
| 10 || 11 || &16 || align="left" | Write error
 
|- align="center"
 
|- align="center"
| 11 || 00 || &18 || align="left" | Sector not found
+
| 11 || 00 || &18 || align="left" | Sector not found || &19 || align="left" | Bad drive number
 
|- align="center"
 
|- align="center"
| 11 || 01 || &1A || align="left" | unused
+
| 11 || 01 || &1A || align="left" | unused (Disk changed) || &1B || align="left" | Disk already mounted
 
|- align="center"
 
|- align="center"
| 11 || 10 || &1C || align="left" | unused
+
| 11 || 10 || &1C || align="left" | unused (Media change, eg Eject pressed) || &1D || align="left" | Bad image filename
 
|- align="center"
 
|- align="center"
| 11 || 11 || &1E || align="left" | Drive not present/drive empty
+
| 11 || 11 || &1E || align="left" | Drive not present/drive empty || &1F || align="left" | No disk mounted
 +
|- align="center"
 +
|    ||    || &FE || align="left" | (Command not recognised)
 
|-
 
|-
 
|}
 
|}
Line 227: Line 231:
 
<nowiki>**</nowiki> Not possible on a BBC as needs DMA hardware.
 
<nowiki>**</nowiki> Not possible on a BBC as needs DMA hardware.
  
The result byte will have &20 added to it if deleted data has been read.
+
The result byte will have &20 added to it if deleted data has been read. Results in (brackets) are extensions used by systems with hardware that supports the functionality, or when translating results from non-8271 hardware. Odd numbered results are additional codes returned by extensions such as mounting image files, dropping bit 0 gives an equivalent hardware code.
  
 
Intel documentation states that result type 01 should be retried up to a
 
Intel documentation states that result type 01 should be retried up to a
Line 243: Line 247:
  
 
Read Drive Status (&6C) resets any 'not ready' error and returns the drive status as the result byte:
 
Read Drive Status (&6C) resets any 'not ready' error and returns the drive status as the result byte:
* b7   : unused
+
* b7: unused
* b6   : READY1
+
* b6: READY1
* b5   : FAULT
+
* b5: FAULT
* b4   : INDEX
+
* b4: INDEX
* b3   : WR PROTECT
+
* b3: WRPROTECT
* b2   : READY0
+
* b2: READY0
* b1   : TRACK0
+
* b1: TRACK0
* b0   : COUNT
+
* b0: COUNT
  
 
==8271 Commands==
 
==8271 Commands==
Line 258: Line 262:
 
   | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |  
 
   | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |  
 
   +---+---+---+---+---+---+---+---+
 
   +---+---+---+---+---+---+---+---+
     |  |  |  |   |  |  |  |
+
     |  |  |  ||  |  |  |
 
     |  |  +---+---+  |  +---+----Size:  00 multiple scan data
 
     |  |  +---+---+  |  +---+----Size:  00 multiple scan data
     |  |      |   |   |                  01 no transfer
+
     |  |      ||     |                  01 no transfer
     |  |      |   |   |                  10 128 bytes
+
     |  |      ||     |                  10 128 bytes
     |  |      |   |   |                  11 multiple sectors
+
     |  |      ||     |                  11 multiple sectors
     |  |      |   |   |
+
     |  |      ||     |
     |  |      |   |   +------------Data:  0 ignore delete data
+
     |  |      ||     +------------Data:  0 ignore deleted data
     |  |      |   |                       1 all data
+
     |  |      ||                           1 accept deleted data
     |  |      |   |
+
     |  |      ||
     |  |      |   +-----------Direction:  0 Write to FDC
+
     |  |      |+--------------Direction:  0 Write to FDC
 
     |  |      |                            1 Read from FDC
 
     |  |      |                            1 Read from FDC
 
     |  |      |
 
     |  |      |
 
     |  |      +-----------------Command: 000 Scan
 
     |  |      +-----------------Command: 000 Scan
     |  |                                  001 Read
+
     |  |                                  001 Write
     |  |                                  010 Write
+
     |  |                                  010 Read
 
     |  |                                  011 Verify
 
     |  |                                  011 Verify
 
     |  |                                  100 Format
 
     |  |                                  100 Format
Line 279: Line 283:
 
     |  |                                  111 Special Registers
 
     |  |                                  111 Special Registers
 
     |  |
 
     |  |
     |  +---------------------------------- Drive
+
     |  +---------------------------------- Drive select 0
     +-------------------------------------- Side
+
     +-------------------------------------- Drive select 1
 +
 
 +
The drive select bits must be set to %01 in all commands that operate the
 +
drive, to ensure that exactly one drive responds.  The command byte value
 +
lies in the range &40 to &7F.<ref name="footnote-cmd-range">The 8271 data
 +
sheet specifies command &35 to Initialise, i.e. both drive select lines
 +
zero.  With mini-floppy drives the drive select line levels do not matter
 +
while the head is unloaded and so command &75 is also acceptable.</ref>
 +
 
 +
Acorn DFS toggles ''both'' bits when the drive parameter selects drive 1 or
 +
3.<ref name="dnfs300-src-dos03">Acorn Computers, source code to DNFS 3.00, file <tt>[https://github.com/stardot/AcornDNFSv300/blob/master/src/DOS03#L349 DOS03]</tt>, l.349: <tt>EORIM &C0</tt></ref>
 +
Then it writes the command to the 8271 command register where bits 6 and 7
 +
directly control the select lines to drive 0 and 1, respectively.  Each
 +
attached drive responds only when its select line is set to logical 1.  The
 +
8271 uses bit 7 internally to choose which track register to update, and
 +
resets most drive control outputs when bits 6 or 7 change.
 +
Bit 5 of special register &23 controls the output on pin 1 and selects which
 +
side of the disc to use.<ref name="footnote-side-select">The 8271 does not
 +
know the purpose of the output and effectively assumes a single actuator for
 +
both sides of a double-sided drive.  Bit 1 of the mode register applies when
 +
two drives share one actuator, such as the drives on a DEC RX50.</ref>
 +
 
 +
Emulating implementations of OSWORD &7F typically mask off bits 6 and 7 of
 +
the command byte, and select the drive and side using their private control
 +
register.  They seldom recognise the 128-byte versions of commands.
  
DFS copies the drive and side bits from the drive number passed in XY?0,
+
Bit 4 is used to select the appropriate NMI and Tube code to transfer to or
and is the origin of the DFS drive numbering scheme. Bit 3 is used to
+
from the floppy disk controller.
select the appropriate NMI and Tube code to transfer to or from the
 
floppy disk controller.
 
  
Obviously, some combinations result in commands that are not sensible or are
+
Obviously, the bitmap above is a simplification: the real effect of each
ineffective. For instance, it makes no sense to combine "Read" with "no
+
command bit is more complex than the labels imply.  None of the undocumented
transfer".
+
commands are defined.  They are not available in implementations of OSWORD
 +
&7F that emulate an 8271 controller, though some undocumented commands on a
 +
real 8271 exhibit repeatable and exploitable behaviour.
  
 
==Implementation==
 
==Implementation==
Line 307: Line 335:
 
number. Unfortunately, the programmers didn't realise that the double
 
number. Unfortunately, the programmers didn't realise that the double
 
density bit was moved in the BBC Master hardware, so double density access
 
density bit was moved in the BBC Master hardware, so double density access
is not possible without a patched filing system
+
is not possible on the Master without a patched filing system<ref>http://mdfs.net/ROMs/Filing/Disk</ref>.
<ref>http://mdfs.net/ROMs/Filing/Disk</ref>.
 
  
 
===Watford DDFS===
 
===Watford DDFS===
 
Density selectable with b4-b5 of the drive number.
 
Density selectable with b4-b5 of the drive number.
 +
 +
===Opus DDOS===
 +
Command &5B auto-detects the disc density by trying each density twice until
 +
an ID is read.  It does not seek the specified track and reads one ID only,
 +
from the track currently under the read head.
 +
 +
Special register &12 is write-only and sets the current track number of
 +
the physical drive selected by XY?&00.
 +
 +
The count of bytes to be transferred is computed from the ''size+count''
 +
parameter, but the sectors' N records are not matched with ''size''.
 +
 +
There is one density flag and one double-stepping flag shared by all drives
 +
and exposed in the Read/write Special Registers commands.
 +
 +
The result of command &6C (read drive status) contains only the
 +
write-protect state in bit 3, ORed with &44.  Otherwise the returned status
 +
byte is the WD controller status byte masked according to the command (e.g.
 +
bit 5 is cleared if the command accepts deleted data). &00 indicates
 +
success; any other value indicates an error.  No translation to an
 +
equivalent 8271 result is carried out.
 +
 +
===Slogger Challenger===
 +
As Opus DDOS except this call provides floppy disc emulation for the
 +
RAM discs in drives 4 and 5. Special registers &12 and &1A emulate those in
 +
the 8271 but are still write-only due to a bug. XY?&00 b3=1 forces double
 +
density operation.
  
 
===Opus EDOS===
 
===Opus EDOS===
This emulates key commands of the 8271, and operates on each drive in the
+
This emulates key commands of the 8271, and maintains one density flag and
density that was detected at the last <code>*CAT</code> (single or double).
+
one double-stepping flag for each drive (two pairs of flags per disc.)  Only
Software double-stepping is enabled if <code>*OPT 8,255</code> is entered
+
a catalogue read operation updates the flags, one drive at a time, though a
and <code>*CAT</code> detects a 40 track disc.
+
manual <code>*OPT 6</code> or <code>*OPT 8</code> setting during the
 +
operation will force the flags to a desired value.  Commands that read the
 +
catalogue include <code>*CAT</code>, <code>*CATGEN</code>, [[OSFIND]]
 +
&40, [[OSGBPB]] 5 or 8, and (with an EDOSPAT patched ROM) [[OSWORD]] &71,
 +
&7D or &7E.  All raise an error if a valid catalogue is not found.
  
The Format Track command formats 256-byte sectors only in single density, or
+
The Format Track command formats 256-byte sectors only, in double density if
double density if 16 or more sectors are specified. The density of operation
+
16 or more sectors are specified, otherwise single. The density of operation
 
cannot be directly specified to other commands.
 
cannot be directly specified to other commands.
  
The sector size parameter is ignored in favour of the sectors' N records.
+
The sector size parameter is ignored in favour of the sectors' N records,
 +
which alone determine the number of bytes transferred.
 +
 
 +
Seven WD controller status values are translated to Intel equivalents (&00,
 +
&0A, &0C, &0E, &12, &18, &20); a WD status with an unexpected combination of
 +
errors is returned with bit 0 set.
  
 
==Coding==
 
==Coding==
Line 331: Line 394:
 
control block, <code>Y%=X%DIV256</code>. <code>den%=1</code> for single
 
control block, <code>Y%=X%DIV256</code>. <code>den%=1</code> for single
 
density and, if supported by the hardware, <code>den%=2</code> for double density.
 
density and, if supported by the hardware, <code>den%=2</code> for double density.
 +
It returns a result of &1E (not present) if no OSWORD &7F call is available.
  
 
     DEFFNdisk(addr%,cmd%,drv%,trk%,sec%,num%,den%):LOCAL fs%
 
     DEFFNdisk(addr%,cmd%,drv%,trk%,sec%,num%,den%):LOCAL fs%
Line 336: Line 400:
 
     REPEAT
 
     REPEAT
 
       X%?0=drv%+den%*24+8:X%!1=addr%:X%?5=3-7*(cmd%>127)
 
       X%?0=drv%+den%*24+8:X%!1=addr%:X%?5=3-7*(cmd%>127)
       X%?6=cmd%:X%?7=trk%:X%?8=sec%:X%?9=num%OR&20
+
       X%?6=cmd%:X%?7=trk%:X%?8=sec%:X%!9=num%OR&1E20
 
       A%=127:CALL&FFF1:A%=X%?(X%?5+7)
 
       A%=127:CALL&FFF1:A%=X%?(X%?5+7)
 
     UNTIL A%<>&10:IF fs%<>4:OSCLI"FX143,18,"+STR$ fs%
 
     UNTIL A%<>&10:IF fs%<>4:OSCLI"FX143,18,"+STR$ fs%

Latest revision as of 03:58, 11 February 2023

OSWORD &7F (127) - Floppy disk operation

Specification

On entry: On exit:
Control block
XY?&00 Drive
XY!&01 Data address
XY?&05 Number of parameters (n)
XY?&06 Command
XY+&07... Parameters
XY?(7+n) Result

No contents of the control block should be relied upon on exit other than the result byte. Some systems update the control block, some systems do not, though code universally expects the number of parameters to remain so the result can be found after the call with XY?(XY?5+7).

Command  Parameters Meaning
&40 <track> <sector> <size+count> <size> <field> Scan data **
&44 <track> <sector> <size+count> <size> <field> Scan data and deleted data multi-sector **
&4A <track> <sector> Write data 128 bytes
&4B <track> <sector> <size+count> Write data
&4E <track> <sector> Write deleted data 128 bytes
&4F <track> <sector> <size+count> Write deleted data
&52 <track> <sector> Read data 128 bytes
&53 <track> <sector> <size+count> Read data
&56 <track> <sector> Read data and deleted data 128 bytes
&57 <track> <sector> <size+count> Read data and deleted data
&5B <track> <&00> <count> Read IDs
&5E <track> <sector> Verify data and deleted data 128 bytes
&5F <track> <sector> <size+count> Verify data and deleted data
&63 <track> <gap3> <size+count> <gap5> <gap1>   Format track
&64 <track> (EDOS) Write track
&65 <track> (EDOS) Read track
&69 <track> Seek
&6C Read drive status and reset 'not ready'
&75 <&0D> <step> <settle> <load> Initialise
&75 <&1n> <bad 1> <bad 2> <current track> Specify bad tracks
&76 (EDOS) Force interrupt
&7A <register> <value> Write special register
&7D <register> Read special register
&E0 <track> <nine more bytes> (1770) Read track
&F0 <track> <nine more bytes> (1770) Write track

** Not possible on a BBC as needs DMA hardware.

Parameters

Drive

The drive number specifies the drive to access. If bit 7 is set, then the previously-used drive is used, and the drive status check is skipped.

The drive number can be expressed as a binary number %pxDDDdsd.

  • b7  : p - If 1, selects the previously-used drive and density
  • b5-b3 : DDD - select the drive density:
 %xx0=Acorn single density
 %xx1=Acorn double density
 %0xx=Watford current density
 %10x=Watford single density
 %11x=Watford double density
  • b2,b0 : dd - physical drive number
  • b1  : s - side

Single density DFSs do not have any ability to select double density disk access. Acorn DFSs select the density with b3, Watford DFSs select the density with b4 and b5. To specify a density in a manner compatible with both Acorn and Watford DFSs specify the density with both methods:

       %001000sd - to specify single density
       %001110sd - to specify double density

Most DFSs do not implement physical drives numbers larger than 1 (logical drives greater than 3). Selecting the previously selected drive can only be relied upon if DFS is the currently selected filing system. A drive number of &FF should be passed to select the previously used drive.

DFS 2.xx in the Master MOS 3.20 ROM incorrectly passes the density bit in b3 to the drive control register b3 instead of b5, so OSWORD &7F cannot access double density disks without patching the DFS[1].

Data Address

This is the address to transfer data to or from.

Track

This is the logical track to transfer data to or from. This may be different from the physical track number if the drive has previously been stepped to the correct physical track.

Sector

This is the logical sector number to start data transfer from. Sectors can be numbered anything from &00 to &FF, but single-density DFS-formatted disks use &00-&09 and double-density DFS and ADFS disks use &00-&0F.

Size + Count

Bits 0 to 4 specify the number of sectors to be read or written. Specifying zero sectors is undefined and may result in unpredictable behaviour.

Bits 5 to 7 specify the sector size as 128*2^size, as follows:

 b7   b6   b5   Sector size
0 0 0 128 bytes
0 0 1 256 bytes
0 1 0 512 bytes
0 1 1 1024 bytes
1 0 0 2048 bytes (8271 only)
1 0 1 4096 bytes (8271 only)
1 1 0 8192 bytes (8271 only)
1 1 1 16384 bytes (8271 only)

Special Registers

Command &7A and &7D write and read internal special registers. These registers are:

  • &00 40/80 flag (Opus) : reserved:dstep:0:0:0:0:0:0 0=single, 1=double
  • &03 Density (Opus) : reserved:densy:0:0:0:0:0:0 0=single, 1=double
  • &04 SROM (Opus) : &00-&0F
  • &06 Scan Sector (sector any error occured at)
  • &10 Bad Track Register 1 (drive 0/2)
  • &11 Bad Track Register 2 (drive 0/2)
  • &12 Track
  • &13 Scan Count LSB
  • &14 Scan Count MSB
  • &17 DMA Mode Register 1:1:0:0:0:0:<single head>:<no DMA>
  • &18 Bad Track 1 (drive 1/3)
  • &19 Bad Track 2 (drive 1/3)
  • &1A Track (drive 1/3)
  • &22 Drive Control Input
  • &23 Drive Control Output SEL1:SEL0:FAULT:LOW:LOAD:DIR:SEEK:WREN

What Special Registers are supported depends on the specific hardware and DFS firmware.

Result

The result is returned to the byte after the last parameter. The location is addressed by XY?(7+XY?5). For command &6C this location contains the drive status; for command &7D it is the requested special register; and for command &7A the result is undefined. Values returned by the other commands are as made up as follows:

  • b7-b6: always zero (1770 DFS returns 11 if command unrecognised)
  • b5:       deleted data found
  • b4-b3: completion type: 00=no error, 01=data error, 10=disk error, 11=media error
  • b2-b1: completion code
  • b0:       always zero (used by extensions)

This gives the following result values:

 type   code   Result   Meaning  Result   Meaning
00 00 &00 Successful completion
00 01 &02 Success, scan met equal **
00 10 &04 Success, scan met not equal **
00 11 &06 unused
01 00 &08 Clock error
01 01 &0A Late DMA ** / Late ISR / Abort, eg Escape
01 10 &0C ID CRC error / Bad sector ID
01 11 &0E Data CRC error
10 00 &10 Drive not ready
10 01 &12 Disk write protected
10 10 &14 Track 0 not found
10 11 &16 Write error
11 00 &18 Sector not found &19 Bad drive number
11 01 &1A unused (Disk changed) &1B Disk already mounted
11 10 &1C unused (Media change, eg Eject pressed) &1D Bad image filename
11 11 &1E Drive not present/drive empty &1F No disk mounted
&FE (Command not recognised)

** Not possible on a BBC as needs DMA hardware.

The result byte will have &20 added to it if deleted data has been read. Results in (brackets) are extensions used by systems with hardware that supports the functionality, or when translating results from non-8271 hardware. Odd numbered results are additional codes returned by extensions such as mounting image files, dropping bit 0 gives an equivalent hardware code.

Intel documentation states that result type 01 should be retried up to a total of ten times before abandoning. In practice:

  • results types 01 and 10, other than &10 - Drive not ready - and &12 - Disk write protected, should be retried up to ten times
  • result &10 should be retried indefinitely until some other result occurs
  • result &18 - Sector not found - could be followed by a seek to track zero then one additional attempt.
  • While result &1E - Drive not present/empty - is not mentioned in official documentation, if left trying to access an empty drive this result will eventually occur. As such, emulators such as BeebEm will give Disk fault 1E if trying to access an empty drive. 1770 DFSs usually return Disk error 18 (Sector not found) instead.

The result byte can be preloaded with a value to return if no OSWORD &7F routine exists. For instance, preloading the result with &00 makes all such failed calls appear to succeed, preloading with &18 makes all calls appear to return 'Sector not found'. HADFS preloads the result byte with &1E to give a default result of 'Drive not present'.

Read Drive Status (&6C) resets any 'not ready' error and returns the drive status as the result byte:

  • b7: unused
  • b6: READY1
  • b5: FAULT
  • b4: INDEX
  • b3: WRPROTECT
  • b2: READY0
  • b1: TRACK0
  • b0: COUNT

8271 Commands

The 8271 command passed in the control block is actually a bitmap made up as follows:

  +---+---+---+---+---+---+---+---+
  | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 
  +---+---+---+---+---+---+---+---+
    |   |   |   ||  |   |   |   |
    |   |   +---+---+   |   +---+----Size:  00 multiple scan data
    |   |       ||      |                   01 no transfer
    |   |       ||      |                   10 128 bytes
    |   |       ||      |                   11 multiple sectors
    |   |       ||      |
    |   |       ||      +------------Data:   0 ignore deleted data
    |   |       ||                           1 accept deleted data
    |   |       ||
    |   |       |+--------------Direction:   0 Write to FDC
    |   |       |                            1 Read from FDC
    |   |       |
    |   |       +-----------------Command: 000 Scan
    |   |                                  001 Write
    |   |                                  010 Read
    |   |                                  011 Verify
    |   |                                  100 Format
    |   |                                  101 Seek
    |   |                                  110 Initialise
    |   |                                  111 Special Registers
    |   |
    |   +---------------------------------- Drive select 0
    +-------------------------------------- Drive select 1

The drive select bits must be set to %01 in all commands that operate the drive, to ensure that exactly one drive responds. The command byte value lies in the range &40 to &7F.[2]

Acorn DFS toggles both bits when the drive parameter selects drive 1 or 3.[3] Then it writes the command to the 8271 command register where bits 6 and 7 directly control the select lines to drive 0 and 1, respectively. Each attached drive responds only when its select line is set to logical 1. The 8271 uses bit 7 internally to choose which track register to update, and resets most drive control outputs when bits 6 or 7 change. Bit 5 of special register &23 controls the output on pin 1 and selects which side of the disc to use.[4]

Emulating implementations of OSWORD &7F typically mask off bits 6 and 7 of the command byte, and select the drive and side using their private control register. They seldom recognise the 128-byte versions of commands.

Bit 4 is used to select the appropriate NMI and Tube code to transfer to or from the floppy disk controller.

Obviously, the bitmap above is a simplification: the real effect of each command bit is more complex than the labels imply. None of the undocumented commands are defined. They are not available in implementations of OSWORD &7F that emulate an 8271 controller, though some undocumented commands on a real 8271 exhibit repeatable and exploitable behaviour.

Implementation

Some DFSs, such as DFS 2.45 supplied in the Master MOS 3.50 ROM, only respond to OSWORD &7F if DFS is the current filing system and fail silently if any other filing system is selected.

Acorn DFS

This is the original implementation of OSWORD &7F. It is a fairly simple interface to the Intel 8271 floppy disc controller; it passes the command and parameters to the controller, supplies the appropriate NMI service routine to fetch or store the disc data, and returns the result.

Acorn 1770 DFS

This emulates key commands of the 8271. Software double-stepping is available. Double density access can be made by setting bit 3 of the drive number. Unfortunately, the programmers didn't realise that the double density bit was moved in the BBC Master hardware, so double density access is not possible on the Master without a patched filing system[5].

Watford DDFS

Density selectable with b4-b5 of the drive number.

Opus DDOS

Command &5B auto-detects the disc density by trying each density twice until an ID is read. It does not seek the specified track and reads one ID only, from the track currently under the read head.

Special register &12 is write-only and sets the current track number of the physical drive selected by XY?&00.

The count of bytes to be transferred is computed from the size+count parameter, but the sectors' N records are not matched with size.

There is one density flag and one double-stepping flag shared by all drives and exposed in the Read/write Special Registers commands.

The result of command &6C (read drive status) contains only the write-protect state in bit 3, ORed with &44. Otherwise the returned status byte is the WD controller status byte masked according to the command (e.g. bit 5 is cleared if the command accepts deleted data). &00 indicates success; any other value indicates an error. No translation to an equivalent 8271 result is carried out.

Slogger Challenger

As Opus DDOS except this call provides floppy disc emulation for the RAM discs in drives 4 and 5. Special registers &12 and &1A emulate those in the 8271 but are still write-only due to a bug. XY?&00 b3=1 forces double density operation.

Opus EDOS

This emulates key commands of the 8271, and maintains one density flag and one double-stepping flag for each drive (two pairs of flags per disc.) Only a catalogue read operation updates the flags, one drive at a time, though a manual *OPT 6 or *OPT 8 setting during the operation will force the flags to a desired value. Commands that read the catalogue include *CAT, *CATGEN, OSFIND &40, OSGBPB 5 or 8, and (with an EDOSPAT patched ROM) OSWORD &71, &7D or &7E. All raise an error if a valid catalogue is not found.

The Format Track command formats 256-byte sectors only, in double density if 16 or more sectors are specified, otherwise single. The density of operation cannot be directly specified to other commands.

The sector size parameter is ignored in favour of the sectors' N records, which alone determine the number of bytes transferred.

Seven WD controller status values are translated to Intel equivalents (&00, &0A, &0C, &0E, &12, &18, &20); a WD status with an unexpected combination of errors is returned with bit 0 set.

Coding

The following routine can be used to perform an OSWORD &7F call that takes three parameters, such as Write (&4B) and Read (&53), or Track Read (&E0) and Track Write (&F0) which take ten parameters. It requires X%=>15-byte control block, Y%=X%DIV256. den%=1 for single density and, if supported by the hardware, den%=2 for double density. It returns a result of &1E (not present) if no OSWORD &7F call is available.

   DEFFNdisk(addr%,cmd%,drv%,trk%,sec%,num%,den%):LOCAL fs%
   fs%=FNfs:IF fs%<>4:*FX143,18,4
   REPEAT
     X%?0=drv%+den%*24+8:X%!1=addr%:X%?5=3-7*(cmd%>127)
     X%?6=cmd%:X%?7=trk%:X%?8=sec%:X%!9=num%OR&1E20
     A%=127:CALL&FFF1:A%=X%?(X%?5+7)
   UNTIL A%<>&10:IF fs%<>4:OSCLI"FX143,18,"+STR$ fs%
   =A%
   DEFFNfs:LOCAL A%,E%,Y%:=(USR&FFDA)AND&FF

Tube note

The Tube MOS copies a 16-byte control block over the Tube, so on a read operation, any data read to immediately after the control block will be overwitten by the returned control block if it is within 16 bytes of the start of the control block.

If code is to run properly, the destination address of any reads must be at least 16 bytes away from the start of the control block, for example:

   DIM X% 15, T% 255
   Y% = X% DIV 256
   X%!1 = T%
   etc...

If blocks are declared with variables in the heap, the variable definitions count towards the 16-byte distance, so the following is ok:

   DIM ctrl% 12, data% 255
   X%=ctrl%:Y%=X% DIV 256
   X%!1 = data%
   etc...

As the variable data% is assigned space between the two buffers, the value of data% - ctrl% exceeds 15.

See Also

References

  1. http://mdfs.net/ROMs/Filing/Disk
  2. The 8271 data sheet specifies command &35 to Initialise, i.e. both drive select lines zero. With mini-floppy drives the drive select line levels do not matter while the head is unloaded and so command &75 is also acceptable.
  3. Acorn Computers, source code to DNFS 3.00, file DOS03, l.349: EORIM &C0
  4. The 8271 does not know the purpose of the output and effectively assumes a single actuator for both sides of a double-sided drive. Bit 1 of the mode register applies when two drives share one actuator, such as the drives on a DEC RX50.
  5. http://mdfs.net/ROMs/Filing/Disk