module
31

| Command | Does | Section |
|---|---|---|
F name | Build and show the FCB for a name | S6 |
O name | Open; show A and the FCB | S7 |
T name | Type a text file through the BDOS | S8 |
R name n | Record n, by read random | S9, S12 |
W name text | Write a new one-record file | S10 |
E name | Erase | S11 |
N old new | Rename | S11 |
P name n text | Write record n, by write random | S11 |
S d t s | Show a sector (s a number, or a letter for its ID) | S13, S24 |
+ | The next sector | S14 |
D d | Directory, by hand | S16 |
L d name | Type a file, by hand | S17 |
K offset text | Put text into the sector buffer | S18 |
M d t s | Write the sector buffer | S18 |
U d | Show a disc's boot header | S19 |
B | Make drive 1's disc start DISKMON | S20 |
J d name n | Record n, by hand | S22 |
G d t | Move a head: Restore, Seek | S25, S26 |
I d t | A track's IDs, in the order they pass the head | S27 |
H d t s | Read a sector through the controller's ports | S28 |
Q | Back to the DOS (or stop, if booted) | S6, S21 |
Names are [d:]NAME.EXT; d is 0 or 1. The BDOS commands (F to P) need XtalDOS; booted, DISKMON refuses them.
; DISKMON - reads and writes the Einstein's discs.
; The Assembly Disc Access Primer's program, as it stands at the end of
; the section named in this file's name.
ORG 0100H
; Buffers, clear of the program, the DOS and the MOS.
DIRBUF: EQU 8000H ; a whole directory: 4 sectors, 2048 bytes
SECBUF: EQU 8800H ; one sector: 512 bytes
RECBUF: EQU 8A00H ; one record: 128 bytes
LINE: EQU 8A80H ; the command line: 64 bytes
STACK: EQU 9000H ; DISKMON's own stack grows down from here
START: LD (OLDSP),SP
LD SP,STACK
LD HL,TITLE
CALL PRINT
XOR A ; is there a DOS? 0005h holds JP (C3h) if so
LD (HASDOS),A
LD A,(0005H)
CP 0C3H
JR NZ,NODOS
LD A,1
LD (HASDOS),A
JR MAIN
NODOS: LD HL,NODOSM
CALL PRINT
; The command loop: read a line, act on its first letter.
MAIN: LD SP,STACK
LD HL,PROMPT
CALL PRINT
CALL GETLINE
CALL NEWLINE
CALL SKIPSP
OR A
JR Z,MAIN
INC HL
LD (LPTR),HL
CP 'Q'
JP Z,QUIT
CP 'F'
JP Z,CMDF
CP 'O'
JP Z,CMDO
CP 'T'
JP Z,CMDT
CP 'R'
JP Z,CMDR
CP 'W'
JP Z,CMDW
CP 'E'
JP Z,CMDE
CP 'N'
JP Z,CMDN
CP 'P'
JP Z,CMDP
CP 'S'
JP Z,CMDS
CP '+'
JP Z,CMDNXT
CP 'D'
JP Z,CMDD
CP 'L'
JP Z,CMDL
CP 'K'
JP Z,CMDK
CP 'M'
JP Z,CMDM
CP 'U'
JP Z,CMDU
CP 'B'
JP Z,CMDB
CP 'J'
JP Z,CMDJ
CP 'G'
JP Z,CMDG
CP 'I'
JP Z,CMDI
CP 'H'
JP Z,CMDH
WHAT: LD HL,WHATM
DONE: CALL PRINT
JP MAIN
CRMAIN: CALL NEWLINE
JP MAIN
QUIT:
LD A,(HASDOS)
OR A
JR NZ,QUIT1
LD HL,STOPM ; no DOS to go back to
CALL PRINT
STOP: JR STOP
QUIT1:
LD SP,(OLDSP)
RET
; ---------------------------------------------------------------- BDOS
; F name: build the FCB for a name and show its 36 bytes.
CMDF: LD DE,FCB
CALL GETNAME
JP C,WHAT
LD HL,FCB
LD BC,36
CALL SHOWBLK
JP MAIN
; O name: open the file; show what the BDOS says and the FCB after.
CMDO: CALL NEEDDOS
LD DE,FCB
CALL GETNAME
JP C,WHAT
LD DE,FCB
LD C,15
CALL 5
PUSH AF
LD HL,OPENM
CALL PRINT
POP AF
PUSH AF
CALL PHEX
CALL NEWLINE
POP AF
CP 0FFH
LD HL,NOTFM
JP Z,DONE
LD HL,FCB
LD BC,32
CALL SHOWBLK
JP MAIN
; T name: type a text file, a record at a time, through the BDOS.
CMDT: CALL NEEDDOS
CALL OPENIT
LD DE,RECBUF ; reads go to RECBUF
LD C,26
CALL 5
LD HL,0
LD (COUNT),HL
CMDT1: LD DE,FCB
LD C,20 ; read the next record
CALL 5
OR A
JR NZ,CMDT2 ; not 0: the end of the file
LD HL,(COUNT)
INC HL
LD (COUNT),HL
LD HL,RECBUF
LD BC,128
CALL TYPEOUT
JR NC,CMDT1 ; carry: a 1Ah ended the text
CMDT2: CALL NEWLINE
LD HL,(COUNT)
CALL PDEC
LD HL,RECSM
JP DONE
; OPENIT: name from the line into FCB, open it; to MAIN if that fails.
OPENIT: LD DE,FCB
CALL GETNAME
JP C,WHAT
LD DE,FCB
LD C,15
CALL 5
CP 0FFH
RET NZ
LD HL,NOTFM
JP DONE
; R name n: read record n with read random and show it.
CMDR: CALL NEEDDOS
CALL OPENIT
CALL GETNUM
JP C,WHAT
LD (FCB+33),HL ; the record number, low byte first
XOR A
LD (FCB+35),A
LD DE,RECBUF
LD C,26
CALL 5
LD DE,FCB
LD C,33 ; read random
CALL 5
OR A
JR NZ,CMDR1
LD HL,RECBUF
LD BC,128
CALL SHOWBLK
JP MAIN
CMDR1: CP 1
LD HL,NORECM
JP Z,DONE
CP 4
LD HL,NOEXTM
JP Z,DONE
PUSH AF
LD HL,AM
CALL PRINT
POP AF
CALL PHEX
JP CRMAIN
; W name text: make a new file holding one record: the text, then
; CR LF, then 1Ah to the end of the record.
CMDW: CALL NEEDDOS
LD DE,FCB
CALL GETNAME
JP C,WHAT
CALL TEXTREC ; the rest of the line into RECBUF
LD DE,FCB
LD C,19 ; delete any old file of this name
CALL 5
LD DE,FCB
LD C,22 ; make
CALL 5
CP 0FFH
LD HL,NOMAKEM
JP Z,DONE
LD DE,RECBUF
LD C,26
CALL 5
LD DE,FCB
LD C,21 ; write the record
CALL 5
LD DE,FCB
LD C,16 ; close: now the directory knows
CALL 5
LD HL,WROTEM
JP DONE
; TEXTREC: RECBUF = the rest of the command line, CR, LF, then 1Ah.
TEXTREC: LD HL,RECBUF
LD B,128
TR1: LD (HL),1AH
INC HL
DJNZ TR1
CALL SKIPSP
LD DE,RECBUF
LD B,125
TR2: LD A,(HL)
OR A
JR Z,TR3
LD (DE),A
INC HL
INC DE
DJNZ TR2
TR3: LD A,13
LD (DE),A
INC DE
LD A,10
LD (DE),A
RET
; E name: erase a file.
CMDE: CALL NEEDDOS
LD DE,FCB
CALL GETNAME
JP C,WHAT
LD DE,FCB
LD C,19
CALL 5
CP 0FFH
LD HL,NOTFM
JP Z,DONE
LD HL,ERASEM
JP DONE
; N old new: rename. The new name goes in FCB bytes 16-31.
CMDN: CALL NEEDDOS
LD DE,FCB
CALL GETNAME
JP C,WHAT
LD DE,FCB2
CALL GETNAME
JP C,WHAT
LD HL,FCB2
LD DE,FCB+16
LD BC,16
LDIR
XOR A
LD (FCB+16),A ; the new name's drive byte: 0
LD DE,FCB
LD C,23
CALL 5
CP 0FFH
LD HL,NOTFM
JP Z,DONE
LD HL,RENM
JP DONE
; P name n text: write the text as record n, with write random.
CMDP: CALL NEEDDOS
CALL OPENIT
CALL GETNUM
JP C,WHAT
LD (FCB+33),HL
XOR A
LD (FCB+35),A
CALL TEXTREC
LD DE,RECBUF
LD C,26
CALL 5
LD DE,FCB
LD C,34 ; write random
CALL 5
LD DE,FCB
LD C,16
CALL 5
LD HL,WROTEM
JP DONE
; NEEDDOS: back to MAIN with a message if there is no DOS to call.
NEEDDOS:
LD A,(HASDOS)
OR A
RET NZ
LD HL,NEEDM
JP DONE
RET
; ----------------------------------------------------------------- MOS
; S d t s: read drive d, track t, sector s and show it.
CMDS: CALL GETDTS
JP C,WHAT
CMDS1: CALL READSEC
JP NZ,DISCERR
CALL TRIES
LD HL,SECBUF
LD BC,512
CALL SHOWBLK
JP MAIN
; GETDTS: drive, track, sector from the line into SDRV, STRK, SSEC.
GETDTS: CALL GETNUM
RET C
LD (SDRV),A
CALL GETNUM
RET C
LD (STRK),A
CALL SKIPSP ; a letter is an ID in itself
CP 'A'
JR C,GDT1
INC HL
LD (LPTR),HL
LD (SSEC),A
OR A
RET
GDT1:
CALL GETNUM
RET C
LD (SSEC),A
RET
; READSEC: MOS call 162 - the sector in SDRV/STRK/SSEC to SECBUF.
; Z set if it was read.
READSEC: CALL SETPAD
RST 8
DEFB 162
RET
; SETPAD: the MOS's scratch-pad: drive, track, sector, address.
SETPAD: LD A,(SDRV)
LD (0FB50H),A
LD A,(STRK)
LD (0FB51H),A
LD A,(SSEC)
LD (0FB52H),A
LD HL,SECBUF
LD (0FB53H),HL
RET
; +: the next sector - the next ID, then sector 0 of the next track.
CMDNXT: LD HL,SSEC
INC (HL)
LD A,(HL)
CP 10
JP C,CMDS1
LD (HL),0
LD HL,STRK
INC (HL)
JP CMDS1
; DISCERR: the MOS said no. A holds its error number.
DISCERR: PUSH AF
LD HL,DERRM
CALL PRINT
POP AF
PUSH AF
CALL PHEX
POP AF
CP 3
LD HL,NOSECM
JP Z,DONE
CP 1
LD HL,BADM
JP Z,DONE
JP CRMAIN
; TRIES: how many of its ten tries the MOS needed.
TRIES: LD HL,TRIESM
CALL PRINT
LD A,(0FB57H)
LD B,A
LD A,11
SUB B
LD L,A
LD H,0
CALL PDEC
JP NEWLINE
; D d: list the files on drive d by reading the directory itself.
CMDD: CALL GETNUM
JP C,WHAT
LD (SDRV),A
CALL READDIR
JP NZ,DISCERR
LD IX,DIRBUF
LD B,64
CMDD1: PUSH BC
LD A,(IX+0)
CP 0E5H ; E5h: an empty or deleted slot
JR Z,CMDD2
CALL SHOWENT
CMDD2: LD DE,32
ADD IX,DE
POP BC
DJNZ CMDD1
JP MAIN
; READDIR: track 2 sectors 0-3 of drive SDRV into DIRBUF. Z if all read.
READDIR: LD A,2
LD (STRK),A
LD HL,DIRBUF
LD B,0
RD1: PUSH BC
PUSH HL
LD A,B
LD (SSEC),A
CALL SETPAD
POP HL
LD (0FB53H),HL ; this sector's place in DIRBUF
PUSH HL
RST 8
DEFB 162
POP HL
POP BC
RET NZ
INC H ; 512 bytes on: H + 2
INC H
INC B
LD A,B
CP 4
JR NZ,RD1
XOR A ; Z: all four read
RET
; SHOWENT: one directory entry at IX: name, extent, record count.
SHOWENT: PUSH IX
POP HL
INC HL
LD B,8
CALL PNAME
LD A,'.'
CALL PUTC
LD B,3
CALL PNAME
BIT 7,(IX+9)
LD A,' '
JR Z,SE1
LD A,'*' ; bit 7 of byte 9: locked
SE1: CALL PUTC
LD HL,EXTM
CALL PRINT
LD L,(IX+12)
LD H,0
CALL PDEC
LD HL,RECM
CALL PRINT
LD L,(IX+15)
LD H,0
CALL PDEC
JP NEWLINE
; PNAME: print B name characters from HL, without their top bits.
PNAME: LD A,(HL)
AND 7FH
CALL PUTC
INC HL
DJNZ PNAME
RET
; L d name: find a file in drive d's directory and type it, following
; its blocks to the sectors - what the BDOS's open and read did for you.
CMDL: CALL FINDSET
XOR A
LD (EXTENT),A
CMDL1: CALL FINDEXT
JR NZ,CMDL9
LD A,(IX+15) ; records in this extent
LD (RLEFT),A
LD B,8
PUSH IX
POP HL
LD DE,16
ADD HL,DE ; HL -> the block numbers
CMDL2: PUSH BC
LD E,(HL)
INC HL
LD D,(HL)
INC HL
PUSH HL
LD A,D
OR E
JR Z,CMDL8 ; block 0: no more blocks
LD B,4 ; four sectors to a block
LD C,0
CMDL3: PUSH BC
PUSH DE
LD A,(RLEFT)
OR A
JR Z,CMDL7
CALL BLKSEC ; block DE, sector C -> STRK, SSEC
CALL READSEC
JP NZ,DISCERR
LD A,(RLEFT) ; up to four records from this sector
LD B,4
CP B
JR NC,CMDL4
LD B,A
CMDL4: LD A,(RLEFT)
SUB B
LD (RLEFT),A
LD HL,0
LD DE,128
CMDL5: ADD HL,DE
DJNZ CMDL5 ; HL = 128 x records
LD B,H
LD C,L
LD HL,SECBUF
CALL TYPEOUT
JR C,CMDL6 ; 1Ah: the text has ended
POP DE
POP BC
INC C
DJNZ CMDL3
POP HL
POP BC
DJNZ CMDL2
JR CMDLX
CMDL6: JP CRMAIN
CMDL7: POP DE
POP BC
CMDL8: POP HL
POP BC
CMDLX: LD HL,EXTENT
INC (HL)
JR CMDL1
CMDL9: LD A,(EXTENT)
OR A
LD HL,NOTFM
JP Z,DONE
JP CRMAIN
; FINDSET: drive and name from the line; read the directory.
FINDSET: CALL GETNUM
JP C,WHAT
LD (SDRV),A
LD DE,FCB
CALL GETNAME
JP C,WHAT
CALL READDIR
JP NZ,DISCERR
RET
; FINDEXT: IX -> the entry for FCB's name with extent EXTENT. Z if found.
FINDEXT: LD IX,DIRBUF
LD B,64
FE1: LD A,(IX+0)
CP 0E5H
JR Z,FE3
LD A,(EXTENT)
CP (IX+12)
JR NZ,FE3
PUSH BC
PUSH IX
POP HL
INC HL
LD DE,FCB+1
LD B,11
FE2: LD A,(HL)
AND 7FH ; ignore the locked bit
LD C,A
LD A,(DE)
CP C
JR NZ,FE4
INC HL
INC DE
DJNZ FE2
POP BC
XOR A ; Z: found
RET
FE4: POP BC
FE3: LD DE,32
ADD IX,DE
DJNZ FE1
OR 1 ; NZ: not there
RET
; BLKSEC: block DE's sector C (0-3) -> STRK, SSEC.
; Logical sector 4 x block + C, counted from track 2 sector 0;
; track = logical / 10 + 2, sector = logical mod 10.
BLKSEC: EX DE,HL
ADD HL,HL
ADD HL,HL
LD B,0
ADD HL,BC
CALL DIV10
LD (SSEC),A
LD A,L
ADD A,2
LD (STRK),A
RET
; K offset text: put the text into the sector buffer at offset.
CMDK: CALL GETNUM
JP C,WHAT
LD DE,SECBUF
ADD HL,DE
EX DE,HL
LD HL,(LPTR)
LD A,(HL) ; one space, then the text exactly
CP ' '
JR NZ,CMDK1
INC HL
CMDK1: LD A,(HL)
OR A
JR Z,CMDK2
LD (DE),A
INC HL
INC DE
JR CMDK1
CMDK2: LD HL,SECBUF
LD BC,128
CALL SHOWBLK
JP MAIN
; M d t s: write the sector buffer to drive d, track t, sector s.
CMDM: CALL GETDTS
JP C,WHAT
CALL SETPAD
RST 8
DEFB 163
JP NZ,DISCERR
LD HL,WROTEM
JP DONE
; U d: read drive d's track 0 sector 0 and show its boot header.
CMDU: CALL GETNUM
JP C,WHAT
LD (SDRV),A
XOR A
LD (STRK),A
LD (SSEC),A
CALL READSEC
JP NZ,DISCERR
LD IX,SECBUF
LD HL,STARTM
CALL PRINT
LD L,(IX+0)
LD H,(IX+1)
CALL PHEXW
LD HL,ENDM
CALL PRINT
LD L,(IX+2)
LD H,(IX+3)
CALL PHEXW
LD HL,JUMPM
CALL PRINT
LD L,(IX+4)
LD H,(IX+5)
CALL PHEXW
LD HL,SIDEM
CALL PRINT
LD A,(IX+6)
CALL PHEX
JP CRMAIN
; B: make the disc in drive 1 start DISKMON. A header goes in the 7
; bytes before 0100h - start 00F9h, end LAST, jump 0100h, side 0 - and
; from 00F9h on, as many sectors as that takes are written to track 0.
CMDB: LD HL,00F9H
LD (HL),0F9H ; start: 00F9h
INC HL
LD (HL),00H
INC HL
LD DE,LAST
LD (HL),E ; end: LAST
INC HL
LD (HL),D
INC HL
LD (HL),00H ; jump: 0100h
INC HL
LD (HL),01H
INC HL
LD (HL),0 ; side: 0
LD A,1
LD (0FB50H),A
XOR A
LD (0FB51H),A
LD HL,00F9H
LD B,(LAST-00F9H)/512+1 ; sectors from 00F9h to LAST
LD C,0
CMDB1: LD A,C
LD (0FB52H),A
LD (0FB53H),HL
PUSH BC
PUSH HL
RST 8
DEFB 163
POP HL
POP BC
JP NZ,DISCERR
INC H
INC H
INC C
DJNZ CMDB1
LD L,(LAST-00F9H)/512+1
LD H,0
CALL PDEC
LD HL,BOOTM
JP DONE
; J d name n: record n of a file, found by hand - Blackwater's way of
; reading its data, with no DOS.
CMDJ: CALL FINDSET
CALL GETNUM
JP C,WHAT
LD (RECNO),HL
ADD HL,HL ; extent = record / 128
LD A,H
LD (EXTENT),A
CALL FINDEXT
LD HL,NOEXTM
JP NZ,DONE
LD A,(RECNO)
AND 7FH ; record within the extent
CP (IX+15)
LD HL,NORECM
JP NC,DONE
LD C,A
RRCA ; block index = (record mod 128) / 16
RRCA
RRCA
RRCA
AND 07H
ADD A,A
ADD A,16
LD E,A
LD D,0
PUSH IX
POP HL
ADD HL,DE
LD E,(HL)
INC HL
LD D,(HL)
LD A,C ; sector within the block = (record mod 16) / 4
RRCA
RRCA
AND 03H
PUSH BC
LD C,A
CALL BLKSEC
CALL READSEC
POP BC
JP NZ,DISCERR
LD A,C ; place in the sector = (record mod 4) x 128
AND 03H
LD H,A
LD L,0
SRL H
RR L
LD DE,SECBUF
ADD HL,DE
LD BC,128
CALL SHOWBLK
JP MAIN
; ------------------------------------------------- the controller itself
; G d t: move drive d's head to track t yourself: Restore, then Seek.
CMDG: CALL GETNUM
JP C,WHAT
LD (SDRV),A
CALL GETNUM
JP C,WHAT
LD (STRK),A
CALL FDCSEL
CALL FDCHOME
PUSH AF
CALL FDCSEEK
LD B,A
IN A,(19H) ; the track register
LD C,A
EI
POP AF
PUSH BC
PUSH AF
LD HL,RESTM
CALL PRINT ; PRINT leaves A = 0, so keep the status
POP AF
CALL PHEX
POP BC
PUSH BC
LD HL,SEEKM
CALL PRINT
LD A,B
CALL PHEX
LD HL,TRKM
CALL PRINT
POP BC
LD L,C
LD H,0
CALL PDEC
CALL MOSTRK ; tell the MOS where the head is now
LD A,(STRK)
LD (HL),A
JP CRMAIN
; FDCSEL: interrupts off; select drive SDRV (port 23h: 1 drive 0, 2 drive 1).
FDCSEL: DI
LD A,(SDRV)
LD B,A
INC B
LD A,1
JR FS2
FS1: ADD A,A
FS2: DJNZ FS1
OUT (23H),A
RET
; FDCHOME: Restore - head to track 0. A = the status after.
FDCHOME: LD A,(0FBB0H) ; the MOS's step rate
OR 00H
JR FDCCMD
; FDCSEEK: Seek to track STRK. A = the status after.
FDCSEEK: LD A,(STRK)
OUT (1BH),A ; the track to go to, in the data register
LD A,(0FBB0H)
OR 10H
; FDCCMD: give the controller command A, and wait until it has done it.
FDCCMD: OUT (18H),A
CALL BUSYON
; FDCWAIT: wait until the controller is not busy. A = its status.
FDCWAIT: IN A,(18H)
BIT 0,A ; bit 0: busy
JR NZ,FDCWAIT
RET
; BUSYON: wait (a short while at most) for the controller to say it is
; busy - it takes a moment to start a command, as the MOS knows.
BUSYON: PUSH BC
LD B,0
BO1: IN A,(18H)
BIT 0,A
JR NZ,BO2
DJNZ BO1
BO2: POP BC
RET
; MOSTRK: HL -> the MOS's record of where drive SDRV's head is (FB58h+d).
MOSTRK: LD HL,0FB58H
LD A,(SDRV)
LD E,A
LD D,0
ADD HL,DE
RET
; PUTBACK: seek back to the track the MOS thinks the head is on.
PUTBACK: CALL MOSTRK
LD A,(HL)
LD (STRK),A
CALL FDCSEEK
EI
RET
; I d t: the IDs on drive d's track t, in the order they pass the head,
; with Read Address - twenty of them, so you see the round twice.
CMDI: CALL GETNUM
JP C,WHAT
LD (SDRV),A
CALL GETNUM
JP C,WHAT
LD (STRK),A
CALL FDCSEL
CALL FDCHOME
CALL FDCSEEK
LD HL,RECBUF
LD B,20
CMDI1: PUSH BC
LD A,0C0H ; Read Address: 6 bytes from the next ID
OUT (18H),A
CALL BUSYON
LD DE,RECBUF+120 ; the 6 bytes land here
LD B,6
CMDI2: IN A,(18H)
BIT 1,A ; bit 1: a byte is waiting
JR NZ,CMDI3
BIT 0,A
JR NZ,CMDI2
JR CMDI4
CMDI3: IN A,(1BH)
LD (DE),A
INC DE
DJNZ CMDI2
CMDI4: CALL FDCWAIT
LD A,(RECBUF+122) ; the third byte is the sector ID
LD (HL),A
INC HL
POP BC
DJNZ CMDI1
CALL PUTBACK
LD HL,IDSM
CALL PRINT
LD HL,RECBUF ; as characters...
LD B,20
CMDI5: LD A,(HL)
CALL PCHAR
INC HL
DJNZ CMDI5
CALL NEWLINE
LD HL,RECBUF ; ...and in hex
LD BC,20
CALL SHOWBLK
JP MAIN
; H d t s: read a sector through the controller's ports, byte by byte.
CMDH: CALL GETDTS
JP C,WHAT
CALL FDCSEL
CALL FDCHOME
CALL FDCSEEK
LD A,(SSEC)
OUT (1AH),A ; the ID to look for
LD HL,SECBUF
LD DE,0
LD A,80H ; Read Sector
OUT (18H),A
CALL BUSYON
CMDH1: IN A,(18H)
BIT 1,A
JR NZ,CMDH2
BIT 0,A
JR NZ,CMDH1
JR CMDH3
CMDH2: IN A,(1BH)
LD (HL),A
INC HL
INC DE
JR CMDH1
CMDH3: LD (COUNT),DE
PUSH AF
CALL PUTBACK
LD HL,STATM
CALL PRINT
POP AF
CALL PHEX
LD HL,BYTESM
CALL PRINT
LD HL,(COUNT)
CALL PDEC
CALL NEWLINE
LD HL,SECBUF
LD BC,512
CALL SHOWBLK
JP MAIN
; ------------------------------------------------------ the command line
; GETLINE: read keys into LINE until ENTER, echoing them.
GETLINE: LD HL,LINE
LD (LPTR),HL
LD B,0
GL1: PUSH HL
PUSH BC
RST 8
DEFB 156 ; wait for a key
POP BC
POP HL
CP 13
JR Z,GL2
CP ' '
JR C,GL1 ; ignore other control keys
LD C,A
LD A,B
CP 60
JR NC,GL1 ; the line is full
LD A,C
LD (HL),A
INC HL
INC B
CALL PUTC
JR GL1
GL2: LD (HL),0
RET
; SKIPSP: step LPTR past spaces. HL = LPTR, A = the character there.
SKIPSP: LD HL,(LPTR)
SK1: LD A,(HL)
CP ' '
JR NZ,SK2
INC HL
JR SK1
SK2: LD (LPTR),HL
RET
; GETNUM: a decimal number from the line into HL (and A = L).
; Carry set if there was none.
GETNUM: CALL SKIPSP
CALL ISDIG
RET C
LD HL,0
GN1: PUSH HL
LD HL,(LPTR)
LD A,(HL)
CALL ISDIG
JR C,GN2
INC HL
LD (LPTR),HL
POP HL
SUB '0'
LD D,H ; HL = HL x 10 + digit
LD E,L
ADD HL,HL
ADD HL,HL
ADD HL,DE
ADD HL,HL
LD E,A
LD D,0
ADD HL,DE
JR GN1
GN2: POP HL
LD A,L
OR A ; no carry
RET
; ISDIG: carry clear if A is '0'-'9'.
ISDIG: CP '0'
RET C
CP '9'+1
CCF
RET
; GETNAME: a file name from the line - [d:]NAME[.EXT] - into the FCB at
; DE: drive byte (0 = current, d+1 if given), name and extension padded
; with spaces, the rest zero. Carry set if there was no name.
GETNAME: PUSH DE
LD H,D
LD L,E
LD (HL),0
INC HL
LD B,11
GNM1: LD (HL),' '
INC HL
DJNZ GNM1
LD B,24
GNM2: LD (HL),0
INC HL
DJNZ GNM2
CALL SKIPSP
POP DE
OR A
SCF
RET Z
INC HL ; "d:" in front?
LD A,(HL)
DEC HL
CP ':'
JR NZ,GNM3
LD A,(HL)
SUB '0'-1
LD (DE),A
INC HL
INC HL
GNM3: INC DE
LD B,8
CALL NAMEPART
LD A,(HL)
CP '.'
JR NZ,GNM4
INC HL
GNM4: LD B,3
CALL NAMEPART
LD (LPTR),HL
OR A
RET
; NAMEPART: up to B characters from HL to DE, stopping at '.', ' ' or the
; end; DE moves on B places whatever; extra characters are skipped.
NAMEPART: LD A,(HL)
OR A
JR Z,NP2
CP ' '
JR Z,NP2
CP '.'
JR Z,NP2
LD (DE),A
INC HL
INC DE
DJNZ NAMEPART
NP1: LD A,(HL) ; skip what does not fit
OR A
RET Z
CP ' '
RET Z
CP '.'
RET Z
INC HL
JR NP1
NP2: INC DE
DJNZ NP2
RET
; --------------------------------------------------------------- output
; PRINT: print the zero-terminated text at HL.
PRINT: LD A,(HL)
OR A
RET Z
CALL PUTC
INC HL
JR PRINT
; PUTC: print the character in A, keeping BC, DE and HL.
PUTC: PUSH BC
PUSH DE
PUSH HL
RST 8
DEFB 158
POP HL
POP DE
POP BC
RET
; NEWLINE: carriage return, then line feed.
NEWLINE: LD A,13
CALL PUTC
LD A,10
JP PUTC
; PHEX: print A as two hex digits.
PHEX: PUSH AF
RRCA
RRCA
RRCA
RRCA
CALL DIGIT
POP AF
DIGIT: AND 0FH
ADD A,'0'
CP '9'+1
JR C,DIG1
ADD A,7
DIG1: JP PUTC
; PHEXW: print HL as four hex digits.
PHEXW: LD A,H
CALL PHEX
LD A,L
JP PHEX
; PCHAR: print A if it is a printable character, otherwise '.'.
PCHAR: CP ' '
JR C,PC1
CP 7FH
JP C,PUTC
PC1: LD A,'.'
JP PUTC
; SHOWBLK: show BC bytes from HL, 8 to a row: offset, hex, characters.
; After every 128 bytes, if there is more, wait for a key.
SHOWBLK: LD DE,0 ; DE = the offset shown
SB1: LD A,B
OR C
RET Z
LD A,E
AND 7FH
JR NZ,SB2
LD A,D ; a new 128 bytes: pause, unless the first
OR E
JR Z,SB2
PUSH HL
LD HL,KEYM
CALL PRINT
RST 8
DEFB 156
CALL NEWLINE
POP HL
SB2: LD A,B ; this row: 8 bytes, or what is left
OR A
LD A,8
JR NZ,SB3
LD A,C
CP 8
JR C,SB3
LD A,8
SB3: LD (ROWN),A
PUSH HL
EX DE,HL
CALL PHEXW
EX DE,HL
LD A,' '
CALL PUTC
POP HL
PUSH BC
PUSH HL
LD A,(ROWN)
LD B,A
SB4: LD A,(HL)
CALL PHEX
LD A,' '
CALL PUTC
INC HL
DJNZ SB4
LD A,(ROWN) ; a short row: spaces to line up
SUB 8
NEG
JR Z,SB6
LD B,A
SB5: LD A,' '
CALL PUTC
CALL PUTC
CALL PUTC
DJNZ SB5
SB6: POP HL
LD A,(ROWN)
LD B,A
SB7: LD A,(HL)
CALL PCHAR
INC HL
DJNZ SB7
CALL NEWLINE
POP BC
PUSH HL ; the offset moves on 8
LD HL,8
ADD HL,DE
EX DE,HL
LD A,(ROWN) ; BC = BC - this row
LD L,A
LD H,0
PUSH DE
EX DE,HL
LD H,B
LD L,C
OR A
SBC HL,DE
LD B,H
LD C,L
POP DE
POP HL
JP SB1
; DIV10: HL = HL / 10, A = the remainder.
DIV10: LD B,16
XOR A
DV1: ADD HL,HL
RLA
CP 10
JR C,DV2
SUB 10
INC L
DV2: DJNZ DV1
RET
; PDEC: print HL in decimal.
PDEC: CALL DIV10
PUSH AF
LD A,H
OR L
CALL NZ,PDEC
POP AF
ADD A,'0'
JP PUTC
; TYPEOUT: print BC bytes from HL as text, stopping at 1Ah (carry set).
TYPEOUT: LD A,(HL)
CP 1AH
SCF
RET Z
CALL PUTC
INC HL
DEC BC
LD A,B
OR C
JR NZ,TYPEOUT
RET ; carry clear: no 1Ah yet
; ----------------------------------------------------------------- data
TITLE: DEFB 'DISKMON',13,10,0
PROMPT: DEFB '> ',0
WHATM: DEFB '?',13,10,0
KEYM: DEFB ' (KEY)',0
ROWN: DEFB 0
OLDSP: DEFW 0
LPTR: DEFW 0
FCB: DEFS 36
OPENM: DEFB 'OPEN: ',0
NOTFM: DEFB 'NOT FOUND',13,10,0
COUNT: DEFW 0
RECSM: DEFB ' RECORDS',13,10,0
AM: DEFB 'A=',0
NOMAKEM: DEFB 'CANNOT MAKE IT',13,10,0
WROTEM: DEFB 'WRITTEN',13,10,0
FCB2: DEFS 36
ERASEM: DEFB 'ERASED',13,10,0
RENM: DEFB 'RENAMED',13,10,0
NORECM: DEFB 'NO SUCH RECORD',13,10,0
NOEXTM: DEFB 'NO SUCH EXTENT',13,10,0
SDRV: DEFB 0
STRK: DEFB 0
SSEC: DEFB 0
DERRM: DEFB 'DISC ERROR ',0
NOSECM: DEFB ': NO SECTOR',13,10,0
BADM: DEFB ': BAD DATA',13,10,0
EXTM: DEFB ' EXTENT ',0
RECM: DEFB ' RECORDS ',0
EXTENT: DEFB 0
RLEFT: DEFB 0
STARTM: DEFB 'START ',0
ENDM: DEFB ' END ',0
JUMPM: DEFB ' JUMP ',0
SIDEM: DEFB ' SIDE ',0
BOOTM: DEFB ' SECTORS WRITTEN TO TRACK 0',13,10,0
HASDOS: DEFB 0
NODOSM: DEFB 'NO DOS: SECTORS ONLY',13,10,0
NEEDM: DEFB 'NEEDS THE DOS',13,10,0
STOPM: DEFB 'STOPPED',13,10,0
RECNO: DEFW 0
RESTM: DEFB 'RESTORE ',0
SEEKM: DEFB ' SEEK ',0
TRKM: DEFB ' TRACK ',0
TRIESM: DEFB 'TRIES ',0
IDSM: DEFB 'IDS: ',0
STATM: DEFB 'STATUS ',0
BYTESM: DEFB ' BYTES ',0
LAST: DEFB 0 ; the last byte the boot loads
This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.