mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-26 18:04:07 +00:00
342 lines
9.2 KiB
NASM
342 lines
9.2 KiB
NASM
; 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
|
||
|