.NLIST
.INCLUDE /ASCII.MAC/
.INCLUDE /HWDF.MAC/
.INCLUDE /DSMAC.MAC/
.INCLUDE /MYMAC.MAC/
.LIST
MODULE NAME=
, VER=<001>, COMM=, TYPE=
.NLIST
.INCLUDE /DDPCM.MAC/
.LIST
.ASECT
.=^O<0>
V.0:
.WORD V.0+2
HALT
V.4:
.WORD V.4+2
HALT
V.10:
.WORD V.10+2
HALT
.=^O<60>
V.TKB:
.WORD VKB
.WORD PR4
.PSECT
PROCEDURE DIR
BEGIN
POP MRET
LET SP := #DIR
LET TKS := TKS SET.BY #^O<100> ; Enable interrupt from keyboard
LET PS := #^O<0> ; Lower priority
LET RFCNT := #^O<0> ; Reverse file count
LET BLKNUM := #^D<66> ; Read UFD block #0
CALL DTREAD ; Read
CALL CNFILS ; Count the number of files
IF RFCNT NE #0 THEN ; Reverse file count - if at least one file is found
CALL UBDIR ; UFD block directory listing
END
LET BLKNUM := #^D<67> ; Read UFD block #1
CALL DTREAD ; Read
CALL CNFILS ; Count the number of files
CALL UBDIR ; UFD block directory listing
LET RFCNT := RFCNT + # ; + Max files for two UFD block -> Free file descriptors count
JSR R5, DECASC
.WORD RFCNT ; Reverse file count
.WORD AFCNT ; Buffer
.WORD 2 ; Digits count (2 UFD blocks - 56 files max)
CALL MES ; Show free files count
.WORD AFFILS
JUMPTO @MRET
END DIR
;
; Count the number of files
;
PROCEDURE CNFILS
BEGIN
JSR R5, SAV05
LET R0 := #^O ; Buffer addres (skip link word)
LET R1 := #UFDFLC ; UFD block File count
REPEAT
IF (R0) NE #0 THEN ; If file record valid
LET RFCNT := RFCNT - #1
END
LET R0 := R0 + #EN.BBS ; Pointer to next file descriptor
LET R1 := R1 - #1 ; One file less
UNTIL RESULT IS EQ ; Until UFD block completed
CALL RST05
RETURN
END CNFILS
;
; UFD block directory listing
;
PROCEDURE UBDIR
BEGIN
JSR R5, SAV05
LET R0 := #^O
LET R1 := #UFDFLC ; UFD block File count
REPEAT
IF (R0) NE #0 THEN
LET FILNAM := (R0) ; EN.FIL
LET FILNAM+EN.NAM := EN.NAM(R0)
LET FILNAM+EN.TYP := EN.TYP(R0)
LET FILLEN := EN.LEN(R0)
LET FILDAT := EN.DAT(R0)
JSR R5, R50ASC
.WORD FILNAM
.WORD AFILNM
JSR R5, R50ASC
.WORD FILNAM+EN.NAM
.WORD ^O ; Skip first three chars
JSR R5, R50ASC
.WORD FILNAM+EN.TYP
.WORD ^O ; Skip file name chars, one space ana point
JSR R5, DECASC
.WORD FILLEN
.WORD AFLEN
.WORD 3
CALL DATASC ; DOS-11 File date to Ascii
CALL MES ; Show next file info
.WORD AFDESC
END
LET R0 := R0 + #EN.BBS ; Pointer to next file descriptor
LET R1 := R1 - #1 ; One file less
UNTIL RESULT IS EQ ; Until UFD block completed
CALL RST05
RETURN
END UBDIR
Stack R0 R1 R2 R3 R4 R5 PC PS
;
; Show Ascii string (with % as CRLF and @ as terminator char)
;
PROCEDURE MES
BEGIN
JSR R5, SAV05
LET R5 := SP.PC(SP) ; Argument pointer
LET R0 := (R5)+
LOOP
LET R1 :B= (R0)+ ; Next char
IFB #'@ EQ R1 THEN ; If terminator
LET SP.PC(SP) := R5
CALL RST05
RETURN
END
IFB #'% EQ R1 GOTO CRLF ; If CRLF special char
ENTRY CHOUT1
CALL CHROUT ; Out char to TV
END
END MES
;
; Out char to TV
;
PROCEDURE CHROUT
BEGIN
LET @#TPB :B= R1
REPEAT
UNTILB @#TPS MI #0
RETURN
END CHROUT
;
; CRLF for directory list
;
PROCEDURE CRLF
BEGIN
LET R1 :B= #CR
CALL CHROUT ; Out char to TV
LET R1 :B= #LF
GOTO CHOUT1 ; Out char to TV
END CRLF
PROCEDURE EXIT
BEGIN
CALL SHNLCH ; Show two chars on new line
JUMPTO @MRET
END EXIT
;
; Show two chars on new line
;
PROCEDURE SHNLCH
BEGIN
PUSH R2
LET R2 := #LF*^O<400>+CR
CALL SHO2CH ; Show two chars
POP R2
CALL SHO2CH ; Show two chars
RETURN
END SHNLCH
;
; Show two chars
;
PROCEDURE SHO2CH
BEGIN
LET @#TPB :B= R2
REPEAT
UNTILB @#TPS MI #0
SWAB R2
$GOTO SHOCHR ; Show char
END SHO2CH
;
; Show char
;
PROCEDURE SHOCHR
BEGIN
LET @#TPB :B= R2
REPEAT
UNTILB @#TPS MI #0
RETURN
END SHOCHR
PROCEDURE R50ASC
BEGIN
JSR R4, SAV04
LET R4 := @(R5)+
LET R3 := (R5)+
LET R1 := #2
PUSH #-1
REPEAT
PUSH R4
LET R4 := #0
;
; Divide by 50??
;
REPEAT
LET R0 := (SP)
LET R0 :B= R0 SET.BY (PC) ; 2 (010002)
LET R2 := R0 R.ROTATE 1 R.SHIFT 1
LET R0 := R0 - R2 OFF.BY #^O<37>
LET TOP := TOP - R0
LET R0 := R0 R.ROTATE 1 R.SHIFT 1
LET TOP := TOP - R0
LET R4 := R4 + R0
UNTIL (SP) LOS #^O<47>
LET R4 := R4 R.SHIFT 3
LET R1 := R1 - #1
UNTIL RESULT IS EQ
IFB R4 HI #^O<47> GOTO 10$
REPEAT
IFB R4 NE #0 THEN
IFB R4 EQ #^O<35> THEN
10$:
LET R2 := #"E6
JUMPTO EXIT
END
IFB R4 EQ #33 GOTO 30$
IF RESULT IS HI GOTO 20$
LET R4 := R4 + #^O<40>
END
LET R4 := R4 + #^O<16>
20$:
LET R4 := R4 + #^O<11>
30$:
LET R4 := R4 + #^O<11>
LET (R3)+ :B= R4
POP R4
UNTIL RESULT IS MI
CALL RST04
RTS R5
END R50ASC
PROCEDURE DECASC
BEGIN
JSR R4, SAV04
LET R0 := #DECBUF
LET R1 := @(R5)+ ; Num
LET OBUF := (R5)+ ; Buf
LET NDIG := (R5)+ ; Digit count
LET R2 := #DECTAB
LET DPCNT := #5
REPEAT
LET DECP := (R2)+
CALL N10DIG
LET DPCNT := DPCNT - #1
UNTIL RESULT IS EQ
LET R0 := R0 - NDIG
LET K02006 := R0
JSR R5, CPYBYT
K02006:
.WORD 0
OBUF:
.WORD 0
NDIG:
.WORD 0
CALL RST04
RTS R5
END DECASC
PROCEDURE N10DIG
BEGIN
LET NXTDIG := #0
LOOP
LET R1 := R1 - DECP
IF RESULT IS LO LEAVE LOOP
LET NXTDIG := NXTDIG + #1
END
LET R1 := R1 + DECP
LET NXTDIG := NXTDIG + #'0
LET (R0)+ :B= NXTDIG
RETURN
END N10DIG
DPCNT:
.WORD 0 ; Ten powers count
NXTDIG: ; Next digit
.WORD 0
DECP: ; Current ten power
.WORD 0
DECTAB: ; Ten powers
.WORD ^D<10000>
.WORD ^D<1000>
.WORD ^D<100>
.WORD ^D<10>
.WORD ^D<1>
DECBUF:
.ASCII | |
PROCEDURE CPYBYT
BEGIN
JSR R4, SAV04
LET R0 := (R5)+
LET R1 := (R5)+
LET R2 := (R5)+
REPEAT
LET (R1)+ :B= (R0)+
LET R2 := R2 - #1
UNTIL RESULT IS EQ
CALL RST04
RTS R5
END CPYBYT
;
; DOS-11 File date to Ascii
;
PROCEDURE DATASC
BEGIN
JSR R5, SAV05
LET R3 := #MONTHS ; <232><2>|DEC|<36>|NOV|...
LET R2 := #12
LET R4 := #AFDATE ; | - - @|
LET R5 := #^D<69>
LET R0 := FILDAT
REPEAT
LET R5 := R5 + #1
LET R0 := R0 - #^D<1000>
UNTIL RESULT IS LO
IF #3 OFF.IN R5 THEN
LET AFEB :B= AFEB + #1
LET R0 := R0 - #1
END
LET R1 := (R3)+
REPEAT
LET R0 := R0 + R1
IF RESULT IS GT GOTO 10$
LET R3 := R3 + #3
LET R1 :B= (R3)+
UNTIL RESULT IS EQ
LET R0 := #0
10$:
LET R1 := #^O<<'9+1>*400+<'0-1>>
REPEAT
LET R1 := R1 + #1
LET R0 := R0 - R2
UNTIL RESULT IS LO
IFB R1 GE #^O<'9+1>
LET R1 := R1 - R2
END
CALL SBYTE ; Save byte
SWAB R1
LET R1 := R1 + R0
CALL SBYTE ; Save byte
LET R0 := R5
IF RESULT IS EQ GOTO SETFEB ; Set february day count
LET R5 := #4000
20$:
LET R1 := #55
LOOP
CALL SBYTE ; Save byte
LET R5 := R5 L.SHIFT 1
IF RESULT IS CS GOTO 10$
IF RESULT IS MI GOTO 20$
LET R1 :B= (R3)+
END
END DATASC
;
; Save byte
;
PROCEDURE SBYTE
BEGIN
LET (R4)+ :B= R1
RETURN
END SBYTE
;
; Set february day count
;
PROCEDURE SETFEB
BEGIN
IFB #^D<28> NE AFEB THEN
DECB AFEB
END
CALL RST05
RETURN
END SETFEB
PROCEDURE VKB
BEGIN
LET INCHR := TKB
LET INCHR := INCHR OFF.BY #^C<^O<177>>
IF #3 NE INCHR THEN
RTI
END
JUMPTO @MRET
END VKB
INCHR:
.WORD 000000
PROCEDURE SAV05
BEGIN
JSR R4, SAV04
LET PC := R5
END SAV05
PROCEDURE SAV04
BEGIN
PUSH ; Save R3-R0
LET PC := R4 ; R4 is already saved
END SAV04
PROCEDURE RST04
BEGIN
POP ; Return address, restore R0-R3
RTS R4 ; Restore R4 and return
END RST04
PROCEDURE RST05
BEGIN
POP ; Return address, restore R0-R4
RTS R5 ; Restore R5 and return
END RST05
ISOPRD:
.BYTE 0
RSRCHC:
.BYTE 0
RREADC:
.BYTE 0
.EVEN
;
; Read block
; Input : PSPTOP - pointer to pointer to block number
; Output: PSPTOP - pointer to pointer to buf
;
PROCEDURE DTREAD
BEGIN
JSR R5, SAV05
RETRY:
LET R5 := #BUF ; Pointer to Block num
LET R1 := (R5) ; Block num
LET R4 := #0
LET (R5) := (R5) L.SHIFT 1 ; Block num * 2
IF RESULT IS CS THEN
LET R4 := NOT R4 ; Reverse move
CLC
END
LET (R5) := (R5) R.SHIFT 1 ; Block num
LET R3 := #CM.REV ; Reverse
LET @#TCBA := R5 ; Buffer address (and link word at readed block)
LET @#TCWC := #-400 ; One block
LET RSRCHC :B= #6 ; Initial retry count for search
LET RREADC :B= #3
LET ISOPRD :B= #0 ; Operation is block search
LET R0 := #TCRNU$!TCDO$ ; Read block number
REPEAT ; on error retry cycle
LOOP ; loop for search and read
LOOP ; loop for read
REPEAT ; loop for search and read
LOOP ; loop for +3 block on forward moving
REPEAT ; one time repeat on forward moving, many time repeat on reverse moving
LOOP ; loop for -3 block on reverse moving
REPEAT ; one time repeat on reading and reverse moving, many time repeat on forward moving
LET @#TCCM := R0 ; command
REPEAT ; wait for ready
UNTIL #TAERR$!TATRQ$ SET.IN @#TCCM
IFB ISOPRD NE #0 GOTO DTCERR ; If op is read - check on error and complete call, if success
; No read - block searching
IF @#TCCM MI #0 GOTO CHKEZ ; If TAERR$ - check End Zone and others error
IF @#TCDT EQ (R5) GOTO BPFND ; If desired block - possible found
IF RESULT IS GT GOTO POSAFT ; Current > desired
UNTIL R3 SET.IN @#TCCM ; Current < desired - repeat, if forward moving
LET @#TCDT := @#TCDT + #3 ; +3 sectors for change to forward
IF @#TCDT LOS (R5) GOTO FDIR ; If moved backward enough, change the direction to forward
END
;
; Current > desired - reverse direction after block number "desired+3"
;
POSAFT:
UNTIL R3 OFF.IN @#TCCM ; repeat, if reverse moving
LET @#TCDT := @#TCDT - #3 ; +3 sectors for change to reverse
IF (R5) LE @#TCDT GOTO RDIR ; If moved forward enough, change the direction to reverse
END
;
; Desired block found, checking move and read direction
;
BPFND:
IF R3 SET.IN @#TCCM GOTO BPFRVR ; If reverse move - check read on reverse op
UNTIL R4 EQ #0 ; Forward move, if reverse read - repeat search, else - go to read
;
; Desired block found and move and read match in direction - switch to read
;
BLKFND:
LET ISOPRD :B= NOT ISOPRD ; Set read as current op flag
LET R0 :B= #TCRDA$!TCDO$ ; Set read as current op
END
;
; Desired block found, reverse move. Is reverse read?
;
BPFRVR:
IF R4 NE #0 GOTO BLKFND ; If reverse read - block is founded - switch to read
; Else - reverse move, forward read - repeat search
END
CHKEZ:
IF @#TCST MI #0 GOTO INVDIR ; If TCEZ$ (End Zone of tape) - invert direction
RRERR: ; Repeat on read error
IF #TCPE$!TCMTE$!TCBME$!TCDME$ SET.IN @#TCST THEN ; Parity error, mark track error, block missed or data was missed
LET RREADC :B= RREADC - #1 ; Retry count for read
IF RESULT IS NE THEN ; Once more try
LET (R5) := R1
GOTO RETRY
END
LET R2 := #"E2 ; Read error
ELSE
LET R2 := #"E1 ; Block search error
END
DTERR: ; Exit with error
LET @#TCCM := @#TCCM OFF.BY #TCIE$!TCMSK$
JUMPTO EXIT
INVDIR: ; Invert direction
IF R3 SET.IN @#TCCM THEN
FDIR: ; Set forward direction
LET R0 := R0 OFF.BY R3
ELSE
RDIR: ; Set reverse direction
LET R0 := R0 SET.BY R3
END
LET RSRCHC :B= RSRCHC - #1 ; Retry count for search
UNTIL RESULT IS EQ
LET R2 := #"E3
GOTO DTERR ; Exit with error
DTCERR: ; Check on error and completed, if success
IF @#TCCM MI #0 GOTO RRERR ; If error (on read) - repeat
LET @#TCCM := @#TCCM OFF.BY #TCIE$!TCMSK$
CALL RST05
RETURN
END DTREAD
AFDESC:
.ASCII |%| ; CR LF
AFILNM: ; File name and extension
.ASCII | . |
AFLEN: ; File length
.ASCII | |
AFDATE:
.ASCII | - - @|
AFFILS:
.ASCII |%%FREE FILES: |
AFCNT:
.ASCII | @|
MONTHS:
.WORD ^D<666>
.ASCII |DEC|<^D<30>>|NOV|<^D<31>>|OCT|<^D<30>>|SEP|<^D<31>>|AUG|<^D<31>>|JUL|<^D<30>>
.ASCII |JUN|<^D<31>>|MAY|<^D<30>>|APR|<^D<31>>|MAR|
AFEB:
.ASCII <^D<28>>|FEB|
.ASCII <^D<31>>|JAN|<0>|XXX |
;
; Reverse file count
;
RFCNT:
.WORD 0
FILNAM:
.WORD 0, 0, 0
FILLEN:
.WORD 0
FILDAT:
.WORD 0
MRET: ; Monitor return address
.WORD 0
BUF:
BLKNUM:
.WORD 0
END DIR
.END DIR