home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
simtel
/
sigm
/
vols000
/
vol017
/
21bios.asm
< prev
next >
Wrap
Assembly Source File
|
1984-04-29
|
48KB
|
1,947 lines
TITLE 'CP/M BASIC INPUT/OUTPUT ROUTINES'
; CP/M BASIC INPUT/OUTPUT OPERATING SYSTEM (BIOS)
; TARBELL ELECTRONICS
; 2.1 VERSION OF 1-9-80
; CHANGE SIGN-ON DATE FOR CP/M 2.1
;
; UPDATED BY:
; ROBERT M. WHITE
; H & W COMPUTER SYSTEMS, INC.
; 8530 STONEHAVEN
; BOISE, ID 83704
;
;
; THIS MODULE CONTAINS ALL THE INPUT/OUTPUT
; ROUTINES FOR THE CP/M SYSTEM, INCLUDING
; THE DISK ROUTINES. It has been designed
; to provide a full implementation for a
; Tarbell controller and console configura-
; tion. The disk drivers fully support
; various sector sizes and densities as
; documented later. The I/O drivers fully
; support the IOBYTE as defined in the
; CP/M Alteration Manual. Note this is an
; oversized BIOS and requires that the CCP
; be defined as a file on the default drive.
; Thus only the BDOS and BIOS are on the
; system tracks allowing a BIOS of 2.75k
; when both tracks are single density.
; Currently, a total of 4k is being allocated
; to the BIOS. Therefore, the max CP/M
; memory size is 61k. To calculate this,
; do as follows:
; Max memory size+1 (64k) =10000H
; 10000H-1000H = F000H (Bios Base)
; F000H-1600H = DA00H (CP/M Base)
; DA00H-3400H = A600H (CBASE)
; A600H/400H = 41
; 41+20 = 61 (Max CP/M Size)
;
; To SYSGEN, do the following:
; 1. Assemble this BIOS using MAC and
; creating the file, 21BIOS.HEX.
; 2. Assemble the special Boot creating
; the file, 21BOOT.HEX.
; 3. Create a CCP file on the
; new default disk as follows:
; DDT CPMxx.COM
; -M980,1180,100
; -^C
; SAVE 8 CCP.COM
; 4. Put BDOS, BOOT & BIOS on the
; new default disk as follows:
; DDT CPMxx.COM
; -M1180,1F80,980
; -I21BOOT.HEX
; -R900
; -I21BIOS.HEX
; -H1780,nnnn
; xxxx yyyy (Returned by DDT)
; -Ryyyy
; -^C
; SYSGEN
; (Answer as normal).
;
; Note -- A handy way of debugging this BIOS is
; to have an operating CP/M which is 16k larger.
; Boot this bios. To capture data areas, simply
; re-boot the other and look at them with DDT.
; This technique was used extensively to get this
; BIOS operational.
;
;
; THIS SECTION DEFINES THE I/O PORTS AND
; STATUS BITS. BY SETTING THE PROPER VALUES
; FOR THE EQU STATEMENTS, THE I/O MAY BE
; AUTOMATICALLY RECONFIGURED TO FIT MOST
; SITUATIONS. THE TRUE AND FALSE ONES
; CONTROL CONDITIONAL ASSEMBLIES OF DIFFERENT
; SECTIONS OF I/O ROUTINES TO FIT DIFFERENT
; INTERFACE REQUIREMENTS.
MACLIB SPCLMAC
TRUE EQU 0FFFFH ;DEFINE VALUE OF TRUE.
FALSE EQU NOT TRUE ;DEFINE VALUE OF FALSE.
BC EQU B ;DOUBLE REGISTER EQUATES
DE EQU D
HL EQU H
;***************************************************
;*** THIS BEGINS THE AREA WHICH REQUIRES CHANGES ***
;*** FOR DIFFERENT CONSOLE I/O SYSTEMS ***
;***************************************************
MSIZE EQU 61 ;MEMORY SIZE IN KBYTES.
INTRP EQU FALSE ;TRUE IF INTERRUPTS ALLOWED.
DFTDSK EQU 0 ;DEFAULT DISK ON BOOT (0-3)
DFTUSR EQU 0 ;DEFAULT USER ON BOOT (0-15)
OLDTARB EQU FALSE ;TRUE IF OLD TARBELL CONTROLLER (1771)
TARBELL EQU TRUE ;TRUE IF NEW TARBELL CONTROLLER (1791)
DEBUG EQU FALSE ;TRUE FOR SPECIAL DEBUGGING MESSAGES
SPOOL EQU FALSE ;TRUE IF USING KLH SPOOLER.
NDISK EQU 3 ;DEFINES THE NUMBER DRIVES IN SYSTEM.
CSTAT EQU 16 ;CONSOLE STATUS PORT.
CCOM EQU 16 ;CONSOLE COMMAND PORT.
CDATA EQU 17 ;CONSOLE DATA PORT.
CONUL EQU FALSE ;CONSOLE NULLS?
CNULL EQU 0 ;CONSOLE NULL COUNT.
LSTAT EQU 18 ;LIST STATUS PORT.
LCOM EQU 18 ;LIST COMMAND PORT.
LDATA EQU 19 ;LIST DATA PORT.
LSTNUL EQU FALSE ;LIST DEVICE NULLS?
LNULL EQU 0 ;LIST NULL COUNT.
LSTPAG EQU FALSE ;LIST DEVICE PAGING?
LINCNT EQU 66 ;LINES PER PAGE.
STPRAT EQU 2 ;RATE 1=6MS, 2=10MS, 3=20MS.
DUAL EQU FALSE ;TRUE IF DUAL DRIVE.
PERSCI EQU FALSE ;TRUE IF FAST SEEK (PERSCI).
;*******************************************************
;*** THIS IS THE END OF THE AREA WHICH NORMALLY NEED ***
;*** BE CHANGED FOR MOST CONSOLE I/O SYSTEMS ***
;*******************************************************
DISK EQU 0F8H ;DISK BASE ADDRESS.
DCOM EQU DISK ;DISK COMMAND PORT.
DSTAT EQU DISK ;DISK STATUS PORT.
TRACK EQU DISK+1 ;DISK TRACK PORT.
SECTP EQU DISK+2 ;DISK SECTOR PORT.
DDATA EQU DISK+3 ;DISK DATA PORT.
WAIT EQU DISK+4 ;DISK WAIT PORT.
DCONT EQU DISK+4 ;DISK CONTROL PORT.
IF TARBELL
DMACHK EQU DISK+5 ;DMA CHECK PORT.
ENDIF
RTCNT EQU 10 ;RETRY COUNT.
CKBR EQU 00000001B ;KEYBOARD READY BIT.
CPTR EQU 00000010B ;PRINT READY BIT.
LKBR EQU 00000001B ;LISTER READY BIT.
LPTR EQU 00000010B ;LISTER READY BIT.
IOBYTE EQU 3 ;ADDRESS OF I/O BYTE.
CBASE EQU (MSIZE-20)*1024 ;BIAS FOR LARGER THAN 20K.
CPMB EQU CBASE+3400H ;START OF CPM 2.0
BDOS EQU CPMB+806H ;START OF BDOS 2.0.
BIOS EQU CPMB+1600H ;START OF CBIOS IO.
CDISK EQU 4 ;LOCATION 4 IS CURRENT DISK.
NSECTS EQU 44 ;NUMBER OF SECTORS IN IT.
ORG BIOS ;START OF CBIOS STRUCTURE.
;
; I/O JUMP VECTOR
; THIS IS WHERE CPM CALLS WHENEVER IT NEEDS
; TO DO ANY INPUT/OUTPUT OPERATION.
; USER PROGRAMS MAY USE THESE ENTRY POINTS
; ALSO, BUT NOTE THAT THE LOCATION OF THIS
; VECTOR CHANGES WITH THE MEMORY SIZE.
;
JMP BOOT ;FROM COLD START LOADER.
WBOOTE: JMP WBOOT ;FROM WARM BOOT.
JMP CONST ;CHECK CONSOLE KB STATUS.
JMP CONIN ;READ CONSOLE CHARACTER.
JMP CONOUT ;WRITE CONSOLE CHARACTER.
JMP LSTOUT ;WRITE LISTING CHAR.
JMP PUNOUT ;WRITE PUNCH CHAR.
JMP RDRIN ;READ READER CHAR.
JMP HOME ;MOVE DISK TO TRACK ZERO.
JMP SELDSK ;SELECT DISK DRIVE.
JMP SETTRK ;SEEK TO TRACK IN REG A.
JMP SETSEC ;SET SECTOR NUMBER.
JMP SETDMA ;SET DISK STARTING ADR.
JMP READ ;READ SELECTED SECTOR.
JMP WRITE ;WRITE SELECTED SECTOR.
JMP LSTST ;LIST STATUS CHECK.
JMP SECTRAN ;SECTOR TRANSLATE ROUTINE.
; THESE ENTRY POINTS ADDED BY TARBELL ELECTRONICS.
IF SPOOL ;IF USING KLH SPOOLER.
DB 0FFH ;FLAG FOR SPOOLER.
DW LTBSY ;LISTER STATUS LOCATION
DW LTBSY ;FOR SPOOLER - -
DW LTBSY ;I DON'T KNOW WHY IT'S
DW LTBSY ;HERE 4 TIMES EITHER.
ENDIF
; SPECIAL ENTRY POINTS FOR DIRECT DISK I/O
JMP Pselct ;Select the drive in (C).
JMP Phome ;Home current drive.
JMP Pseek ;Seek track in (C).
JMP Pread ;Read a sector in (C), dma in (HL)
JMP Pwrite ;Write a sector in (C), dma in (HL)
;*****************************************************
;* *
;* Sector Deblocking Algorithms for CP/M 2.0 *
;* *
;*****************************************************
;
; This section of programming provides the disk
;drivers for the BIOS. They are designed to handle
;many combinations of disk formats and sector sizes.
;Currently, the definitions of these combinations are
;defined as in DFOCO distributed by S. J. Singer via
;the CP/M User's Group. For further information, see
;the documentation for that fine program.
; The actual routines are divided into two sec-
;tions. The first performs logical blocking and de-
;blocking of the host physical sectors. The second
;section contains the actual physical routines to per-
;form the I/O functions necessary for proper operation
;of the disk drives. Currently, these routines assume
;a Tarbell Single or Double Density Controller. The
;original logical routines were supplied by Digital
;Research as a part of CP/M 2.0.
;
;*****************************************************
;* *
;* CP/M to host disk constants *
;* *
;*****************************************************
hstmax equ 1024 ;host max disk sector size
;
;*****************************************************
;* *
;* BDOS constants on entry to write *
;* *
;*****************************************************
wrall equ 0 ;write to allocated
wrdir equ 1 ;write to directory
wrual equ 2 ;write to unallocated
;/////////////////////////////////////////////////////
;/ Logical Disk I/O Driver Routines /
;/////////////////////////////////////////////////////
;*****************************************************
;* *
;* The BDOS entry points given below show the *
;* code which is relevant to deblocking only. *
;* *
;*****************************************************
;
; DISKDEF macro, or hand coded tables go here
;
; * * * Disk Parameter Header * * *
; In general, each disk has an associated Disk
;Parameter Header which both contains information about
;the disk drive and provides a scratchpad area for
;certain BDOS operations.
;
dphbase equ $ ;disk param block header
DPE0 equ $ ;** Disk A **
dw 00000H,00000H ;XLT adr, Scratch
dw 00000H,00000H ;Scratch, Scratch
dw dirbuf,00000H ;Dir Buf adr, DPB adr
dw CSV0,ALV0 ;CSV adr, ALV adr
DPE1 equ $ ;** Disk B **
dw 00000H,00000H ;XLT adr, Scratch
dw 00000H,00000H ;Scratch, Scratch
dw dirbuf,00000H ;Dir Buf adr, DPB adr
dw CSV1,ALV1 ;CSV adr, ALV adr
DPE2 equ $ ;** Disk C **
dw 00000H,00000H ;XLT adr, Scratch
dw 00000H,00000H ;Scratch, Scratch
dw dirbuf,00000H ;Dir Buf adr, DPB adr
dw CSV2,ALV2 ;CSV adr, ALV adr
DPE3 equ $ ;** Disk D **
dw 00000H,00000H ;XLT adr, Scratch
dw 00000H,00000H ;Scratch, Scratch
dw dirbuf,00000H ;Dir Buf adr, DPB adr
dw CSV3,ALV3 ;CSV adr, ALV adr
;
; * * * Disk Parameter Block * * *
; In general, each DPH, Disk Parameter Header,
;points to a particular DPB, Disk Parameter Block.
;The DPB contains information directly relating to
;the organition of data on the disk and its hardware
;characteristics.
;
; * * DPB Field Displacements * *
dpbspt equ 0 ;host CP/M sectors/track
dpbbsh equ 2 ;block shift factor
dpbblm equ 3 ;block shift mask
dpbexm equ 4 ;extent mask
dpbdsm equ 5 ;max block rcd #
dpbdrm equ 7 ;max dir mask
dpbal0 equ 9 ;dir allocation vector
dpbal1 equ 10 ;dir allocation vector
dpbcks equ 11 ;dir check value
dpboff equ 13 ;rsvd tracks offset
dpbdfc equ 15 ;disk format code
dpbssc equ 16 ;host sector size
dpbhbm equ 18 ;host sector mask
dpbhbs equ 19 ;host sector shift value
dpbxlt equ 20 ;xlt ptr
dpblen equ 22 ;DPB length
;
dpbbase equ $ ;Base of Disk Parameter Blocks
dpbs00 equ $ ;** Single Density, 128 byte Sectors **
DPB 020H,128,26,1024,243,64,64,2,xlts00
dpbs01 equ $ ;** Single Density, 256 byte Sectors **
DPB 021H,256,16,2048,150,64,64,2,0
dpbs02 equ $ ;** Single Density, 512 byte Sectors **
DPB 022H,512,8,2048,150,64,64,2,0
dpbs03 equ $ ;** Single Density, 1024 byte Sectors **
DPB 023H,1024,4,2048,150,64,64,2,0
dpbd00 equ $ ;** Double Density, 128 byte Sectors **
DPB 010H,128,51,2048,239,128,128,2,xltd00
dpbd01 equ $ ;** Double Density, 256 byte Sectors **
DPB 011H,256,26,2048,243,128,128,2,0
dpbd02 equ $ ;** Double Density, 512 byte Sectors **
DPB 012H,512,16,2048,300,128,128,2,0
dpbd03 equ $ ;** Double Density, 1024 byte Sectors **
DPB 013H,1024,8,2048,300,128,128,2,0
dpbnum equ ($-dpbbase)/dpblen ;# of entries in table
; * * * Sector Translation Table * * *
; This section contains the STT, Sector Translation
;Table, for particular disk configurations (I.E. DPB's).
;The table gives a logical to physical mapping of sector
;numbers. Thereby, allowing different mappings for per-
;formance betterment. Note that all entries must be rela-
;tive to zero, not one.
xltbase equ $ ;Base of Sector Translation Tables
xlts00 equ $ ;** Single density, 128 byte sectors,
; ; 26 Sec/Trk, Skew 6 **
db 0,6,12,18,24
db 4,10,16,22,2
db 8,14,20,1,7
db 13,19,25,5,11
db 17,23,3,9,15,21
xltd00 equ $ ;** Double density, 128 byte sectors,
; ; 51 Sec/Trk, Skew 18 **
db 0,17,34,9,26,43,1,18,35,10,27
db 44,2,19,36,11,28,45,3,20,37,12
db 29,46,4,21,38,13,30,47,5,22,39
db 14,31,48,6,23,40,15,32,49,7,24
db 41,16,33,50,8,25,42
;
;
;*****************************************************
;* *
;* BOOT - Cold Boot Routine. *
;* Executed whenever Reset is pressed. *
;* *
;*****************************************************
BOOT:
; Do initialization.
lxi sp,080H ;set stack ptr.
if INTRP
ei ;enable interrupts.
endif
; Initialize Mits 2SIO.
mvi a,3 ;Issue reset.
out ccom
out lcom
mvi a,015H ;Set up Ports.
out ccom
out lcom
in cdata ;clear console port.
; Save last six bytes of CCP.
lxi h,BDOS-6
lxi d,ccpsav
mvi c,6
mov a,m
stax d
inx h
inx d
dcr c
jnz $-5
; Zero defined Scratch area.
lxi b,ENDZ-STARTZ
lxi h,STARTZ
mvi m,0
inx h
dcx b
mov a,b
ora c
jnz $-6
; Set Low memory areas excluding jumps.
mvi a,095H ;IOBYTE := CON=CRT, LST=LPT, PUN=PTP,
sta IOBYTE ; RDR=PTR
mvi a,0 ;Default disk = A:
sta CDISK
; Issue opening message.
lxi h,smsg
call Pmsg
; Finish by warm booting.
jmp WBOOT
;*****************************************************
;* *
;* WBOOT - Warm Boot Routine. *
;* *
;*****************************************************
WBOOT:
; Do initialization.
lxi sp,080H ;set stack ptr.
if INTRP
di ;disable interrupts.
endif
; Set up jumps for CP/M in low memory.
mvi a,0C3H ;put (JMP) for WBOOT.
sta 0
lxi h,WBOOTE
shld 1
sta 5 ;put (JMP) for BDOS.
lxi h,BDOS
shld 6
; Issue loading CCP message.
if DEBUG
lxi h,lodccp
call pmsg
endif
; Zero Disk table.
mvi c,4*2
lxi h,dsktbl
mvi m,0
inx h
dcr c
jnz $-4
; Reset Deblock fields.
xra a
sta hstact ;host buffer inactive
sta unacnt ;clear unalloc count.
; Select and login default disk drive.
mvi c,DFTDSK ;do it.
call SELDSK
; Set default user to zero for now.
mvi e,0
mvi c,020H
call BDOS
; Reset disk system.
mvi c,00DH
call BDOS
; Select default drive.
mvi e,DFTDSK
mvi c,00EH
call BDOS
; Zero CCP's FCB.
lxi h,ccpfcb+12
mvi c,21
mvi m,0
inx h
dcr c
jnz $-4
; Open CCP's FCB.
lxi d,ccpfcb
mvi c,00FH
call BDOS
inr a ;Error?
jc Bterr ;...yes.
; Read in the CCP.
mvi c,16 ;set # of sectors in CCP.
lxi d,128 ;set sector size.
lxi h,CPMB ;set CCP base address.
call Ccpred ;Read a sector.
dad d ;bump ptr.
dcr c ;Decr count.
jnz $-5 ;loop till done.
; Restore CCP's last six bytes.
lxi h,ccpsav
lxi d,BDOS-6
mvi c,6
mov a,m
stax d
inx h
inx d
dcr c
jnz $-5
; Issue CCP loaded Message.
if DEBUG
lxi h,ccplod
call Pmsg
endif
; Do misc initialization.
lxi h,080H ;set default buffer in dma.
shld dmaadr
if INTRP
ei ;enable interrupts.
endif
; Set default drive and user and go to CCP.
lda CDISK ;get default drive.
mov c,a ;save it.
mvi a,DFTUSR ;get Default user (0-15).
ral ;Put it in high hex digit.
ral
ral
ral
add c ;add in default drive.
mov c,a ;set for CCP.
jmp CPMB ;go to CCP.
ccpfcb: db 0,'CCP ','COM',0,0,0,0
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
db 0
; * * Read a sector of CCP. * *
Ccpred:
; Do initialization.
push b ;save regs.
push d
push h
; Set DMA for read.
xchg
mvi c,01AH
call BDOS
; Issue the read.
lxi d,ccpfcb
mvi c,014H
call BDOS
ora a ;Error?
jnz Bterr ;...yes.
; Return to caller.
pop h ;restore regs.
pop d
pop b
ret
; * * Handle boot errors * *
Bterr:
; Tell operator.
lxi h,btmsg ;Issue Boot error msg.
call Pmsg
call CONIN ;Wait.
jmp WBOOT ;Try warm boot again.
;*****************************************************
;* *
;* SELDSK - Select a Disk. *
;* *
;*****************************************************
SELDSK:
; Validate the disk #.
lxi h,0 ;set for error.
mov a,c ;get the disk #.
cpi NDISK ;Undefined drive?
rnc ;...yes, return w/error.
mov a,c ;selected disk number
sta sekdsk ;seek disk number
; Get ptr to disk's DPH.
mov l,a ;disk number to HL
mvi h,0
rept 4 ;multiply by 16
dad h
endm
lxi d,dphbase ;base of parm block
dad d ;hl=.dph(curdsk)
shld sekdph ;save it.
; Log the disk if not already logged.
mov a,c ;point to disk table entry.
call Dskadr
mov a,m ;get flag byte.
ora a ;Already logged?
jm $+6 ;...yes.
call Logdsk ;...no, log it in.
; now get address of dpb.
lhld sekdph ;hl = .dph(curdsk)
lxi d,10 ;hl = .dphdpb(curdsk)
dad d
mov e,m ;hl = .dpb(curdsk)
inx h
mov d,m
xchg
shld sekdpb ;save it.
; return to caller.
lhld sekdph
ret
;*****************************************************
;* *
;* Logdsk - Login disk in (C). *
;* *
;*****************************************************
Logdsk:
; Get the format code from sector 1 track 0.
call Pselct ;Physically select the drive.
call Phome ;Home the head.
mvi c,0 ;Seek track 0 setting density.
call Pseek
mvi c,1 ;Read in first Sector.
lxi h,dirbuf
call Pread
lda dirbuf+07FH ;Get the format code.
sta dskdfc ;save it.
; Log the disk's DPH.
lhld sekdph
call Logdph
; Log it into the disk table.
lda sekdsk ;point to disk table entry.
call Dskadr
lda dskdfc ;get the density code.
ani 010H
rrc ;put it in low order byte.
rrc
rrc
rrc
ori 080H ;add in logged bit.
mov m,a ;put it in table flag byte.
; return to caller.
ret
;*****************************************************
;* *
;* Logdph - Login disk parameter header. *
;* *
;*****************************************************
Logdph:
; Get the right DPB.
xchg ;de = .dph
lda dskdfc ;get format code for search.
call Srcdpb ;Search the DPB table.
; Put the XLT address in the DPH.
push h ;save DPB ptr.
rxdld b,<>,dpbxlt ;Get XLT address.
xchg ;put it in DPH.
mov m,c
inx h
mov m,b
; Put DPB address in DPH.
lxi d,9 ;point to dphdpb.
dad d
pop d ;get DPB address.
mov m,e ;put it in DPH.
inx h
mov m,d
; return to caller.
ret
;*****************************************************
;* *
;* Srcdpb - Search DPB table on format code. *
;* *
;*****************************************************
Srcdpb:
; Do initialization.
push b ;save regs.
push d
mov b,a ;save format code.
mvi c,dpbnum ;set for # of entries.
lxi h,dpbbase ;point to DPB table.
lxi d,dpblen ;get entry length.
; Scan the table taking default if not
; found.
Srcdpl:
push h ;save current entry ptr.
rxld a,<>,dpbdfc ;get entry's format code.
pop h
cmp b ;Did we find it?
jz Srcdpf ;...yes, return w/it.
dad d ;bump ptr to next entry.
dcr c ;loop till no more entries.
jnz Srcdpl
lxi h,dpbs00 ;Default to SD/SS 128 byte.
; Return to caller w/entry ptr.
Srcdpf:
pop d ;restore regs.
pop b
ret
;*****************************************************
;* *
;* HOME - Home a particular disk. *
;* *
;*****************************************************
HOME:
;set track given by registers BC
lxi h,0
shld sektrk ;track to seek
ret
;*****************************************************
;* *
;* SETTRK - Set appropriate track. *
;* *
;*****************************************************
SETTRK:
;set track given by registers BC
mov h,b
mov l,c
shld sektrk ;track to seek
ret
;*****************************************************
;* *
;* SETSEC - Set appropriate sector. *
;* *
;*****************************************************
SETSEC:
;set sector given by register c
mov a,c
sta seksec ;sector to seek
ret
;*****************************************************
;* *
;* SETDMA - Set Data Memory Address. *
;* *
;*****************************************************
SETDMA:
;set dma address given by BC
mov h,b
mov l,c
shld dmaadr
ret
;*****************************************************
;* *
;* SECTRAN - Do Sector Translation. *
;* *
;*****************************************************
SECTRAN:
;translate sector number BC
mvi h,0 ;hl = physical sector
mov l,c
mov a,d ;if not using xlat tbl then
ora e ; return.
rz
xchg ;hl = .xlt
dad b ;hl = .xlt(sector)
mov l,m ;hl = xlt'd sector
mvi h,0
ret
;*****************************************************
;* *
;* The READ entry point takes the place of *
;* the previous BIOS defintion for READ. *
;* *
;*****************************************************
READ:
;read the selected CP/M sector
xra a ;accum = 00
sta unacnt ;unacnt= 00
mvi a,1
sta readop ;read operation
sta rsflag ;must read data
mvi a,wrual
sta wrtype ;treat as unalloc
jmp rwoper ;to perform the read
;*****************************************************
;* *
;* The WRITE entry point takes the place of *
;* the previous BIOS defintion for WRITE. *
;* *
;*****************************************************
WRITE:
;write the selected CP/M sector
xra a ;0 to accumulator
sta readop ;not a read operation
mov a,c ;write type in c
sta wrtype
cpi wrual ;write unallocated?
jnz chkuna ;check for unalloc
;
; write to unallocated, set parameters
rxld a,sekdpb,dpbblm ;a = dpbblm(sekdsk) + 1
inr a
sta unacnt
lda sekdsk ;disk to seek
sta unadsk ;unadsk = sekdsk
lhld sektrk
shld unatrk ;unatrk = sectrk
lda seksec
sta unasec ;unasec = seksec
;
chkuna:
;check for write to unallocated sector
lda unacnt ;any unalloc remain?
ora a
jz alloc ;skip if not
;
; more unallocated records remain
dcr a ;unacnt = unacnt-1
sta unacnt
lda sekdsk ;same disk?
lxi h,unadsk
cmp m ;sekdsk = unadsk?
jnz alloc ;skip if not
;
; disks are the same
lxi h,unatrk
call sektrkcmp ;sektrk = unatrk?
jnz alloc ;skip if not
;
; tracks are the same
lda seksec ;same sector?
lxi h,unasec
cmp m ;seksec = unasec?
jnz alloc ;skip if not
;
; match, move to next sector for future ref
inr m ;unasec = unasec+1
mov a,m ;end of track?
push h
rxad sekdpb,dpbspt
cmp m
pop h
jc noovf ;skip if no overflow
;
; overflow to next track
mvi m,0 ;unasec = 0
lhld unatrk
inx h
shld unatrk ;unatrk = unatrk+1
;
noovf:
;match found, mark as unnecessary read
xra a ;0 to accumulator
sta rsflag ;rsflag = 0
jmp rwoper ;to perform the write
;
alloc:
;not an unallocated record, requires pre-read
xra a ;0 to accum
sta unacnt ;unacnt = 0
inr a ;1 to accum
sta rsflag ;rsflag = 1
;*****************************************************
;* *
;* Common code for READ and WRITE follows *
;* *
;*****************************************************
rwoper:
; convert sector to host sector # by
; dividing it by the number of sectors
; per host sector.
xra a ;zero to accum
sta erflag ;no errors (yet)
lda seksec ;compute host sector
rxld b,sekdpb,dpbhbs ;b = dpbhbs(sekdpb)
dcr b ;b = 0?
inr b
jz rwope1 ;...yes, use as is.
ora a ;carry = 0
rar ;shift right
dcr b ;decr shift count.
jnz $-3 ;go shift it again.
rwope1:
sta sekhst ;host sector to seek
;
; active host sector?
lxi h,hstact ;host active flag
mov a,m
mvi m,1 ;always becomes 1
ora a ;was it already?
jz filhst ;fill host if not
;
; host buffer active, same as seek buffer?
lda sekdsk
lxi h,hstdsk ;same disk?
cmp m ;sekdsk = hstdsk?
jnz nomatch
;
; same disk, same track?
lxi h,hsttrk
call sektrkcmp ;sektrk = hsttrk?
jnz nomatch
;
; same disk, same track, same buffer?
lda sekhst
lxi h,hstsec ;sekhst = hstsec?
cmp m
jz match ;skip if match
;
nomatch:
;proper disk, but not correct sector
lda hstwrt ;host written?
ora a
cnz writehst ;clear host buff
;
filhst:
;may have to fill the host buffer
lda sekdsk
sta hstdsk
lhld sektrk
shld hsttrk
lda sekhst
sta hstsec
lhld sekdph
shld hstdph
lhld sekdpb
shld hstdpb
lda rsflag ;need to read?
ora a
cnz readhst ;yes, if 1
xra a ;0 to accum
sta hstwrt ;no pending write
;
match:
;copy data to or from buffer
lda seksec ;mask buffer number
rxad sekdpb,dpbhbm ;hl = .dpbhbm(sekdpb)
ana m ;least signif bits
mov l,a ;ready to shift
mvi h,0 ;double count
rept 7 ;shift left 7
dad h
endm
; hl has relative host buffer address
lxi d,hstbuf
dad d ;hl = host address
xchg ;now in DE
lhld dmaadr ;get/put CP/M data
mvi c,128 ;length of move
lda readop ;which way?
ora a
jnz rwmove ;skip if read
;
; write operation, mark and switch direction
mvi a,1
sta hstwrt ;hstwrt = 1
xchg ;source/dest swap
;
rwmove:
;C initially 128, DE is source, HL is dest
ldax d ;source character
inx d
mov m,a ;to dest
inx h
dcr c ;loop 128 times
jnz rwmove
;
; data has been moved to/from host buffer
lda wrtype ;write type
cpi wrdir ;to directory?
lda erflag ;in case of errors
rnz ;no further processing
;
; clear host buffer for directory write
ora a ;errors?
rnz ;skip if so
xra a ;0 to accum
sta hstwrt ;buffer written
call writehst
lda erflag
ret
;*****************************************************
;* *
;* Utility subroutine for 16-bit compare *
;* *
;*****************************************************
sektrkcmp:
;HL = .unatrk or .hsttrk, compare with sektrk
xchg
lxi h,sektrk
ldax d ;low byte compare
cmp m ;same?
rnz ;return if not
; low bytes equal, test high 1s
inx d
inx h
ldax d
cmp m ;sets flags
ret
;
;*****************************************************
;* *
;* WRITEHST performs the physical write to *
;* the host disk, READHST reads the physical *
;* disk. *
;* *
;*****************************************************
writehst:
;hstdsk = host disk #, hsttrk = host track #,
;hstsec = host sect #. write "hstsiz" bytes
;from hstbuf and return error flag in erflag.
;return erflag non-zero if error
; Select the drive.
lxi h,hstdsk ;c = disk #
mov c,m
call Pselct ;Select it.
; Set the head on the proper track.
lxi h,hsttrk ;c = track #
mov c,m
call Pseek ;do it.
sta erflag ;save error code.
rnz ;return if error.
; Write the sector.
lxi h,hstsec ;c = sector #
mov c,m
inr c ;make it relative to one.
lxi h,hstbuf ;hl = .buffer
call Pwrite ;do it.
sta erflag ;save error code.
ret
readhst:
;hstdsk = host disk #, hsttrk = host track #,
;hstsec = host sect #. read "hstsiz" bytes
;into hstbuf and return error flag in erflag.
; Select the drive.
lda hstdsk ;c = disk #
mov c,a
call Pselct ;Select it.
; Set the head on the proper track.
lxi h,hsttrk ;c = track #
mov c,m
call Pseek ;do it.
sta erflag ;save error code.
rnz ;return if error.
; Read the sector.
lxi h,hstsec ;c = sector #
mov c,m
inr c ;make it relative to one.
lxi h,hstbuf ;hl = .buffer
call Pread ;do it.
sta erflag ;save error code.
ret
;/////////////////////////////////////////////////////
;/ /
;/ Physical Disk I/O Driver Routines /
;/ /
;/////////////////////////////////////////////////////
;*****************************************************
;* *
;* Pselct - Physical Device Select *
;* *
;*****************************************************
Pselct:
; Trace activity.
if DEBUG
push h
lxi h,trcact
mvi m,1
pop h
endif
; Save current disk's Track #.
lda dskcur ;point to Disk table entry.
call Dskadr
inx h ;point to track save.
in TRACK ;get the track #.
mov m,a ;save it.
; Get the new track #.
mov a,c ;get new disk #.
sta dskcur ;make it the current one.
call Dskadr ;point to disk table entry.
inx h ;point to track save.
mov a,m ;get track #.
sta dsktrk ;save it.
out TRACK ;put it in controller.
; Set the new disk's latch.
mov a,c ;get the disk #.
if OLDTARB
cma ;invert it.
add a ;Put bits 1&2 in 4&5.
add a
add a
add a
ori 2 ;make latch command.
endif
if TARBELL
add a ;Put bits 1&2 in 4&5.
add a
add a
add a
endif
sta dsklth ;save new latch.
; Return to caller.
ret
;*****************************************************
;* *
;* Phome - Physical Device Home *
;* *
;*****************************************************
Phome:
; Trace activity.
if DEBUG
push h
lxi h,trcact
mvi m,2
pop h
endif
; Select the drive in single density.
lda dsklth ;Get current latch.
out DCONT ;Issue it to controller.
; Wait for device not to be busy.
in DSTAT ;get disk status.
rrc ;check busy bit.
jc $-3 ;...loop till not busy.
; Issue Restore Command.
mvi a,002H ;Restore cmd - no hdld, no verify
out DCOM ;Issue it.
in WAIT ;Wait for completion.
; Delay 200 msec.
mvi a,200
call delay
; Check the status for track zero.
in DSTAT
ani 4 ;Track zero?
jz Phome ;...no, try again.
; Reset track # in table.
lda dskcur ;point to table entry.
call Dskadr
inx h ;point to track #.
mvi m,0 ;reset it.
lxi h,dsktrk ;reset current track #.
mvi m,0
; Return to caller.
ret
;*****************************************************
;* *
;* Pseek - Physical Device Seek *
;* *
;*****************************************************
Pseek:
; Trace activity.
if DEBUG
push h
lxi h,trcact
mvi m,3
pop h
endif
; Select the drive and density.
mov a,c ;get track #.
sta dsktrk ;save it.
sta dsktrs ;...again.
ora a ;Track zero?
jz Pseek1 ;...yes, force single density.
lda dskcur ;point to disk table entry.
call Dskadr
mov a,m ;get flag byte.
ani 1 ;Double density?
jz $+5 ;...no.
mvi a,8 ;...yes, set it.
Pseek1: mov b,a ;save density.
lda dsklth ;get current latch.
ora b ;add in density.
out DCONT ;put it to controller.
; If we've changed drives since last seek,
; force a seek to the same track to unload
; the head. Thus insuring that the head
; load bit is properly set for this drive.
lhld dsklth ;get old and new latches.
mov a,l ;Are they the same?
cmp h
lda dsklth ;reset them no matter what.
sta dskolt
jnz Pseek2-2 ;...no, insure seek to same track.
; Check to see if current track is desired one.
in TRACK ;get current track.
cmp c ;Are they the same?
rz ;...yes, return.
; Issue the Seek command.
mvi b,RTCNT ;set retry count.
Pseek2: lda dsktrk ;get the desired track #.
out DDATA ;tell controller.
in DSTAT ;Wait till not busy.
rrc
jc $-3
mvi a,014H+STPRAT ;seek cmd w/verify.
out DCOM
in Wait ;Wait till complete.
in DSTAT ;get disk status.
if DEBUG
sta trcerr
endif
ani 091H ;Check for error.
rz ;...none, return.
; Handle errors.
dcr b ;Decr retry count.
jz Pseek3 ;...hard error.
call Phome ;home the device.
lda dsktrs ;restore original trk #.
sta dsktrk
jmp Pseek2 ;Try seeking again.
Pseek3:
call Recov ;Ask about recovery.
lda dsktrs ;restore original trk #.
sta dsktrk
jmp Pseek2-2 ;Try it again.
;*****************************************************
;* *
;* Pread - Physical Sector read. *
;* *
;*****************************************************
Pread:
; Trace activity.
if DEBUG
push h
lxi h,trcact
mvi m,4
pop h
endif
; Save input parameters.
shld dskdma ;dma address
lxi h,dsksec ;sector #
mov m,c
if INTRP
di ;disable interrupts.
endif
; Set retry count and interrupt controller.
Prdagn:
mvi a,RTCNT ;Set retry count.
Prdrty:
sta dskerr
mvi a,0D0H ;Issue soft interrupt.
out DCOM
xthl ;Do some delay.
xthl
; Set the Sector.
lda dsksec ;get it.
out SECTP
; Point to buffer.
lhld dskdma
; Issue Read command to controller.
in DSTAT ;get head load status.
ani 020H
xri 020H ;invert it.
rrc ;put it in proper bit.
rrc
rrc
if OLDTARB
ori 088H ;Read cmd w/o hdld
endif
if TARBELL
ori 080H ;Read cmd w/o hdld
endif
out DCOM ;Issue it.
; Read the data.
Prdlop:
in WAIT ;Wait for INTRQ.
ora a ;Is it there?
jp Prddon ;...yes, we're done.
in DDATA ;get a char.
mov m,a ;put it in buffer.
inx h ;bump ptr.
jmp Prdlop ;go get another.
; Analyze read status.
Prddon:
in DSTAT ;get it.
if DEBUG
sta trcerr
endif
if INTRP
ei ;enable interrupts.
endif
ani 09DH ;any errors?
rz ;...no, return.
call Erchk ;...yes, insure proper track.
lda dskerr ;get retry count.
dcr a ;Decr it.
jnz Prdrty ;...Try reading it again.
call Recov ;Give possible operater cancel.
jmp Prdagn ;Try reading again.
;*****************************************************
;* *
;* Pwrite - Physical Sector Write. *
;* *
;*****************************************************
Pwrite:
; Trace activity.
if DEBUG
push h
lxi h,trcact
mvi m,5
pop h
endif
; Save input parameters.
shld dskdma ;dma address
lxi h,dsksec ;sector #
mov m,c
if INTRP
di ;disable interrupts.
endif
; Set retry count and interrupt controller.
Pwragn:
mvi a,RTCNT ;Set retry count.
Pwrrty:
sta dskerr
mvi a,0D0H ;Issue soft interrupt.
out DCOM
xthl ;Do some delay.
xthl
; Set the Sector.
lda dsksec ;get it.
out SECTP
; Point to buffer.
lhld dskdma
; Issue Write command to controller.
in DSTAT ;get head load status.
ani 020H
xri 020H ;invert it.
rrc ;put it in proper bit.
rrc
rrc
if OLDTARB
ori 0A8H ;Write cmd w/o hdld
endif
if TARBELL
ori 0A0H ;Write cmd w/o hdld
endif
out DCOM ;Issue it.
; Write the data.
Pwrlop:
in WAIT ;Wait for INTRQ.
ora a ;Is it there?
jp Pwrdon ;...yes, we're done.
mov a,m ;get a char from the buffer.
out DDATA ;put it to disk.
inx h ;bump ptr.
jmp Pwrlop ;go get another.
; Analyze read status.
Pwrdon:
mvi a,1 ;delay some.
call Delay
in DSTAT ;get it.
if DEBUG
sta trcerr
endif
if INTRP
ei ;enable interrupts.
endif
ani 0FDH ;any errors?
rz ;...no, return.
call Erchk ;...yes, insure proper track.
lda dskerr ;get retry count.
dcr a ;Decr it.
jnz Pwrrty ;...Try reading it again.
call Recov ;Give possible operater cancel.
jmp Pwragn ;Try reading again.
;*****************************************************
;* *
;* Erchk - Insure proper seek on read/write *
;* *
;*****************************************************
Erchk:
; Return if not Rcd not found error.
push psw ;save error flags.
ani 010H ;Record not found?
jnz Erchk1 ;...yes, read address and seek.
pop psw ;...no, return.
ora a
ret
; Read the next address.
Erchk1:
mvi a,0C4H ;Read address w/15ms delay
out DCOM
in WAIT ;Wait for DRQ or INTRQ.
in DDATA ;Read track address.
push psw ;save it.
; Flush rest of address data.
Erchk2:
in Wait ;Wait for INTRQ.
ora a ;Read done?
jp Erchk3 ;...yes.
in DDATA ;...no, flush rest.
jmp Erchk2
; Check on Read Status.
Erchk3:
in DSTAT ;Get read Status.
ora a ;Sucessful?
jz Erchk4 ;...yes.
pop psw ;...no, clean up stack.
call Phome ; home head
jmp Erchk1 ; and try again.
; Put track # read in controller.
Erchk4:
pop psw ;restore track address.
out TRACK ;put it in controller.
; Seek to proper track.
lda dsktrk ;get the proper track #.
mov c,a
call Pseek ;do the seek.
pop psw ;restore error flag.
ret
;*****************************************************
;* *
;* Dskadr - Get disk table entry ptr. *
;* *
;*****************************************************
Dskadr:
push d ;save regs.
mov l,a ;hl = disp to entry.
mvi h,0
dad h
lxi d,dsktbl ;get base adr.
dad d ;add base to disp.
pop d
ret
;*****************************************************
;* *
;* Recov - Recover from read, seek and write *
;* errors. *
;* *
;*****************************************************
Recov:
lxi h,errmsg ;Issue error message
call Pmsg ; to console.
call conin ;get a response from operator.
cpi 003H ;Control C?
jz WBOOT ;...yes, abort.
ret
;*****************************************************
;* *
;* Pmsg - Print message on console. *
;* *
;*****************************************************
Pmsg:
mov a,m ;get next char of msg.
ora a ;if zero, eom.
rz
push b ;save bc.
mov c,a ;print char on console.
call CONOUT
pop b ;restore bc.
inx h ;bump msg ptr.
jmp Pmsg ;loop till eom.
;*****************************************************
;* *
;* Delay - Delay (A) msec. *
;* *
;*****************************************************
Delay:
push d ;save regs.
push h
Delay1: lxi d,1
lxi h,65335 ;Constant for 1 msec @ 4mhz
dad d
jnc $-1
dcr a ;Decr msec count.
jnz Delay1 ;...loop till done.
pop h ;restore regs.
pop d
ret
;*****************************************************
;* *
;* BDOS Messages *
;* *
;*****************************************************
btmsg: db '** Boot Error **',0
errmsg: db '** BDOS Error **',0
smsg: db 00DH,00AH,'Tarbell'
if OLDTARB
db '(1771) '
endif
if TARBELL
db '(1791) '
endif
db MSIZE/10+'0',MSIZE mod 10 + '0'
db 'K CP/M 2.1',0
if DEBUG
lodccp: db 00DH,00AH,'***Loading CCP---',0
ccplod: db 00DH,00AH,'***CCP is loaded!',0
endif
;****************************************************************************
;* L-O-G-I-C-A-L D-E-V-I-C-E D-R-I-V-E-R-S *
;* THE FOLLOWING SECTION CONTAINS THE LOGICAL DEVICE DRIVERS FOR *
;* EACH LOGICAL DEVICE IN THE SYSTEM. THESE DEVICES ARE DEFINED *
;* BY THE IOBYTE FUNCTION FOUND IN THE CP/M ALTERATION GUIDE. *
;****************************************************************************
;*************************** CON - SYSTEM CONSOLE **************************
CONST:
LDA IOBYTE ;GET IOBYTE.
CALL IOCAL ;EXIT TO SELECTED ROUTINE.
DW TTYST
DW CRTST
DW RDRST
DW DUMST
CONIN:
LDA IOBYTE ;GET IOBYTE.
CALL IOCAL ;EXIT TO SELECTED ROUTINE.
DW TTYIN
DW CRTIN
DW RDRIN
DW DUMIN
CONOUT:
LDA IOBYTE ;GET IOBYTE.
CALL IOCAL ;EXIT TO SELECTED ROUTINE.
DW TTYOUT
DW CRTOUT
DW PUNOUT
DW DUMOUT
;*************************** LST - OUTPUT LIST DEVICE **********************
LSTST:
LDA IOBYTE ;GET IOBYTE.
RLC ;SHIFT BITS.
RLC
CALL IOCAL ;EXIT TO SELECTED ROUTINE.
DW TTYST
DW CRTST
DW LPTST
DW DUMST
LSTOUT:
LDA IOBYTE ;GET IOBYTE.
RLC ;SHIFT BITS.
RLC
CALL IOCAL ;EXIT TO SELECTED ROUTINE.
DW TTYOUT
DW CRTOUT
DW LPTOUT
DW DUMOUT
;*************************** PUN - PAPER TAPE PUNCH ************************
PUNOUT:
LDA IOBYTE ;GET IOBYTE.
RRC ;SHIFT BITS.
RRC
RRC
RRC
CALL IOCAL ;EXIT TO SELECTED ROUTINE.
DW TTYOUT
DW PTPOUT
DW DUMOUT
DW DUMOUT
;*************************** RDR - PAPER TAPE READER ***********************
RDRST:
LDA IOBYTE ;GET IOBYTE.
RRC ;SHIFT BITS.
RRC
CALL IOCAL ;EXIT TO SELECTED ROUTINE.
DW TTYST
DW PTRST
DW DUMST
DW DUMST
RDRIN:
LDA IOBYTE ;GET IOBYTE.
RRC ;SHIFT BITS.
RRC
CALL IOCAL ;EXIT TO SELECTED ROUTINE.
DW TTYIN
DW PTRIN
DW DUMIN
DW DUMIN
;*************************** I/O DISPATCHER ********************************
IOCAL:
RLC ;SHIFT BITS.
ANI 006H ;LIMIT BITS.
XTHL ;SAVE HL, GET TABLE ADDRESS.
PUSH D ;SAVE DE.
MOV E,A ;GET SELECTION VALUE.
MVI D,0
DAD D ;GET TABLE ENTRY.
MOV A,M
INX H
MOV H,M
MOV L,A
POP D ;RESTORE DE.
XTHL ;RESTORE HL, SAVE RTN ADDRESS.
RET ;EXIT TO ROUTINE.
;****************************************************************************
;* P-H-Y-S-I-C-A-L D-E-V-I-C-E D-R-I-V-E-R-S *
;* THE FOLLOWING SECTION CONTAINS THE PHYSICAL DEVICE DRIVERS FOR *
;* EACH ACTUAL DEVICE IN THE SYSTEM. FOR EACH DEVICE, THERE MUST *
;* EXIST AT LEAST TWO OF THREE ROUTINES, A DEVICE STATUS ROUTINE *
;* AND A DEVICE INPUT OR OUTPUT ROUTINE. THE LOGICAL PORTION OF *
;* THE BIOS WILL ONLY CALL A STATUS, INPUT OR OUTPUT ROUTINE. *
;****************************************************************************
;*************************** DUM - DUMMY DEVICE ****************************
DUMST:
MVI A,0FFH ;INDICATE READY.
RET
DUMIN:
MVI A,01AH ;INDICATE <EOF>.
RET
DUMOUT:
RET
;*************************** CRT - HIGH SPEED CONSOLE **********************
CRTST:
IN CSTAT ;GET CONSOLE STATUS.
ANI CKBR ;IF NOT READY,
MVI A,0
RZ ; RETURN.
CMA ;RETURN 0FFH.
RET
CRTIN:
IN CSTAT ;GET CONSOLE STATUS.
ANI CKBR ;IF NOT READY,
JZ CRTIN ; LOOP.
IN CDATA ;READ THE CHAR.
ANI 07FH ;MAKE MOST SIG. BIT=0.
RET
CRTOUT:
IN CSTAT ;GET CONSOLE STATUS.
ANI CPTR ;IF NOT READY,
JZ CRTOUT ; LOOP.
MOV A,C ;GET THE CHAR.
OUT CDATA ;PRINT IT.
RET
;*************************** LPT - LINE PRINTER ****************************
;NOTE -- THIS SECTION GIVES AN LA-36 DECWRITER SOME INTELLIGENCE.
LPTST:
IN LSTAT ;GET PRINTER STATUS.
ANI LPTR ;IF NOT READY,
MVI A,0
RZ ; RETURN.
CMA ;RETURN 0FFH.
RET
LPTIN EQU DUMIN
LPTOUT:
MOV A,C ;GET CHAR.
CPI 007H ;<BELL>?
JZ LPTOUTC ;...YES.
CPI 008H ;<BACKSPACE>?
JZ LPTBS ;...YES.
CPI 009H ;<HORIZONTAL TAB>?
JZ LPTHT ;...YES.
CPI 00AH ;<LINE FEED>?
JZ LPTLF ;...YES.
CPI 00CH ;<FORM FEED>?
JZ LPTFF ;...YES.
CPI 00DH ;<CARRIAGE RETURN>?
JZ LPTCR ;...YES.
LPTCLI:
LDA CLCNT ;INCR COLUMN COUNT.
INR A
STA CLCNT
MOV B,A ;SAVE IT.
LPTOUTC:
IN LSTAT ;GET PRINTER STATUS.
ANI LPTR ;IF NOT READY,
JZ LPTOUTC ; LOOP.
MOV A,C ;GET THE CHAR.
OUT LDATA ;PRINT IT.
RET
LPTBS:
LDA CLCNT ;DECR COLUMN COUNT.
DCR A
RZ ;IF <0 THEN RETURN W/O PRINTING.
STA CLCNT
JMP LPTOUTC
LPTHT:
MVI C,' ' ;ISSUE <BLANK>.
CALL LPTCLI
MOV A,B ;GET COLUMN COUNT.
ANI 8-1 ;ROUND TO MOD 8.
JNZ LPTHT ;LOOP TO MOD 8.
RET
LPTLF:
LDA LFCNT ;INCR LF COUNT.
CPI 66 ;MAX VALUE?
JC $+4 ;...NO.
XRA A ;...YES, RESET IT.
INR A
STA LFCNT
JMP LPTOUTC
LPTFF:
LDA LFCNT ;TOP OF FORM?
CPI 1
RZ ;...YES.
MVI C,00AH ;ISSUE <LF>.
CALL LPTLF
JMP LPTFF
LPTCR:
XRA A ;ZERO COLUMN COUNT.
STA CLCNT
JMP LPTOUTC
CLCNT: DB 0 ;COLUMN COUNT
LFCNT: DB 1 ;LINE FEED COUNT
;************************ PTP - PAPER TAPE PUNCH ***************************
PTPST EQU DUMST
PTPIN EQU DUMIN
PTPOUT EQU DUMOUT
;************************ PTR - PAPER TAPE READER **************************
PTRST EQU DUMST
PTRIN EQU DUMIN
PTROUT EQU DUMOUT
;************************ TTY - SLOW SPEED CONSOLE *************************
TTYST:
IN LSTAT ;GET TTY STATUS.
ANI LKBR ;IF NOT READY,
MVI A,0
RZ ; RETURN.
CMA ;RETURN 0FFH.
RET
TTYIN:
IN LSTAT ;GET TTY STATUS.
ANI LKBR ;IF NOT READY,
JZ TTYIN ; LOOP.
IN LDATA ;READ THE CHAR.
ANI 07FH ;MAKE MOST SIG. BIT=0.
RET
TTYOUT EQU LPTOUT
;*****************************************************
;* *
;* Unitialized RAM data areas *
;* *
;*****************************************************
;
STARTZ: ;** Start of zeroed area **
sekdsk: ds 1 ;seek disk number
sektrk: ds 2 ;seek track number
seksec: ds 1 ;seek sector number
sekdph: ds 2 ;seek .dph(sekdsk)
sekdpb: ds 2 ;seek .dpb(sekdsk)
;
hstdsk: ds 1 ;host disk number
hsttrk: ds 2 ;host track number
hstsec: ds 1 ;host sector number
hstdph: ds 2 ;host .dph(sekdsk)
hstdpb: ds 2 ;host .dpb(sekdsk)
;
sekhst: ds 1 ;seek shr secshf
hstact: ds 1 ;host active flag
hstwrt: ds 1 ;host written flag
;
unacnt: ds 1 ;unalloc rec cnt
unadsk: ds 1 ;last unalloc disk
unatrk: ds 2 ;last unalloc track
unasec: ds 1 ;last unalloc sector
;
dskcur: ds 1 ;current disk #
dsktrk: ds 2 ;current track #
dsksec: ds 1 ;current sector #
dsktrs: ds 1 ;current trk # (saved)
dskdfc: ds 1 ;current format code
; note - the following two latches must be kept
; contiguous.
dsklth: ds 1 ;current disk latch
dskolt: ds 1 ;old disk latch
dskdma: ds 2 ;current dma address
dskerr: ds 1 ;current disk error count
dsktbl: ds 4*2 ;disk parameter table
; ; one entry for each
; ; physical drive
; db 0nnH ;flags
; 80 - 0=not logged, 1=disk logged
; 40 - 0=single density, 1=double
; db nn ;current track
ENDZ: ;** End of Zeroed Area **
if DEBUG
trcact: ds 1 ;last traced activity number
trcerr: ds 1 ;last traced controller error
endif
erflag: ds 1 ;error reporting
rsflag: ds 1 ;read sector flag
readop: ds 1 ;1 if read operation
wrtype: ds 1 ;write operation type
ccpsav: ds 6 ;CCP non-128-byte boundary data.
dmaadr: ds 2 ;last dma address
ALV0: ds 48
CSV0: ds 32
ALV1: ds 48
CSV1: ds 32
ALV2: ds 48
CSV2: ds 32
ALV3: ds 48
CSV3: ds 32
dirbuf: ds 128 ;directory buffer
hstbuf: ds hstmax ;host buffer
end