Files
Digital-Research-Source-Code/CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG9-5.ASM
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

342 lines
9.2 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

; Figure 9-5
;
; This shows slightly more user-friendly error processor
; for disk errors than that shown in the enhanced BIOS
; in Figure 8-10.
; This version outputs a recommended course of action
; depending on the nature of the error detected.
; Code that remains unchanged from Figure 8-10 has been
; abbreviated.
;
; Dummy Equates and data declarations needed to get
; an error free assembly of this example.
;
Floppy$Read$Code EQU 01H ;Read Command for controller
Floppy$Write$Code EQU 02H ;Write Command for controller
;
Disk$Hung$Flag: DB 0 ;Set NZ when Watchdog timer times
; out.
Disk$Timer EQU 600 ;10 seconds delay (16.66ms tick)
;
Disk$Status$Block EQU 43H ;Address in memory where controller
; returns status
;Values from controller command table
Floppy$Command: DB 0
Floppy$Head: DB 0
Floppy$Track: DB 0
Floppy$Sector: DB 0
Deblocking$Required: DB 0 ;Flag set by SELDSK according
; to selected disk type
Disk$Error$Flag: DB 0 ;Error flag returned to BDOS
;
In$Buffer$Disk: DB 0 ;Logical disk Id. relating to current
; disk sector in deblocking buffer
;
; Equates for Messages
;
BELL EQU 07H ;Sound terminal Bell
CR EQU 0DH ;Carriage Return
LF EQU 0AH ;Line Feed
;
BDOS EQU 5 ;BDOS Entry Point (for system reset)
;
;
;
;
No$Deblock$Retry:
;----------------------------------------------------
; Omitted code to setup disk controller command table
; and initiate the disk operation
;----------------------------------------------------
JMP Wait$For$Disk$Complete
;
;
Write$Physical: ;Write contents of Disk Buffer to
; correct sector.
MVI A,Floppy$Write$Code ;Get Write Function code
JMP Common$Physical ;Go to common code
Read$Physical: ;Read previously selected Sector
; into Disk Buffer.
MVI A,Floppy$Read$Code ;Get Read Function code
Common$Physical:
STA Floppy$Command ;Set command table
;
Deblock$Retry: ;Re-entry point to re-try after error
;---------------------------------------------------
; Omitted code sets up disk controller command block
; and initiates the disk operation
;---------------------------------------------------
;
Wait$For$Disk$Complete: ;Wait until Disk Status Block indicates
; operation has completed, then check
; if any errors occurred.
;On entry HL -> Disk Control byte
XRA A ;Ensure hung flag clear
STA Disk$Hung$Flag
LXI H,Disk$Timed$Out ;Setup Watchdog timer
LXI B,Disk$Timer ;Time delay
CALL Set$Watchdog
Disk$Wait$Loop:
MOV A,M ;Get control byte
ORA A
JZ Disk$Complete ;Operation done
LDA Disk$Hung$Flag ;Also check if timed out
ORA A
JNZ Disk$Error ;Will be set to 40H
JMP Disk$Wait$Loop
Disk$Timed$Out: ;Control arrives here from Watchdog
; routine itself - so this is effectively
; part of the interrupt service routine.
MVI A,40H ;Set Disk Hung error code
STA Disk$Hung$Flag ; into error flag to pull
; control out of loop
RET ;Return to Watchdog routine
Disk$Complete:
LXI B,0 ;Reset Watchdog timer
;HL is irrelevant here
CALL Set$Watchdog
LDA Disk$Status$Block ;Complete - now check status
CPI 80H ;Check if any errors occurred
JC Disk$Error ;Yes
;
Disk$Error$Ignore:
XRA A ;No
STA Disk$Error$Flag ;Clear error flag
RET
;
; Disk Error Message handling
;
;
Disk$Error$Messages: ;This table is scanned, comparing the
; Disk Error Status with those in the
; table. Given a match, or even when
; then end of the table is reached, the
; address following the status value
; points to the correct advisory message text.
; Following this is the address of an
; error description message.
DB 40H
DW Disk$Advice1,Disk$Msg$40
DB 41H
DW Disk$Advice2,Disk$Msg$41
DB 42H
DW Disk$Advice3,Disk$Msg$42
DB 21H
DW Disk$Advice4,Disk$Msg$21
DB 22H
DW Disk$Advice5,Disk$Msg$22
DB 23H
DW Disk$Advice5,Disk$Msg$23
DB 24H
DW Disk$Advice6,Disk$Msg$24
DB 25H
DW Disk$Advice6,Disk$Msg$25
DB 11H
DW Disk$Advice7,Disk$Msg$11
DB 12H
DW Disk$Advice7,Disk$Msg$12
DB 13H
DW Disk$Advice7,Disk$Msg$13
DB 14H
DW Disk$Advice7,Disk$Msg$14
DB 15H
DW Disk$Advice7,Disk$Msg$15
DB 16H
DW Disk$Advice7,Disk$Msg$16
DB 0 ;<== Terminator
DW Disk$Advice7,Disk$Msg$Unknown ;Unmatched code
;
DEM$Entry$Size EQU 5 ;Entry size in Error Message Table
;
;
; Message Texts
;
Disk$Msg$40: DB 'Hung',0 ;Timeout message
Disk$Msg$41: DB 'Not Ready',0
Disk$Msg$42: DB 'Write Protected',0
Disk$Msg$21: DB 'Data',0
Disk$Msg$22: DB 'Format',0
Disk$Msg$23: DB 'Missing Data Mark',0
Disk$Msg$24: DB 'Bus Timeout',0
Disk$Msg$25: DB 'Controller Timeout',0
Disk$Msg$11: DB 'Drive Address',0
Disk$Msg$12: DB 'Head Address',0
Disk$Msg$13: DB 'Track Address',0
Disk$Msg$14: DB 'Sector Address',0
Disk$Msg$15: DB 'Bus Address',0
Disk$Msg$16: DB 'Illegal Command',0
Disk$Msg$Unknown: DB 'Unknown',0
;
Disk$EM$1: ;Main disk error message - part 1
DB BELL,CR,LF
DB 'Disk ',0
;
;Error Text output next
;
Disk$EM$2: ;Main disk error message - part 2
DB ' Error ('
Disk$EM$Status: DB 0,0 ;Status code in Hex
DB ')',CR,LF,' Drive '
Disk$EM$Drive: DB 0 ;Disk Drive code, A,B...
DB ', Head '
Disk$EM$Head: DB 0 ;Head number
DB ', Track '
Disk$EM$Track: DB 0,0 ;Track number
DB ', Sector '
Disk$EM$Sector: DB 0,0 ;Sector number
DB ', Operation - '
DB 0 ;Terminator
;
Disk$EM$Read: DB 'Read.',0 ;Operation names
Disk$EM$Write: DB 'Write.',0
;
Disk$Advice0: DB CR,LF,' ',0
Disk$Advice1: DB 'Check disk loaded, Retry',0
Disk$Advice2: DB 'Possible hardware problem',0
Disk$Advice3: DB 'Write enable if correct disk, Retry',0
Disk$Advice4: DB 'Retry several times',0
Disk$Advice5: DB 'Reformat disk or use another disk',0
Disk$Advice6: DB 'Hardware error, Retry',0
Disk$Advice7: DB 'Hardware or Software error, Retry',0
;
Disk$Advice9: DB ', or call for help if error persists',CR,LF
;
Disk$Action$Confirm:
DB 0 ;Set to character entered by user
DB CR,LF,0
;
; Disk Error Processor
;
; This routine builds and outputs an error message.
; The user is then given the opportunity to :
;
; R - Retry the operation that caused the error.
; I - Ignore the error and attempt to continue.
; A - Abort the program and return to CP/M.
;
Disk$Error:
PUSH PSW ;Preserve error code from controller
LXI H,Disk$EM$Status ;Convert code for message
CALL CAH ;Converts A to hex
LDA In$Buffer$Disk ;Convert disk id. for message
ADI 'A' ;Make into letter
STA Disk$EM$Drive
LDA Floppy$Head ;Convert head number
ADI '0'
STA Disk$EM$Head
LDA Floppy$Track ;Convert track number
LXI H,Disk$EM$Track
CALL CAH
LDA Floppy$Sector ;Convert sector number
LXI H,Disk$EM$Sector
CALL CAH
LXI H,Disk$EM$1 ;Output first part of message
CALL Output$Error$Message
POP PSW ;Recover error status code
MOV B,A ;For comparisons
LXI H,Disk$Error$Messages - DEM$Entry$Size
;HL -> Table - one entry
LXI D,DEM$Entry$Size ;For loop below
Disk$Error$Next$Code:
DAD D ;Move to next (or first) entry
MOV A,M ;Get code number from table
ORA A ;Check if end of table
JZ Disk$Error$Matched ;Yes - pretend a match occurred
CMP B ;Compare to actual code
JZ Disk$Error$Matched ;Yes - exit from loop
JMP Disk$Error$Next$Code ;Check next code
;
Disk$Error$Matched:
INX H ;HL -> Advisory text address
MOV E,M
INX H
MOV D,M ;DE -> Advisory test
PUSH D ;Save for later
INX H ;HL -> Message text address
MOV E,M ;Get Address into DE
INX H
MOV D,M
XCHG ;HL -> Text
CALL Output$Error$Message ;Display explanatory text
LXI H,Disk$EM$2 ;Display second part of message
CALL Output$Error$Message
LXI H,Disk$EM$Read ;Choose operation text
; (assume a read)
LDA Floppy$Command ;Get controller command
CPI Floppy$Read$Code
JZ Disk$Error$Read ;Yes
LXI H,Disk$EM$Write ;No - change address in HL
Disk$Error$Read:
CALL Output$Error$Message ;Display operation type
LXI H,Disk$Advice0 ;Display leading blanks
CALL Output$Error$Message
POP H ;Recover Advisory text pointer
CALL Output$Error$Message
LXI H,Disk$Advice9 ;Display trailing component
CALL Output$Error$Message
;
Disk$Error$Request$Action: ;Ask the user what to do next
CALL Request$User$Choice ;Display prompt and get single
; character response (folded to
; upper case)
CPI 'R' ;Retry?
JZ Disk$Error$Retry
CPI 'A' ;Abort
JZ System$Reset
CPI 'I' ;Ignore
JZ Disk$Error$Ignore
JMP Disk$Error$Request$Action
;
Disk$Error$Retry: ;The decision on where to return to
; depends on whether the operation
; failed on a deblocked or
; non-deblocked drive
LDA Deblocking$Required
ORA A
JNZ Deblock$Retry
JMP No$Deblock$Retry
;
System$Reset: ;This is a radical approach, but
; it does cause CP/M to restart
MVI C,0 ;System Reset
CALL BDOS
;
; Omitted subroutines (listed in full in Figure 8-10)
;
Set$Watchdog: ;Set Watchdog timer (to number of "ticks" in BC, and
; to transfer control to (HL) if timer hits zero).
CAH: ;Convert A to two ASCII hex characters, storing
; the output in (HL) and (HL+1)
Output$Error$Message: ;Display the 00-byte terminated error message
; pointed to by HL. Output is directed only to
; those console devices not being used for list
; output as well.
Request$User$Choice: ;Display prompt "Enter R, A, I..." and return
; single keyboard character (upper case) in A
RET ;Dummy