home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
cpm
/
cbios
/
acibs1k.ark
/
ACIBS1K.ASM
next >
Wrap
Assembly Source File
|
1989-10-21
|
60KB
|
2,287 lines
PAGE 62
;P2BIOS.ASM aka ACIBS1K.ASM
;ALSPA COMPUTER, INC. Double Density Floppy Disk BIOS P2DOS/CPM2.2
;******************************************************
;EDIT HISTORY
; DATE: REL: MOD:
;01/11/82 - 02/01/82 1.8 ACIBS modified to 61K CPM, Blocking added
;02/01/82 - 02/02/82 Track mechanism fixed, side A:/B: code removed
;02/03/82 - 02/04/82 Diskswap fixed
;02/08/82 - 02/09/82 2.0 B: Logon fixed, sign-on 'glitch' fixed
;02/18/82 - 02/18/82 RCLOCK/WCLOCK timing fix, PIP/Density fixed
;02/25/82 2.1*SELDSK modified to delay disk change till R/W/SEEK
;03/02/82 2.2 Disk chg (dbl-sd PIP[V]) problem fixed
;03/05/82 D B: (rev A) problem fixed
;03/08/82 IBM format on B: option supported (rev xI)
;03/15/82 SYSFMT generated from IOBYTE, IOBYTE corrected
;03/16/82 - 03/25/82 2.3 Clock routines updated, IO routines re-done
;04/19/82 - 04/26/82 IOBYTE select, Coldboot in buffer, Autostart done.
;04/27/82 - 05/05/82 2.4 Add Motor on/off, User#/JumpTable saved in Wboot.
;05/07/82 2.5 System speed optimized.
;05/10/82 2.6 Wboot select error fixed.
;05/19/82 - 05/20/82 Select problem (when no Home after SELDSK) fixed.
;05/21/82 2.7*Select C:+ problem (drive# in Wboot) fixed.
;05/22/82 2.8*Tandon Motor-On speed mod.
;05/24/82 2.9 Motor-On mod improved (spindle-speed test added).
;08/23/82 - 08/25/82 3.0 1 Drive Side-select(B:dbl1/A:sngl0) bug fixed.
;10/27/82 - 11/02/82 Type-ahead buffer added (WordStar users rejoice).
;11/10/82 Density flag clear in HOME added (for JBS drives).
;11/10/82 - 11/11/82 Flush buffer on CONIN added.
;12/09/82 - 12/21/82 Autoswitch IOBYTE option added, Warmboot CCP only.
;12/21/82 - 01/17/83 3.1 Code for self-load of ACIDOS.COM file added.
;03/03/85 - 03/03/85 3.2%Added USER0 code
;09/18/87 3.3%Added USER0 warning (USER0 kills ZCPR3 & FCOPY)
;10/30/87 - 11/09/87 Added P2DOS support.
;11/10/87 - 11/12/87 made rev A code optional, to save a few bytes,
;11/15/87 Added 2-drive only flag and p2dos time function.
;11/17/87 Added clear of mem above BIOS on coldboot.
;11/21/87 Added ZCPR3 definitions.
;11/24/87 - 11/26/87 Added ZCPR3/P2DOS overlays and data areas.
;11/28/87 - 11/29/87 3.4%Added fix for motor-on problem.
;01/12/88 3.5%Upgraded for P2DOS v. 23
;01/27/89 3.6%Added parallel printer status
;09/19/89 - 09/20/89 3.7%Modified to NOT use DIRBUF for scratch area.
; possible improvement - flush on nnnn*CONST (if no char is input)??
; * Unreleased/Limited Release versions
; % Special version - Custom by W.O.S.
;******************************************************
MO EQU 09 ;LAST EDIT DATE
DA EQU 20
YR EQU 89
REVNO EQU 37 ;REVISION #
TRUE EQU 0FFFFH
FALSE EQU NOT TRUE
VER36 EQU FALSE ;Version3.6 code option (for restore after testing 3.7)
;************************************************************
;* USER-SELECTED ASSEMBLY-TIME OPTIONS *
;************************************************************
IBMB EQU FALSE ;Set to true if IBM disk compatibility is desired.
;This will cause the system to use 'diskette' density
;when reading Track 1 of disks B:,C:,... (i.e. not A:).
;ALSPA disks always use double-density
;on track 1 to hold the system, even if disk density
;is single-d. Since the system on B: is not likely
;to be read (except, maybe, by 'Disk Editor' utilities)
;This should not affect normal operation. If an IBM-CPM
;translation utility is used, this option MUST be
;selected.
LL EQU 0 ;DEFAULT PRINTER OPTION: (0,1,2,or 3)
;0=Parallel printer interface
;1=(console output)
;2=Serial interface, ETX/ACK protocol
;3=Serial interface, X-ON/X-OFF(or NO) protocol
DD EQU 2 ;# OF PHYSICAL FLOPPY DISK DRIVES: (1 or 2)
AA EQU 1 ;AUTOSWITCH OPTION: (0 OR 1)
;0=Autoswitch enabled
;1=Autoswitch disabled
;The Autoswitch option runs the Modem and Console ports
;in parallel, i.e. any character input from either
;port is accepted as console input, and is echoed to
;both Console and Modem output ports.
SS SET 0 ;AUTOSTART OPTION: (0 OR 1)
;0=Autostart enabled (both Cold/Warmboot)
;1=Autostart disabled (Coldboot only)
;The Autostart option allows the user to insert a
;command in the CCP to be executed upon either coldboot
;or warmboot. If the option is disabled, the command in
;the CCP buffer will be ignored on warmboot, but
;executed upon coldboot(power-on or reset).
;Autostart MUST be ENABLED for ZCPR3!
QSIZE EQU 25 ;Type-ahead buffer size (maximum: 255 characters)
TYPEAHEAD EQU TRUE ;TYPE-AHEAD Option = TRUE or FALSE
USER0 SET FALSE ;Add USER 0 = Public capability (patch CCP).
;USER0 MUST be FALSE for ZCPR3!
P2DOS EQU FALSE ;TRUE if this is a P2DOS BIOS, FALSE for CP/M.
ZCPR3 EQU TRUE ;TRUE if this BIOS is to be use with ZCPR3.
DEBUG EQU FALSE ;Add debugging code - watch ENDDISK parameter!
;G = GoCPM dnn = drive# tnn = track#
;snn = sector# r = read w = write
;R = real read W = real write H = real home
;* = warmboot xnn = xlat sector
NOREVA EQU TRUE ;If true, BIOS handles Alspa rev B boards only.
ONLY2 EQU TRUE ;TRUE for 2-drive only version (saves code space).
;*******************************************************************
if ZCPR3
SS SET 0
USER0 SET FALSE
endif
MSIZE EQU 61 ;MEMORY SIZE
if not NOREVA
REVA EQU 'A' ;VALUE OF CPU-BOARD=REV.A FLAG
REVB EQU 'B' ;VALUE OF CPU-BOARD=REV.B FLAG
endif
;SERIAL I/O PORTS (8251)
MSTAT EQU 5 ;MODEM STATUS PORT
MDATA EQU 4 ;MODEM DATA PORT
CSTAT EQU 3 ;CONSOLE STATUS PORT
CDATA EQU 2 ;CONSOLE DATA PORT
LSTAT EQU 1 ;LIST STATUS PORT
LDATA EQU 0 ;LIST DATA PORT
;PARALLEL I/O PORTS (8255 - REV B ONLY)
PPORTA EQU 0D0H ;8255 PORT A
PPORTB EQU PPORTA+1 ;8255 PORT B
PPORTC EQU PPORTA+2 ;8255 PORT C
PPCMD EQU PPORTA+3 ;8255 COMMAND PORT
PPINIT EQU 91H ;A MODE0 IN, C HI OUT; B MODE0 OUT, C LO IN
;**********************************************************
;* SYSTEM CONFIGURATION: *
;* Both IOBYTE and SYSFMT are initialized from 'IOBYTA': *
;* IOBYTE=(IOBYTA AND IOBMSK) OR (DFTSY SHR 2 AND 1) *
;* SYSFMT=(IOBYTA AND SYSMSK) OR DFTSY *
;* This is done for continuity with earlier systems which *
;* used IOBYTE for all the system configuration functions.*
;**********************************************************
IOBYTE EQU 0003H ;I/O BYTE: <llpprrcc> (Reserved Memory location)
;IOBYTE assignments: (Default = '*', optional defaults = '-')
;------------------------------------------------
;ll: prn protocol pp: punch device
;-00 PARALLEL TTY: -00 PARALLEL PRN TTY:
;-01 (CONSOLE OUT) CRT: -01 (not used) PUN:
;-10 ETX/ACK LPT: *10 MODEM OUT UP1:
;*11 XON/XOFF(or NO) UL1: -11 CLOCK WRITE UP2:
; --------------------------------------
;rr: reader device cc: console device
;-00 (not used) TTY: *00 CONSOLE TTY:
; 01 (not used) RDR: 01 CONSOLE/MODEM CRT: (autoswitch)
;*10 MODEM IN UR1: -10 MODEM I/O BAT:
; 11 CLOCK READ UR2: 11 CLOCK R/W UC1:
;------------------------------------------------
;SYSFMT Sytem format byte: <---s-a-d>
;s: autostart mode a: autoswitch mode d: #drives
; 0 on (cold/warm) 0 on(modem&console) 0 2-drives
;*1 off (cold) *1 off(console only) *1 1-drive
;------------------------------------------------
SYSMSK EQU 05H ;(Mask for bits used in SYSFMT from IOBYTA)
IOBMSK EQU (NOT SYSMSK) AND 0FFH ;(Mask for bits used in IOBYTE from IOBYTA)
DFTIO EQU ((LL shl 6 or 28H) and iobmsk) ;Default IOBYTE
DFTSY EQU (AA*4+(not (DD-1) and 1)+(SS*10H and 10H)) ;Default SYSFMT
DFLTIOB EQU DFTIO or (DFTSY AND SYSMSK) ;Default IOBYTA
;********************************************************
CDISC EQU 0004H ;CP/M Reserved memory location - current disk
;DOUBLE DENSITY TEST CODE FLAG
;NOTE: FOR A DISK TO BE CONSIDERED DOUBLE DENSITY
;CODE3 MUST BE ALREADY ON THE DISK AT TRACK 0
;SECTOR 1, BYTE 7F (LAST BYTE)
;CODE4 FOR DOUBLE DENSITY DOUBLE SIDE
CODE3 EQU 0DDH
CODE4 EQU 0D0H
SINGL EQU 2 ;LOGDEN VALUE FOR SINGLE DENS. DISK
;BLOCKING/DEBLOCKING PARAMETERS
WRALL EQU 0 ;WRITE TO ALLOCATED SECTOR*BDOS
WRDIR EQU 1 ;WRITE TO DIRECTORY *CONSTANTS
WRUAL EQU 2 ;WRITE TO UNALLOCATED SEC.*
HSTSIZ EQU 1024 ;PHYSICAL SECTOR SIZE
HSTSPT EQU 8 ;HOST SECTORS PER TRACK
HSTBLK EQU HSTSIZ/128 ;CPM SECTORS/HOST SECTOR
;DISK IO PORTS
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.
DSEL EQU DISK+5 ;DENSITY SELECT/MOTOR CONTROL PORT:
; CODE: | 01/02 | 04/08 |
; |density=dble/single|motor=on/off(revB)|
DCONT EQU DISK+4 ;DISK CONTROL PORT:
; CODE: | 01/02 | 04/08 |
;REV B: |disk=B/A |side=1/0 |
;REV A: |disk/side| n/a |
;CPM PARAMETERS
RTCNT EQU 10 ;RETRY COUNT
BIAS EQU (MSIZE-20)*1024 ;BIAS FOR LARGER THAN 17K.
CCP EQU BIAS+3400H ;START OF CPM.
OFFSET EQU 980H-CCP ;OFFSET USED WITH DDT IN SYSTEM CONFIGURATION
BDOS EQU CCP+806H ;BASE OF BDOS
BIOS EQU CCP+1600H ;BASE OF BIOS
CPML EQU BDOS-CCP ;LENGTH OF CPM CCP (re-loaded in warmboot).
NSECTS EQU (CPML+127)/128 ;NUMBER OF CPM SECTORS IN IT.
NPSECTS EQU (HSTSIZ-1+NSECTS*128)/HSTSIZ ;# OF PHYSICAL SECTORS
MAXDRV EQU 1 ;DRIVES 0 - 1 VALID
CCCONOT EQU CCP+8CH ;CCP: OUTPUT A TO CONSOLE
CCGTUSR EQU CCP+113H ; GET USER NUMBER
CCSTUSR EQU CCP+115H ; SET USER NUMBER
CCOPFCB EQU CCP+0D0H ; CCP OPEN FILE (CPMFCB$)
CCATTR EQU CCP+7D6H ; ATTRIBUTE FIELD IN CPMFCB$
CCDSK EQU CCP+7F0H ; DISK GIVEN IN COMMAND STRING
CCERR EQU CCP+76BH ; TYPE ERROR STRING
CCLOAD EQU CCP+6DEH ; IF FILE OPENS, GO HERE
;Character Equates
CR EQU 0DH
LF EQU 0AH
ESC EQU 1BH
BELL EQU 7
;Z80 OPCODE EQUATES
JR EQU 18H ;JR XX
JRNZ EQU 20H ;JR NZ,XX
JRZ EQU 28H ;JR Z,XX
JRNC EQU 30H ;JR NC,XX
JRC EQU 38H ;JR C,XX
RRCB EQU 08CBH ;RRC B
LDIR EQU 0B0EDH ;LDIR
SRLA EQU 2FCBH ;SRL A
DJNZ EQU 10H ;DJNZ XX
PUSHIX EQU 0E5DDH ;PUSH IX
LDIX EQU 21DDH ;LD IX,XXXX
POPIX EQU 0E1DDH ;POP IX
INI EQU 0A2EDH ;INI
JPIX EQU 0E9DDH ;JP (IX)
OUTI EQU 0A3EDH ;OUTI
OUTCA EQU 79EDH ;OUT (C),A
INAC EQU 78EDH ;IN A,(C)
SBCHLDE EQU 52EDH ;SBC HL,DE
RES2HL EQU 96CBH ;RES 2,(HL)
RES3HL EQU 9ECBH ;RES 3,(HL)
;***********ACIDOS.COM PREFACE CODE****************
;This code allows the ACIDOS.COM to be executed. If run
;(by mistake), it merely brings up the new operating system.
ORG 0100H-OFFSET
LXI H,CCP+OFFSET ;COPY (image in ram from .COM file)
LXI D,CCP ; TO (executable address)
LXI B,ENDISK-CCP ; (# of bytes of image)
DW LDIR
JMP BIOS ;COLDSTART (image at executable address)
DB ' no copyright message here '
;***************************************************
if USER0
;***********USER0 PATCHES ON THE CCP****************
;This code patches the CCP to look first on the A: drive, then in USER 0
;for command files requested but not found in the current user number.
;It makes a call on a routine assembled intp the BIOS.
ORG CCP+6DBH ;Replace 'jz ccerr' with 'jz patch'
JZ CCPATCH ;Patch is called if file isn't found
;in current user.
ORG CCP+7F2H ;Patch is placed in area of CCP occupied
CCPATCH: ;by unused NOPs.
LXI H,CCDSK ;Get drive spec'd in command
ORA M ;If explicit drive given, look in USER0
JNZ CHKUSR0
INR M ;Else set A (was 0 on entry) to A:
LXI D,CCATTR ; and retry (re-enter CCP)
JMP CCP+6CDH
;***************************************************
endif
; 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
ORG BIOS
JMP CBOOT ;FROM COLD START LOADER.
WBOOTE: JMP WBOOT
JMP LCONST
JMP LCONIN
JMP LCONOUT
JMP LLIST
JMP LPUNCH
JMP LREADER
JMP HOME
JMP SELDSK
JMP SETTRK
JMP SETSEC ;SET SECTOR NUMBER.
JMP SETDMA ;SET DISK STARTING ADR.
JMP READ ;READ SELECTED RECORD
JMP WRITE ;WRITE SELECTED RECORD
JMP LLISTST ;RETURN LIST STATUS
JMP SECTRAN ;SECTOR TRANSLATE
; this must be after 17th JUMP address
DFLAGS: DB 0,0,0,0 ;DENSITY FLAGS *do
CALL BLDPTR ;DENSITY SETTING ROUTINE*not
CALL DENSITY ;FOR FCOPY PROGRAM *move
RET ; *or
IOBYTA: DB DFLTIOB ;DEFAULT I/O BYTE *change
SYSFMT: DB DFTSY and IOBMSK ; *
if not P2DOS
DB 'Reserve';FOR FUTURE USE *
endif
if P2DOS
JMP BTIME ;BIOS TIME ROUTINES *
DB 'free' ;FOR FUTURE USE *
endif
UARTT: DB 0CEH ;USART MODE SELECT *
UARTP: DB 0CEH ;CODES *
UARTM: DB 0CEH ; *
;FIXED DATA TABLES FOR TWO-DRIVE STANDARD
;IBM-COMPATIBLE 8" DISKS (MODIFIED IN 'DENSITY').
; DISK PARAMETER HEADER FOR DISK 00 -SNGL D
DPBASE: DW TRANS,0000H
DW 0000H,0000H
DW DIRBF,DPSDBK
DW CHK00,ALL00
; DISK PARAMETER HEADER FOR DISK 01 -SNGL D
DW TRANS,0000H
DW 0000H,0000H
DW DIRBF,DPSDBK
DW CHK01,ALL01
; SINGLE DENSITY SECTOR TRANSLATE VECTOR
TRANS: DB 1,7,13,19 ;SECTORS 1,2,3,4
DB 25,5,11,17 ;SECTORS 5,6,7,8
DB 23,3,9,15 ;SECTORS 9,10,11,12
DB 21,2,8,14 ;SECTORS 13,14,15,16
DB 20,26,6,12 ;SECTORS 17,18,19,20
DB 18,24,4,10 ;SECTORS 21,22,23,24
DB 16,22 ;SECTORS 25,26
; DOUBLE DENSITY SECTOR TRANSLATE VECTOR
TRANSD: EQU 0 ;NO SECTOR TRANSLATION
DPDDBK: ;DOUBLE DENSITY PARAMETER BLOCK
DW 64 ;SECTORS PER TRACK - SPT
DB 4 ;BLOCK SHIFT FACTOR - BSH
DB 15 ;BLOCK MASK - BLM
DB 0 ;NULL MASK - EXM
DW 300-1 ;DISK SIZE IN BLOCKS - DSM
DW 128-1 ;DIRECTORY MAX ENTRIES - DLM
DB 0C0H ;DIR. ALLOC. MASK - AL0
DB 0 ;DIR. ALLOC. MASK - AL1
DW 128/4 ;DIR. CHECK SIZE - CKS
DW 2 ;TRACK OFFSET - OFF
DB 16 ;BLOCKSIZE/128 ****************
DB 7 ;SECMASK *BLOCKING PARMS*
DB 3+1 ;SECSHF * DO NOT MOVE *
DB 64 ;CPMSPT ****************
DPDDBK1: ;DOUBLE DENSITY PARAMETER BLOCK (2 side)
DW 64 ;SECTORS PER TRACK - SPT
DB 5 ;BLOCK SHIFT FACTOR - BSH
DB 31 ;BLOCK MASK - BLM
DB 1 ;NULL MASK - EXM
DW 304-1 ;DISK SIZE IN BLOCKS - DSM
DW 128-1 ;DIRECTORY MAX ENTRIES - DLM
DB 80H ;DIR. ALLOC. MASK - AL0
DB 0 ;DIR. ALLOC. MASK - AL1
DW 128/4 ;DIR. CHECK SIZE - CKS
DW 2 ;TRACK OFFSET - OFF
DB 32 ;BLOCKSIZE/128 *BLOCKING PARMS *
DB 7 ;SECMASK * =HSTSIZ/128-1 *
DB 3+1 ;SECSHF *=LG2(SCMSK+1)+1*
DB 64 ;CPMSPT *=HSTBLK*HSTSPT *
DPSDBK: ;DISK PARAMETER BLOCK, SINGLE DENSITY
DW 26 ;SECTORS PER TRACK
DB 3 ;BLOCK SHIFT FACTOR
DB 7 ;BLOCK MASK
DB 0 ;NULL MASK
DW 242 ;DISK SIZE-1
DW 63 ;DIRECTORY MAX
DB 192 ;ALLOC 0
DB 0 ;ALLOC 1
DW 16 ;CHECK SIZE
DW 2 ;TRACK OFFSET
DB 8 ;BLOCKSIZE/128 ****************
DB 0 ;SECMASK *BLOCKING PARMS*
DB 0+1 ;SECSHF * DO NOT MOVE *
DB 26 ;CPMSPT ****************
;******** END OF FIXED TABLES **************************************
;*******************
; COLDBOOT: STARTUP
;*******************
DB MO,DA,YR;THIS MUST PRECEDE CBOOT
CBOOT: JMP BOOT ;BOOT CHANGES THIS TO WBOOT
;***************************************************************
; WARM-BOOT: READ CCP AND PART OF BDOS BACK IN, THEN JUMP TO CCP.
;****************************************************************
;*** THIS CODE BYTE MUST BE ALWAYS BE THE BYTE BEFORE LABEL WBOOT: ***
DB 0DDH ;*** DO NOT MOVE OR REMOVE ***
WBOOT:
if DEBUG
MVI A,'*'
CALL CONOUTA
endif
LXI SP,80H ;SET STACK POINTER.
LDA SEKDSK ;SAVE DISK NUMBER.
PUSH PSW ;
XRA A ;CLEAR BLOCKING FLAGS
STA HSTACT ; -HOSTBUFFER INACTIVE
STA UNACNT ; -UNALLOC CT=0
STA HSTWRT ; -NO PENDING WRITE
STA SEKDSK ;SET DISK=0 (A:)
CALL CLRDFLGS;CLEAR DENSITY FLAGS
CALL CHKSD ;SELECT A:
MVI A,1 ;
CALL SEEK ;SET TRACK=1
MVI A,1 ;SECTOR=E=1
OUT SECTP ;
MOV E,A ;
LXI H,CCP ;HL -> CCP
MVI C,DDATA ;C -> DATAPORT(1793)
MVI A,8CH ;A=(READ W/15MS DELAY)COMMAND
WBOOT2: CALL RLOOP ; READ SECTOR(E) => (HL)
IN DSTAT ; IF (ERROR) THEN EXIT(RDERR)
ANI 9DH ;
DB JRNZ,BTERR-$-1
INR E ; INCREMENT SECTOR
MOV A,E ; IF (SECTOR=NPSECTS) THEN EXIT(DONE)
CPI NPSECTS+1 ;
DB JRZ,WBOOT3-$-1
OUT SECTP ; SET SECTOR(E)
MVI A,88H ; A=(READ W/NO DELAY)COMMAND
DB JR,WBOOT2-$+0FFH ; END
WBOOT3: POP PSW ;RESTORE DISK NUMBER.
STA SEKDSK ;
if not P2DOS
LDA SYSFMT ;IF (AUTOSTART OFF) DISABLE CCP COMMAND
ANI 10H
DB JRZ,GOCPM-$-1
XRA A
STA CCP+7
endif
GOCPM: if DEBUG
MVI A,'G'
CALL CONOUTA
endif
MVI A,0C3H ;PUT JMP TO WBOOT
STA 0 ;ADR AT ZERO.
LXI H,WBOOTE
SHLD 1
STA 5
LXI H,BDOS ;PUT JUMP TO BDOS
SHLD 6 ;AT ADR 5,6,7.
LXI H,80H ;SET DEFAULT DMA ADR.
SHLD DMAADD
LDA SEKDSK ;GET LAST REQUESTED DISK#
MOV C,A
PUSH B
CALL CHKDS1 ;SET UP DRIVE
POP B
LDA CDISC
ANI 0F0H ;GET USER# (if c:+ requested, cdisc is wrong)
ORA C ;GET (REAL) DRIVE #
MOV C,A
if P2DOS and ZCPR3
JMP P2CWBT ;Do extra ZCPR3 warmboot stuff (reinit Submit FCB).
endif
if (not P2DOS) or (not ZCPR3)
JMP CCP ;JUMP TO CCP.
endif
BTERR: LXI H,BTMSG ;GET ADDRESS OF "BOOT ERROR".
CALL ERMSG ;PRINT IT.
CALL LCONIN ;READ A CHAR FROM CONSOLE.
JMP WBOOT ;DO A WARM BOOT.
CLRDFLGS:
LXI H,0 ;CLEAR DENSITY FLAGS
SHLD DFLAGS ;
SHLD DFLAGS+2;
RET
;****************************************************************
;SELDSK: SELECT DISK NUMBER ACCORDING TO REGISTER C.
;BLDPTR: BUILD POINTER (IN HL) TO DISK PARM BLK HEADER
;****************************************************************
SELDSK:
if DEBUG
MVI A,'d'
CALL CONOUTA
MOV A,C
CALL PHEX
endif
LDA SEKDSK ;SAME AS LAST DRIVE REQUESTED?
CMP C ;
DB JRZ,BLDPTR-$-1; YES, JUST BUILD DRIVE HEADER POINTER.
MOV A,C ;
CPI MAXDRV+1;SEE IF DRIVE NO. IS VALID
LXI H,0 ; (IF INVALID, RETURN HL=0)
RNC ;ERROR - RETURN IF OUT OF RANGE
PUSH PSW ;IF WRITE PENDING THEN
CALL FLUSH ; FLUSH BUFFER
POP PSW ;
STA SEKDSK ;SEKDSK=NEW DRIVE SELECTED
MOV C,A ;BUILD DPB HEADER POINTER
CALL BLDPTR ;
JMP DENSITY ;GET DENSITY PARMS
BLDPTR: ;COMPUTE SEL. DRIVE HEADER VECTOR
MOV L,C ;DISK NO.
MVI H,0 ;AS 16 BIT QTY.
DAD H ;*2 (BUILD 16-BYTE OFFSET)
DAD H ;*4
DAD H ;*8
DAD H ;*16
LXI D,DPBASE;TABLE BASE
DAD D ;EFFECTIVE ADDRESS OF VECTOR
RET ;
;****************************************************
;CHKSD: CHECK THAT CURRENT DISK=SELECTED DISK &
;CHKDSK: CHECK THAT DISK (C) =SELECTED DISK &
; & SELECT IF NOT
;****************************************************
CHKSD: LDA SEKDSK ;C=SEKDSK
CHKDSA: MOV C,A
CHKDSK: LDA CURDSK ;A=CURDSK
CMP C ;IF (A=C) THEN RETURN(&TURN MOTORS ON)
JZ MTRON ;
CHKDS1: ;/******* ENTRY FOR BOOT (A=C=0)*******/
;/*FROM HERE ON, C=DISK TO BE SELECTED*/
MOV E,A ;HL => TRACKTABLE(LASTDRIVE)
MVI D,0 ;
LXI H,TRTAB ;
DAD D ;
IN TRACK ;A = 1793 TRACK REGISTER (ADJUSTED)
CALL INTRK ;
MOV M,A ;M(HL) = A
MOV E,C ;HL => TRACKTABLE(NEWDRIVE)
LXI H,TRTAB ;
DAD D ;
MOV A,M ;
CALL OUTRK ;
OUT TRACK ;1793 TRACK REG = TRKTBL(NWDR) (ADJUSTED)
if not ONLY2
LDA SYSFMT ;IF (1 DRIVE SYSTEM) THEN DO
MOV B,A ;
RAR ;
DB JRNC,TWODR-$-1;SWAP DISKS:
PUSH H ;THE FOLLOWING IS SINGLE DRIVE
PUSH B ;DISK SWAP CODE
LDA CURDSK ;
CMP C ;CHECK IF CHANGE IN DISK &
DB JRZ,CHKDS2-$-1 ;
MOV A,C ;PUT DISK REFERENCE IN MESSAGE
ADI 'A' ;
STA SWDSK ;
LXI H,SWMSG ;PROMPT FOR DISK SWAP
CALL PMSG ;
CALL LCONIN ;WAIT FOR KEY TO BE HIT
CALL PCRLF ;PRINT CRLF
CHKDS2: POP B ;
POP H ;
DB JR,CHKDS4-$-1 ;
endif
TWODR: MOV A,C ;ELSE CHANGE DRIVE
INR A ;
CMA ;
ANI 3 ;
OUT DCONT ;
CHKDS4: MOV A,M ;IF (TRACK=0FFH) DO
INR A ;
DB JRNZ,CHKDS6-$-1
if not NOREVA
LDA CPUREV ; IF (REV.B) OR (REV.A AND 2DRIVE SYSTEM) DO
CPI 'B'
DB JRZ,CHKDS5-$-1
MOV A,B
RAR
DB JRNC,CHKDS6-$-1
endif
CHKDS5: PUSH B ; /*This is the 1st time this disk is*/
CALL OUTRK ; SET SIDE 0 /*accessed. We don't know where the*/
OUT TRACK ; /*head is, so we HOME it. */
CALL HOME1 ; HOME DRIVE
POP B ; ENDIF
CHKDS6: CALL MTRON ;WAIT FOR DRIVE READY(TURN MOTOR ON, ALSO)
MOV A,C ;SET CURDSK=SELECTED DRIVE
STA CURDSK ;
CALL BLDPTR ;BUILD POINTER TO PARM. HDR.
;SET DENSITY PARMS FOR DISK (C).
;***********************************************
;DENSITY: SET DRIVE PARMS FOR DRIVE # (C)
; C: DRIVE # (0-3)
; HL: -> DISK PARAMETER HEADER (IN DPBASE:)
; KILLS: A,BC,DE,FLAGS
;DETERMINE DENSITY OF NEW DISK, SELECT TRANSLATE TABLE
;AND DISK PARM BLOCK, IN DPBASE
;***********************************************
DENSITY:
PUSH H ;SAVE DISKPARM HEADER PTR
LXI H,DFLAGS;HL -> DENSITY FLAGS
MVI B,0 ;
DAD B ;
MOV A,M ;
ORA A ;GET DENSITY FLAG(C)
JM LOGED ;SKIP IF LOGGED IN BEFORE
PUSH H ; SAVE DENSITYFLAGPTR
CALL CHKDSK ; CHECK IF SELECTED ALREADY, DO SO IF NOT.
IF VER36
LDA SEKSEC ; SAVE SECTOR
PUSH PSW ;
LHLD DMAADD ; SAVE DMAADD
PUSH H ;
CALL HOME1 ; DENSITYFLAG=F(TRACK0,SECTOR1,BYTE7FH)
MVI C,1
CALL SETSEC
LXI B,DIRBF
CALL SETDMA
CALL READ
POP H ; RESTORE DMADD
SHLD DMAADD
POP PSW ; RESTORE SECTOR
STA SEKSEC
POP H ; RESTORE DENSITYFLAGPTR
LDA DIRBF+07FH;(DENSITYFLAG BYTE)
ENDIF
IF NOT VER36
CALL HOME1
LXI H,ERCNT
MVI M,RTCNT
DENS1: MVI A,0D0H ;FORCE INTERRUPT
OUT DCOM
XTHL ;KILL TIME
XTHL
XTHL
XTHL
MVI A,1 ;SET SECTOR
OUT SECTP
IN DSTAT ;LOOK AT HEAD LOAD BIT
ANI 20H
MVI A,8CH ;READ WITH HEAD LOAD DELAY
DB JRZ,DENS2-$-1
MVI A,88H ; READ WITH NO HEAD LOAD DELAY
DENS2: DW PUSHIX
CALL XRLOOP ;READ SECTOR AND REATIN (ONLY) LAST BYTE
DW POPIX
MOV B,A
IN DSTAT ;CHECK FOR ERRORS
ANI 9DH
DB JRZ,DENS3-$-1 ;NONE FOUND
DCR M ;ERROR FOUND - DECREMENT ERRORCOUNT
DB JRNZ,DENS1-$+0FFH ;RETRY
CALL ERMSG0 ;PRINT ERRMSGS (RETURNS 0 WHICH WE USE FOR SSSD)
DENS3: POP H ;RESTORE PTR TO DENSITY FLAG
MOV A,B
ENDIF
CPI 0DDH ;CODE3
DB JRZ,LOGDD-$-1
CPI 0D0H ;CODE4
DB JRZ,LOGD0-$-1
LOG00: MVI A,82H ;LOGGED DISK IS SINGLE DENSITY
LXI B,TRANS ;
LXI D,DPSDBK;
DB JR,LOGDRV-$-1
LOGED: CPI 081H ;TEST PREVIOUSLY LOGGED DRIVE PARM
DB JRZ,LOGDD-$-1 ;AND BRANCH APPROPRIATELY
CPI 085H ;
DB JRNZ,LOG00-$+0FFH
LOGD0: MVI A,85H ;LOGGED DISK IS DBL SIDE, DBL DENSITY
LXI B,TRANSD;
LXI D,DPDDBK1;
DB JR,LOGDRV-$-1
LOGDD: MVI A,81H ;LOGGED DISK IS SNGL SIDE, DBL DENSITY
LXI B,TRANSD;
LXI D,DPDDBK;
LOGDRV: MOV M,A ;SAVE DISKTYPE IN DENSITY FLAGS
ANI 3 ;STRIP OFF LOGGED IN BIT
STA LOGDEN ;SAVE DENSITY OF LOGGED IN DRIVE
OUT DSEL ;SET IT
POP H ;GET DISKPARMHDR PTR
PUSH H ;SAVE IT FOR RETURN
MOV M,C ;SET UP TRANSLATE TABLE PTR IN BLOCK
INX H
MOV M,B ;
LXI B,9 ;SET UP DISK PARM PTR IN BLOCK
DAD B ;
MOV M,E ;
INX H ;
MOV M,D ;
LXI H,15 ;LET HL->BLOCKING PARMS (SET BLKG PRMS FOR DISK)
DAD D ;
LXI D,CPMSPB;LET DE->LOGGEDDRIVE BLOCKINGPARM AREA
LXI B,4 ;LET BC=#ITEMS TO MOVE
DW LDIR ;(MOVE (HL)=>(DE),BC ITEMS)
POP H ;RETURN DISKPARMHDR POINTER
RET ;
XRLOOP: DW LDIX,XRL1
OUT DCOM
EI
XRL1: HLT ;WAIT FOR F/D CONTROLLER TO START AGAIN...
IN DDATA
EI
DW JPIX
;****************************************************************
; SET TRACK NUMBER TO REGISTER C.
;****************************************************************
SETTRK:
if DEBUG
MVI A,'t'
CALL CONOUTA
MOV A,C
CALL PHEX
endif
MVI H,0 ;SAVE TRACK NUMBER
MOV L,C
SHLD SEKTRK
RET
;****************************************************************
; SET DISK SECTOR NUMBER.
;****************************************************************
SETSEC:
if DEBUG
MVI A,'s'
CALL CONOUTA
MOV A,C
CALL PHEX
endif
MOV A,C ;GET SECTOR NUMBER.
STA SEKSEC
RET ;RETURN FROM SETSEC.
;****************************************************************
; SET DISK DMA ADDRESS.
;****************************************************************
SETDMA: MOV H,B ;MOVE B&C TO H&L.
MOV L,C
SHLD DMAADD ;PUT AT DMA ADR ADDRESS.
RET ;RETURN FROM SETDMA.
;****************************************************************
;TRANSLATE SECTOR IN BC TO HL USING TABLE POINTED AT BY DE.
;****************************************************************
SECTRAN:
if DEBUG
MVI A,'x'
CALL CONOUTA
MOV A,B
CALL PHEX
MOV A,C
CALL PHEX
endif
MOV A,E ;TEST IF TABLE TRANSLATION IS REQUESTED
ORA D ; (I.E. DE<>0)
DB JRNZ,SECTR1-$-1 ; YES, DO IT
MOV L,C ; NO, LET HL=BC+1
MOV H,B ;
INX H ;
RET ;
SECTR1: XCHG ;GET TABLE ADDR IN HL
DAD B ;INDEX INTO TABLE
MOV L,M ;HL=M(BC+DE)
MVI H,0 ;
RET ;
;*****************************************************
;* Read CPM sector (record) from SEKDSK, *
;* SEKTRK,SEKSEC, to M(DMAADD). *
;*****************************************************
READ:
if DEBUG
MVI A,'r'
CALL CONOUTA
endif
XRA A
STA UNACNT
INR A
STA READOP ;read operation
STA RSFLAG ;must read data
MVI A,WRUAL
STA WRTYPE ;treat as unalloc
DB JR,RWOPER-$-1 ;to perform the read
;*****************************************************
;* Write CPM sector (record) from M(DMAADD) *
;* to SEKDSK,SEKTRK,SEKSEC. *
;*****************************************************
WRITE:
if DEBUG
MVI A,'w'
CALL CONOUTA
endif
XRA A ;0 to accumulator
STA READOP ;not a read operation
MOV A,C ;write type in c
STA WRTYPE
LDA LOGDEN ;IF (SD), NEVER RD BEFORE WR
CPI SINGL ;
DB JRZ,NOOVF-$-1 ;
MOV A,C ;
CPI WRUAL ;write unallocated?
DB JRNZ,CHKUNA-$-1 ;check for unalloc
;write to unallocated, set parameters
LDA CPMSPB ;next unalloc recs
STA UNACNT
LXI H,SEKDSK ;Copy SEEK parms to UNALLOC parms
LXI D,UNADSK
LXI B,5
DW LDIR
CHKUNA: ;check for write to unallocated sector
LDA UNACNT ;any unalloc remain?
ORA A
DB JRZ,ALLOC-$-1 ;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?
DB JRNZ,ALLOC-$-1 ;skip if not
;disks are the same
LHLD UNATRK
CALL SEKTRKCMP ;sektrk = unatrk?
DB JRNZ,ALLOC-$-1 ;skip if not
;tracks are the same
LDA SEKSEC ;same sector?
LXI H,UNASEC
CMP M ;seksec = unasec?
DB JRNZ,ALLOC-$-1 ;skip if not
;match, move to next sector for future ref
INR M ;unasec = unasec+1
LDA CPMSPT ;end of track?
CMP M ;count CP/M sectors
DB JRNC,NOOVF-$-1 ;skip if no overflow
;overflow to next track
MVI M,1 ;unasec = 1
LHLD UNATRK
INX H
SHLD UNATRK ;unatrk = unatrk+1
NOOVF: ;match found, mark as unnecessary read
XRA A
STA RSFLAG ;rsflag = 0
DB JR,RWOPER-$-1 ;to perform the write
ALLOC: ;not an unallocated record, requires pre-read
XRA A
STA UNACNT ;unacnt = 0
INR A
STA RSFLAG ;rsflag = 1
;*****************************************************
;* *
;* Common code for READ and WRITE follows *
;* *
;*****************************************************
RWOPER: if TYPEAHEAD
CALL TESTI ;(TEST CONSOLE INPUT)
endif
LDA SECSHF ;COMPUTE HOST SECTOR
MOV B,A
LDA SEKSEC ;HOSTSECTOR=((SEEKSECTOR)-1 SHR SEKSHF)+1
DCR A
DB JR,RWOPR2-$-1
RWOPR1: DW SRLA
RWOPR2: DB DJNZ,RWOPR1-$+0FFH
INR A
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?
DB JRZ,FILHST-$-1 ;fill host if not
;host buffer active, same as seek buffer?
LDA SEKDSK
LXI H,HSTDSK
CMP M ;sekdsk = hstdsk?
DB JRNZ,NOMATCH-$-1
LHLD HSTTRK
CALL SEKTRKCMP ;sektrk = hsttrk?
DB JRNZ,NOMATCH-$-1
LDA SEKHST
LXI H,HSTSEC ;sekhst = hstsec?
CMP M
DB JRZ,MATCH-$-1 ;skip if match
NOMATCH: ;not correct sector
CALL FLUSH ;flush buffer
STA ERFLAG ;REPORT ANY ERRORS
FILHST: ;fill the host buffer
LXI H,SEKDSK ;Copy SEEK parms to HOSTBUFFER parms
LXI D,HSTDSK
LXI B,5
DW LDIR
LDA RSFLAG ;need to read?
ORA A
CNZ READHST ;yes, if 1
LXI H,ERFLAG ;REPORT ANY ERRORS
ORA M
MOV M,A
XRA A
STA HSTWRT ;no pending write
MATCH: ;copy data to or from buffer
LDA SEKSEC ;mask buffer number
DCR A ; HL=((SEKSEC-1) AND SECMSK) SHL 7
MOV L,A
LDA SECMSK
ANA L
RAR
MOV H,A
MVI A,0
RAR
MOV L,A ; HL has relative host buffer address
LXI D,HSTBUF
DAD D ;hl = host address
XCHG ;now in DE
LHLD DMAADD ;get/put CP/M data
XCHG
LXI B,128 ;length of move
LDA READOP ;which way?
ORA A
DB JRNZ,RWMOVE-$-1 ;skip if read
;write operation, mark and switch direction
MVI A,1
STA HSTWRT ;hstwrt = 1
XCHG ;source/dest swap
RWMOVE: DW LDIR ;BC initially 128, HL is source, DE is dest
;data has been moved to/from host buffer
LDA WRTYPE ;write type
CPI WRDIR ;to directory?
LDA ERFLAG ;IF NOT THEN EXIT WITH FLAG
RNZ
;clear host buffer for directory write
ORA A ;errors?
CZ WRITEHST;IF NOT, WRITE BUFFER
RET
;*****************************************************
;* Compare M(HL)=SEKTRK, 16-bit compare *
;*****************************************************
SEKTRKCMP: ;HL = .unatrk or .hsttrk, compare with sektrk
XCHG
LHLD SEKTRK
ORA A ;(clear carry)
DW SBCHLDE ;SBC HL,DE set Z/NZ on compare
RET
;****************************************************************
; READ THE SECTOR AT HSTSEC, HSTTRK, HSTDSK.
; USE HOSTBUFFER.
;****************************************************************
READHST:
if DEBUG
MVI A,'R'
CALL CONOUTA
endif
LDA HSTDSK
CALL CHKDSA ;SELECT HOST DISK
CALL CHKTRK ;CHECK FOR CORRECT CURRENT TRACK, & MOVE
MVI A,RTCNT ;GET RETRY COUNT.
RRETRY: STA ERCNT ;STORE IN ERROR CTR.
if TYPEAHEAD
CALL TESTI
endif
LXI H,HSTBUF;GET STARTING ADR.
MVI A,0D0H ;CAUSE INTERRUPT.
OUT DCOM
XTHL ;SOME DELAY.
XTHL
XTHL
XTHL
LDA HSTSEC ;GET SECTOR NUMBER.
OUT SECTP ;SET SECTOR INTO 1793.
IN DSTAT ;READ STATUS.
ANI 20H ;LOOK AT HLD BIT.
MVI A,8CH ;READ WITH HEAD LOAD DELAY
DB JRZ,READ3-$-1 ;HEAD NOT LOADED.
MVI A,88H ;CODE FOR READ W/O HD LD DELAY
READ3: MVI C,DDATA ;SEND COMMAND TO 1793
DW PUSHIX
CALL RLOOP
DW POPIX
IN DSTAT ;DONE: READ DISK STATUS.
ANI 9DH ;LOOK AT ERROR BITS.
JZ MTROFF ;IF NO ERROR THEN RETURN (&TURN MOTOR OFF)
CALL ERCHK ;CHECK FOR SEEK ERROR.
LXI H,RECNT ;GET RD ERR COUNT ADDR.
INR M ;ONE MORE ERROR.
LDA ERCNT ;GET ERROR COUNT.
DCR A ;DECREMENT COUNT.
DB JRNZ,RRETRY-$+0FFH ;TRY TO READ AGAIN.
ERMSG0: LXI H,RDMSG ;PRINT "READ ".
ERMSG: CALL PMSG ;PRINT ORIGIN MESSAGE.
ERMSG1:
MOV A,D ;GET ERROR BITS.
RAL ;IF BIT 7 HIGH,
LXI H,NRMSG ;"NOT READY".
DB JRC,ERMSG2-$-1
MOV A,D ;GET ERROR BITS.
ANI 10H ;IF BIT 4 IS HIGH,
LXI H,RNMSG ;PRINT "RECORD NOT FOUND"
CNZ PMSG
MOV A,D ;GET ERROR BITS.
ANI 8H ;IF BIT 3 IS HIGH,
LXI H,CRCMSG ;PRINT "CRC ERROR".
CNZ PMSG
MOV A,D ;GET ERROR BITS.
ANI 4H ;IF BIT 2 IS HIGH,
LXI H,LDMSG ;PRINT "LOST DATA".
CNZ PMSG
MOV A,D ;GET ERROR BITS.
RAR ;IF BIT 1 IS HIGH,
LXI H,BSYMSG;PRINT "BUSY".
CC PMSG
PERMSG: LXI H,ERRMSG ;PRINT "ERROR."
ERMSG2: CALL PMSG
MVI A,1 ;SET FOR BDOS ERR.
ORA A
JMP MTROFF ;TURN MOTOR OFF
RLOOP: DW LDIX,RL1
OUT DCOM ;
EI ;
RL1: HLT ;
DW INI ;
EI ;
DW JPIX ;
; ERCHK - CHECK FOR RECORD NOT FOUND ERROR.
ERCHK: MOV D,A ;SAVE ERROR BITS IN D.
ANI 10H ;IF RECORD NOT FOUND,
CNZ CHKSK ;DO A CHECK ON SEEK.
MOV A,D ;RESTORE BITS
ORA A ;SET FLAGS,
RET ;AND RETURN.
;CHECK FOR SEEK TO CORRECT TRACK,
;AND CHANGE IF NECESSARY.
CHKSK: PUSH H ;
MVI A,0C4H ;COMMAND TO READ ADDRESS
MVI C,DDATA ;
LXI H,ADDRBF ;
DW PUSHIX
CALL RLOOP ;
DW POPIX
LDA ADDRBF ;
MOV B,A ;
POP H ;DMAADD: TRK,SIDE,SECTOR,SECL,CRC,CRC
CHKS3: IN DSTAT ;READ DISK STATUS.
ORA A ;SET FLAGS.
DB JRZ,CHKS4-$-1 ;READ ADR OK IF 0.
CALL HOME1 ;OTHERWISE, HOME FIRST.
DB JR,CHKTRK-$-1
CHKS4:
MOV A,B ;UPDATE TRACK REGISTER.
CALL OUTRK ;ADJUST IF 2SIDE
OUT TRACK ;
;*********************************************
;CHKTRK: IF CURRENT TRACK <> HOST TRACK, GOTO HOSTTRACK
;*********************************************
CHKTRK: IN TRACK
CALL INTRK
LXI H,HSTTRK
CMP M
RZ ;TRACKS ARE THE SAME, RETURN
MOV A,M ;TRACKS NOT SAME, CORRECT
JMP SEEK ;
;****************************************************************
; FLUSH THE BUFFER IF A WRITE OPERATION IS PENDING
;****************************************************************
FLUSH: LDA HSTWRT ;
ORA A ;
RZ
;****************************************************************
; WRITE THE SECTOR AT HSTSEC, HSTTRK, HSTDSK.
; USE HOST BUFFER.
;****************************************************************
WRITEHST:
if DEBUG
MVI A,'W'
CALL CONOUTA
endif
LDA HSTDSK ;CHECK FOR CORRECT DISK, AND SELECT
CALL CHKDSA ;
CALL CHKTRK ;GO TO CORRECT TRACK
MVI A,RTCNT ;GET RETRY COUNT.
WRETRY: STA ERCNT ;STORE IN ERROR COUNTER.
if TYPEAHEAD
CALL TESTI
endif
LXI H,HSTBUF ;GET STARTING ADR.
MVI A,0D0H ;STATUS INTERUPT FOR 1793.
OUT DCOM ;COMMAND 1793.
XTHL
XTHL
XTHL
XTHL
LDA HSTSEC ;GET SECTOR NUMBER.
OUT SECTP ;SET THE SECTOR INTO 1793.
IN DSTAT ;GET 1793 STATUS.
ANI 20H ;CHECK FOR HEAD LOAD.
MVI A,0ACH ;SET UP 1793 FOR WRITE.
DB JRZ,WRITE2-$-1 ;HEAD IS NOT LOADED.
MVI A,0A8H ;CODE FOR WRITE W/O HD LD.
WRITE2: MVI C,DDATA
DW PUSHIX
CALL WLOOP
DW POPIX
IN DSTAT ;DONE: READ DISK STATUS.
ANI 0FDH ;LOOK AT THESE BITS.
STA HSTWRT ;CLEAR PENDINGWRITEFLAG IF NO ERROR
JZ MTROFF ;RETURN IF NO ERROR (&TURN MOTOR OFF).
CALL ERCHK ;CHECK/CORRECT SEEK ERR.
LXI H,WECNT ;GET ADR OF WRITE ERR CTR.
INR M ;ONE MORE WRITE ERROR.
LDA ERCNT ;GET ERROR COUNT.
DCR A ;DECREMENT COUNT.
DB JRNZ,WRETRY-$+0FFH ;TRY TO WRITE AGAIN.
LXI H,WTMSG ;PRINT "WRITE ".
CALL PMSG
MOV A,D ;GET ERROR BITS.
ANI 40H ;LOOK AT BIT 6.
LXI H,WPMSG ;PRINT "PROTECT ".
CNZ PMSG
MOV A,D ;GET ERROR BITS.
ANI 20H ;LOOK AT BIT 5.
LXI H,WFMSG ;PRINT "FAULT ".
CNZ PMSG
JMP ERMSG1 ;DO COMMON MESSAGES.
WLOOP: DW LDIX,WL1
OUT DCOM
EI
WL1: HLT
DW OUTI
EI
DW JPIX
;****************************************************************
; HOME DISK DRIVE (RETURN TO TRACK 0)
;****************************************************************
HOME:
if DEBUG
MVI A,'H'
CALL CONOUTA
endif
CALL FLUSH ;IF (BUFFER WRITE PENDING) THEN WRITE BUFFER
; (SPEEDS UP SAVE & PIP)
CALL CLRDFLGS;CLEAR DENSITY FLAGS
CALL CHKSD ;CHECK FOR SEKDSK AND SELECT IF NECESSARY
HOME1: MVI A,2
OUT DSEL ;SINGLE DENSITY
MVI C,0
CALL SETTRK
CALL MTRON ;TURN MOTOR ON
XRA A
OUT DDATA ;TRACK # 0
MVI A,1CH ;3MS SEEK W/ HEAD LOAD & VERIFY
CALL DCOMM
IN DSTAT ;READ STATUS.
ANI 91H ;LOOK AT BITS.
RZ ;OK IF ZERO.
MVI A,9 ;6MS RESTORE W/BEGIN HEAD LOAD
CALL DCOMM ;
IN DSTAT
ANI 91H
DB JRZ,HOME2-$-1 ;IF NOT OK, SEEK TRACK 0
XRA A
CALL SEEK
HOME2: JMP MTROFF ;RETURN (&TURN MOTOR OFF)
;****************************************************************
;SEEK: MOVE THE HEAD TO THE TRACK IN REGISTER A (= 0-153).
;****************************************************************
SEEK: PUSH B ;SAVE B&C.
PUSH PSW ;
CALL MTRON ;(TURN MOTOR ON)
POP PSW ;
MOV B,A ;SAVE DESTINATION TRACK.
XRA A ;
STA SECNT ;CLEAR SEEK ERROR CTR
MOV A,B ;
ORA A ; IF (TK 0) THEN
MVI A,2 ; SET UP FOR SINGLE DENS
DB JRZ,SEEK1-$-1
MVI A,1 ; IF (TK 1) THEN
CMP B ; SET UP FOR DOUBLE DENSITY
if not IBMB
DB JRZ,SEEK1-$-1
endif
if IBMB
DB JRNZ,SEEK0-$-1; (UNLESS NOT A: AND IBM OPTION SELECTED)
LDA CURDSK ; (IN WHICH CASE, TRK1 DENSITY=LOGDEN)
ORA A ;
MVI A,1 ;
DB JRZ,SEEK1-$-1
SEEK0: ;
endif
LDA LOGDEN ;ELSE GET DENSITY OF LOGGED DRIVE.
SEEK1: OUT DSEL ;SET DENSITY IN 1793
MVI A,RTCNT ;GET RETRY COUNT.
SRETRY: STA SERCNT ;STORE IN ERROR COUNTER.
IN TRACK ;READ PRESENT TRACK NO.
CALL INTRK ;ADJUST IF 2SIDE
MOV C,A ;SAVE IN C. (CURR TK)
CMP B ;SAME AS SEEK TRACK NO.? (A IS CURR TK)
MOV A,B ;RESTORE A FROM B. (MAKE A DESIRED TK)
DB JRZ,THERE-$-1 ;IF (THERE) THEN EXIT
MVI A,0D0H ;TERMINATE COMMAND AND/OR BUSY
OUT DCOM ;
XTHL ;WASTE
XTHL ;TIME
MOV A,B ;GET TRACK
CALL OUTRK ;ADJUST FOR 2-SIDE
OUT DDATA ;OUTPUT (SEEK TRACK #)
MVI A,1CH ;3MS SEEK W/ HEAD LOAD & VERIFY
CALL DCOMM ;
IN DSTAT ;READ STATUS.
ANI 91H ;LOOK AT BITS.
DB JRZ,THERE-$-1 ;OK IF ZERO.
MOV B,A ;SAVE STATUS IN B
LDA SECNT ;
INR A ;
STA SECNT ;ADD 1 TO SEEK ERR CTR
LDA SERCNT ;GET ERROR COUNT.
DCR A ;DECREMENT COUNT.
DB JRNZ,SRETRY-$+0FFH ;RETRY SEK.
MOV D,B ;RESTORE STATUS TO D REG
POP B ;RESTORE B&C.
LXI H,SKMSG ;PRINT "SEEK ".
JMP ERMSG ;DO COMMON ERR MESSAGES.
THERE: POP B
RET
DCOMM: OUT DCOM
EI
HLT ;INTERUPT CAUSES RETURN
RET ;WHEN COMMAND COMPLETE
;*****************************************************
; INTRK/OUTRK ADJUST TRACK NUMBERS IF >77
;*****************************************************
INTRK: ;TRACK # IN A INCREASED BY 77 IF SIDEFLG NON-ZERO
PUSH PSW
LDA SIDEFLG
ORA A ;Z:=(TRACK<77)
DB JRZ,INTRK1-$-1
POP PSW
ADI 77
RET
OUTRK: ;TRACK # IN A REDUCED BY 77 IF >76 AND SET SIDEFLG NON-ZERO
PUSH PSW
CPI 77
if not NOREVA
LDA CPUREV ;A=CPU BD REV
endif
DB JRC,OUTRK1-$-1
if not NOREVA
CPI REVB ; (>=T77)
endif
MVI A,4 ; (REV B)
if not NOREVA
DB JRZ,OUTRK0-$-1
MVI A,1 ; (REV A)
endif
OUTRK0: STA SIDEFLG
OUT DCONT
POP PSW
SUI 77
RET
OUTRK1: if not NOREVA
CPI REVB ; (<T77)
endif
MVI A,8 ; (REV B)
if not NOREVA
DB JRZ,OUTRK2-$-1
LDA SEKDSK ; (REV A) IF NOT(DRIVE A) THEN DON'T SET SIDE
ORA A ;
DB JRNZ,OUTRK3-$-1
MVI A,2 ; (REV A AND DRIVE A)
endif
OUTRK2: OUT DCONT
OUTRK3: XRA A
STA SIDEFLG
INTRK1: POP PSW
RET
;****************************************
; DRIVE MOTOR CONTROL ON/OFF
;****************************************
MTRON:
IN TRACK ;SET SIDE 0
CALL OUTRK
MVI A,8 ;TURN DRIVE MOTOR ON
OUT DSEL
MVI A,0D0H ;1793 FORCE INTERRUPT COMMAND
OUT DCOM
IN DSTAT ;IF (READY) THEN RETURN
RAL
RNC
MTRON1: IN DSTAT ;ELSE DO
RAL ; REPEAT
DB JRC,MTRON1-$+0FFH; UNTIL (READY)
PUSH H ; /*Check spindle speed*/
PUSH B
CALL SPIN
POP B
POP H
RET
SPIN: CALL SPIN1 ;Check spindle speed twice
SPIN1: LXI B,-13544; REPEAT
SPIN2: LXI H,0 ; HL=0
SPIN3: ; REPEAT
if TYPEAHEAD
CALL TESTI
endif
IN DSTAT
ANI 2
DB JRZ,SPIN3-$+0FFH; UNTIL (INDEX PULSE)
SPIN4: IN DSTAT ; REPEAT
ANI 2
DB JRNZ,SPIN4-$+0FFH; UNTIL (NO INDEX PULSE)
SPIN5: INX H ; REPEAT
MOV A,H ; IF (HL++ == 0) start over
ORA L
DB JRZ,SPIN2-$+0FFH
IN DSTAT
ANI 2
JZ SPIN5 ; UNTIL (INDEX PULSE)
DAD B ; UNTIL (HL<13544)
JC SPIN2
RET
MTROFF:
PUSH PSW ;TURN DRIVE MOTOR OFF
MVI A,4 ;(DRIVE STOPS ~20 SECS AFTER COMMAND)
OUT DSEL
POP PSW
RET
;****************************************************************
; I/O Routines
;****************************************************************
PCRLF: LXI H,CRLF ;PRINT CRLF
PMSG: MOV A,M ;GET A CHARACTER.
CALL CONOUTA ;PRINT IT.
ORA M ;GET AGAIN, SET FLAGS
RM ;IF MSB SET, RETURN
INX H ;INCREMENT H&L, AND GET ANOTHER.
DB JR,PMSG-$+0FFH
if DEBUG
PHEX: PUSH PSW ;Print ACC in Hex (destroys acc)
RRC
RRC
RRC
RRC
CALL PHEX1
POP PSW
PHEX1: ANI 0FH
ADI 90H
DAA
ACI 40H
DAA
;fall through to CONOUTA
endif
CONOUTA: ;print acc
PUSH B
ANI 7FH
MOV C,A
CALL LCONOUT
POP B
RET
;**************************************************
;* I/O DEVICE DRIVERS *
;* See IOBYTE description at beginning of listing *
;**************************************************
LCONST: PUSH D ;LOGICAL CONSOLE INPUT DEVICE STATUS
CALL DISPATCH0
DW CONST ;00=Console
DW AUTST ;01=Console & Modem in parallel (Autoswitch mode)
DW MODST ;10=Modem
DW NULLRDY ;11=Clock (Always ready)
LCONIN: PUSH D ;LOGICAL CONSOLE INPUT DEVICE
CALL DISPATCH0
DW CONIN ;00=Console
DW AUTIN ;01=Console & Modem
DW MODEMIN ;10=Modem
DW RCLOCK ;11=Clock
LCONOUT:PUSH D ;LOGICAL CONSOLE OUTPUT DEVICE
CALL DISPATCH0
DW CONOUT ;00=Console
DW AUTOUT ;01=Console & Modem
DW MODEMO ;10=Modem
DW WCLOCK ;11=Clock
LREADER:PUSH D ;LOGICAL READER DEVICE
MVI E,2
CALL DISPATCH
DW NULLIN ;00= not used
DW NULLIN ;01= not used
DW MODEMIN ;10=Modem
DW RCLOCK ;11=Clock
LPUNCH: PUSH D ;LOGICAL PUNCH DEVICE
MVI E,4
CALL DISPATCH
DW PLLPRN ;00=Parallel printer
DW NULLOUT ;01= not used
DW MODEMO ;10=Modem
DW WCLOCK ;11=Clock
LLISTST: PUSH D ;LOGICAL LIST DEVICE STATUS
MVI E,6
CALL DISPATCH
DW PLLRDY ;00=Parallel printer
DW NULLRDY ;01=Console
DW NULLRDY ;10=Serial, ETX/ACK
DW NULLRDY ;11=Serial, XON/XOFF
NULLRDY:XRA A ;RETURN STATUS (0 IF NOT-READY SEZ D.R.I.?)
RET
LLIST: PUSH D ;LOGICAL LIST DEVICE
MVI E,6
CALL DISPATCH
DW PLLPRN ;00=Parallel printer
DW CONOUT ;01=Console
DW ETXACK ;10=Serial, ETX/ACK protocol
DW XONXOFF ;11=Serial, XON/XOFF protocol
DISPATCH0:
MVI E,8
DISPATCH:
LDA IOBYTE ;Get byte from IOBYTE
DISP1: RRC ;Rotate bits of interest into lsb
DCR E
DB JRNZ,DISP1-$+0FFH
ANI 3 ;Mask for desired bits
XTHL ;Push HL, Pop (Table Address)
MOV E,A
MVI D,0 ;HL -> Table Item
DAD D
DAD D
MOV E,M ;HL = Table Item
INX H
MOV D,M
XCHG
PUSH B ;Push B (TOS=Caller's HL,DE)
LXI D,DISP2 ;Push return address
PUSH D
if TYPEAHEAD
CALL TESTI ;Test console input
endif
PCHL ;GOTO TABLE ROUTINE
DISP2: POP B ;Restore caller's regs (except psw)
POP H
POP D
RET
CONST: ;IF(CONSOLE RDY) THEN RETURN (NZ)
if TYPEAHEAD
LDA ICOUNT
ORA A
endif
if not TYPEAHEAD
IN CSTAT ;IF (RX CHAR RDY) DO
ANI 2
endif
DB JRNZ,CONST1-$-1
RET
AUTST: CALL CONST
RNZ
MODST: IN MSTAT ;RETURN (MODEM STATUS)
ANI 2
RZ
CONST1: ORI 0FFH
RET
CONIN: CALL FLUSH ;FLUSH BUFFER
if TYPEAHEAD
CALL TESTI
LXI H,ICOUNT ;IF (CON CHAR NOT RDY) GOTO CONIN
MOV A,M
ORA A
DB JRZ,CONIN-$+0FFH
DCR M
LXI H,ICHARQ+1; ELSE DO
LXI D,ICHARQ
MOV C,A
MVI B,0
LDAX D ; A=CHAR
DW LDIR ; DROP QUEUE
endif
if not TYPEAHEAD
IN CSTAT ;IF (CON CHAR NOT RDY) GOTO CONIN
ANI 2
DB JRZ,CONIN-$+0FFH
IN CDATA ;ELSE RETURN (A=CHAR AND 7FH)
endif
ANI 7FH
RET
if TYPEAHEAD
TESTI: IN CSTAT ;IF (RX CHAR RDY) DO
ANI 2
RZ
LDA ICOUNT ; IF (QUEUE<QSIZE) DO
CPI QSIZE
RNC
INR A ; QUEUE.COUNT++
STA ICOUNT
PUSH H ; QUEUE||RX CHAR
LXI H,ICHARQ-1
ADD L
MOV L,A
DB JRNC,TEST0-$-1
INR H
TEST0: IN CDATA
MOV M,A
POP H
RET
endif
AUTIN: CALL FLUSH
AUTIN1:
if TYPEAHEAD
CALL TESTI
endif
CALL CONST
DB JRNZ,CONIN-$+0FFH
CALL MODST
DB JRZ,AUTIN1-$+0FFH
MODEMIN:CALL FLUSH
IN MSTAT
ANI 02H
DB JRZ,MODEMIN-$+0FFH
IN MDATA
RET
CONOUT: IN CSTAT ;OUTPUT (C) TO CONSOLE
RAR
DB JRNC,CONOUT-$+0FFH
MOV A,C
OUT CDATA
RET
AUTOUT: CALL CONOUT
MODEMO: IN MSTAT ;OUTPUT TO MODEM
RAR
DB JRNC,MODEMO-$+0FFH
MOV A,C
OUT MDATA
RET
XONXOFF: ;START OF X-ON X-OFF
IN LDATA
ANI 1FH ;MASK MSB'S
CPI 13H ;CHECK FOR X-OFF
DB JRNZ,XONX2-$-1 ;IF NOT THEN OUTPUT CHAR
XONX1: ;IF SENT THEN WAIT FOR X-ON
IN LDATA
ANI 1FH ;MASK MSB'S
CPI 11H ;X-ON CHAR ?
DB JRNZ,XONX1-$+0FFH;IF NOT GOBACK
XONX2: IN LSTAT
ANI 81H ;SEND CHAR
CPI 81H
DB JRNZ,XONX2-$+0FFH
MOV A,C
OUT LDATA
RET
PLLPRN: ;PARALLEL PORT DRIVER
MVI A,81H
OUT 0D3H ;8255 CONTROL PORT
PLLP1: CALL PLLRDY
DB JRNZ,PLLP1-$+0FFH;LOOP UNTIL READY
MOV A,C
OUT 0D1H ;OUTPUT DATA TO PORT B
MVI A,0BH
OUT 0D3H ;STROBE
DCR A
OUT 0D3H
RET
PLLRDY: IN 0D2H ;Parallel Printer Ready
ANI 4 ;04H==busy, 00=ready
RZ ;Return 0==ready
ORI 0FFH
RET ;Return 0FFH==not ready
ETXACK: IN LSTAT
RAR
DB JRNC,ETXACK-$+0FFH
MOV A,C
OUT LDATA
LXI H,PCOUNT
DCR M
RP
MVI M,80H
MVI C,3
CALL ETXACK
ACKCHK: IN LSTAT
ANI 2
DB JRZ,ACKCHK-$+0FFH
IN LDATA
ANI 7FH
CPI 6
DB JRNZ,ACKCHK-$+0FFH
RET
NULLIN: MVI A,1AH ;NULL INPUT DEVICE - RETURN CONTROL-Z
NULLOUT:RET ;NULL OUTPUT DEVICE
;*****************************************************************
;CLOCK READ/WRITE ROUTINES
;*****************************************************************
RCLOCK: LXI H,PASSADD
DCR M ;DECREMENT PASS COUNTER(RANGE:15H-0-0FDH)
MOV A,M
CPI 0DH ;CHECK TO SEE IF AT BEGINNING
JM RCLOC1
MVI A,' ' ;IF NOT, RET WITH A SPACE
RET
RCLOC1: ORA A ;CHECK TO SEE IF ALL PASSES
JP RCLOC2 ; COMPLETED
CPI 0FEH
MVI A,' ' ;(RETURN {'.',' ',CR} AFTER STRING)
RZ ; (2ND CHAR AFTER)
MVI A,'.'
RNC ; (1ST CHAR AFTER)
MVI M,15H
MVI A,0DH ; (3RD CHAR AFTER)
RET
RCLOC2: MVI A,40H
OUT 0CCH ;TURN ON CLOCK
MVI B,78H
RCLOC3: DB DJNZ,RCLOC3-$+0FFH ;WAIT
MOV A,M
;CONVERT PTR=(12-0) TO (10,9,8,7,12,11,6-0)
CPI 7 ;THIS MAKES DATA ORDER=MMDDYYwHHMMSS
DB JRC,RCLOC4-$-1 ;MUCH MORE CONVENIENT TO USE
SUI 2 ;
CPI 7 ;
DB JRNC,RCLOC4-$-1
ADI 6 ;
RCLOC4: ORI 0C0H ;CONVERT TO CLOCK CHIP I/O PORT#
MOV C,A ;SET UP OUTPUT ADDRESS
MVI A,50H
DW OUTCA ;TOGGLE CLOCK
DW INAC
CALL SWAP ;FLIP THE BITS
ADI 30H
PUSH PSW
XRA A
OUT 0C0H ;RESET CLOCK
POP PSW ;RETURN WITH DATA IN ACC.
RET
WCLOCK: LXI H,CLKDIR
MOV A,C ;IF (CHAR < '0') THEN RETURN
ANI 07FH
SUI '0'
RC
CPI 9+1+1 ;IF (CHAR < '9'+1) THEN DO
DB JRNC,WCLK2-$-1 ; (NOTE: '9'+1=':', NEEDED FOR 24 HR MODE SET)
CALL SWAP
MOV B,A
MOV A,M ;IF ('DIRECTOR' < 'A') THEN RETURN
CPI 'A'-40H
RC
CPI 'M'+1-40H;IF ('DIRECTOR' > 'M') THEN RETURN
RNC
DCR A
CPI 6
DB JRNC,WCLOC0-$-1
ADI 2
CPI 6
DB JRC,WCLOC0-$-1
SUI 6
WCLOC0: INR A
MOV C,A
MVI A,40H
OUT 0C0H ;ISSUE HOLD COMMAND
MVI A,0BFH+14;PORT BASE ADDRESS
SUB C ;ADD ADDRESS TO BASE PORT
MOV C,A ;('A'=13, 'M'=1)
MOV A,B
MVI B,62+6 ;HOLD 200uS (+10% MARGIN)
TIML1: DB DJNZ,TIML1-$+0FFH
ADI 40H ;SET UP ADDRESS
DW OUTCA ;OUT (C),A
XTHL
XTHL ;DELAY
ORI 20H ;TURN ON WRITE
DW OUTCA
XTHL
XTHL ;DELAY
ANI 4FH ;TURN OFF WRITE
DW OUTCA
XRA A
OUT 0C0H ;TURN OFF CLOCK
INR M ;RESET DIRECTOR
RET
WCLK2: CPI 'A'-'0'
RC ;RETURN IF < ASCII "A"
CPI 'M'-'0'+1
RNC ;RETURN IF > ASCII "M"
ANI 0FH ;STRIP OFF ASCII
MOV M,A ;STORE DIRECTOR
RET
SWAP: MOV B,A
XRA A ;SWAP BITS 0-4,1-3
CALL SWAP1
SWAP1: DW RRCB
RAL
DW RRCB
RAL
RET
if P2DOS
;Set Time c==0FFH, de == &buffer:
; NDAYS: DW 0 ;(binary count) #days since 1/1/1978
; HOURS: DB 0 ;(in BCD) 0000H<=ndays<=0FFFFH,
; MINUTE: DB 0 ;(in BCD) i.e. only 1978-2157,
; SECOND: DB 0 ;(in BCD) 179 years.
;Get Time c==00H; return hl == &buffer
;Note: calls to rclock return mmddyyWhhmmss
; pm: hx D2==1, 24: hx D3==1, leap: dx= D2==1
BTIME: INR C
RC ;Cannot set time (yet?)
GTIME: MVI A,0DH ;synchronise rclock
STA PASSADD
LXI D,TBUFMO ;read clock information into buffer
MVI B,13
GTIME2: PUSH B
CALL RCLOCK
POP B
ANI 0FH
STAX D
INX D
DB djnz,GTIME2-$+0FFH
GTIME3: MVI A,15H ;reset rclock
STA PASSADD
;days = day_of_month-1;
LXI H,TBUFYR ;for(yr -= 1978; yr>0; --y)
CALL PAKBIN ; days += 365 + leap(yr);
SUI 78 ;(We assume 1900s here, subtract just 0078)
MOV B,A ;(b = p2dos year)
PUSH B ;(save b for later calculations)
LXI H,TBUFDY
DW res2hl ;(clear "leap year" bit from clock chip)
CALL PAKBIN ;(init hl = day of month - 1)
DCX H
LXI D,365
GTIME4: DCR B
JM GTIME5
DAD D
CALL LEAP
DB jrnz,GTIME4-$+0FFH
INX H
DB jr,GTIME4-$+0FFH
GTIME5: POP B ;(restore b=year#)
XCHG ; m = mon-1; while (m-- > 0)
LXI H,TBUFMO ; day += md[m] + (m == 1 && leap (y));
CALL PAKBIN
DCR A
MOV C,A ;(b=year,c=month,de=day,hl->md[m])
LXI H,MD-1
ADD L
MOV L,A
DB jrnc,GTIME6-$-1
INR H
GTIME6: DCR C
JM GTIME9
MOV A,M
DCX H
ADD E
MOV E,A
DB jrnc,GTIME7-$-1
INR D
GTIME7: MOV A,C ;(is month == 1?)
DCR A
DB jrnz,GTIME6-$+0FFH
CALL LEAP ;(yes, now is it a leap year?)
DB jrnz,GTIME6-$+0FFH
INX D ;(yup, increment #days by 1)
DB jr,GTIME6-$+0FFH
GTIME9: ;Save number of days since 1/1/1978
XCHG
SHLD P2NDAY
LXI D,P2HR
LXI H,TBUFHR
DW res3hl
DW res2hl
CALL PAKBCD
CALL PAKBCD
CALL PAKBCD
LXI H,P2NDAY
RET
PAKBCD: MOV A,M ;Pack two successive bcd bytes into bcd byte
RLC
RLC
RLC
RLC
INX H
ADD M
INX H
STAX D
INX D
RET
;leap - Return Z if p2dos year is a leap year, NZ otherwise.
; year 1978 = p2dos year 0, and maximum p2dos year = 2157
LEAP: MOV A,B ;B = years since 1978
; CPI 122 ; if (y = 122) return (NZ) /*year 2100*/
; DB jrz,LEAP1-$-1
ADI 2 ;correction needed: year 2 is leap year, year 0 is not
LEAP1: ANI 3 ; return (y % 4)
RET
MD: DB 31,28,31,30,31,30,31,31,30,31,30 ;Don't need December
;Pack two successive bytes into binary word
PAKBIN: MOV A,M
RLC
RLC
ADD M
RLC
INX H
ADD M
MOV L,A
MVI H,0
RET
endif
;*************************************************************
; End of I/O routines
;*************************************************************
RNMSG: DB 'ID NOT FOUN','D'+80H
CRCMSG: DB 'CR','C'+80H
LDMSG: DB 'LOST DAT','A'+80H
BSYMSG: DB 'BUS','Y'+80H
WPMSG: DB 'PROTEC','T'+80H
WFMSG: DB 'FAUL','T'+80H
NRMSG: DB 'READY'
ERRMSG: DB ' ERRO','R'+80H
BTMSG: DB 'BOOT',' '+80H
RDMSG: DB 0DH,0AH,'READ',' '+80H
WTMSG: DB 0DH,0AH,'WRITE',' '+80H
SKMSG: DB 0DH,0AH,'SEEK',' '+80H
HEMSG: DB 0DH,0AH,'HOME',' '+80H
if not ONLY2
SWMSG: DB 0DH,0AH,'insert '
SWDSK: DB '?: disk then key retur','n'+80H
endif
;********************************************************
;PRE-INITIALIZED DATA VARIABLES:
; These items are set to initial values when loaded
; during cold-load.
;********************************************************
; Error counts. These locations keep track of the number
; of errors occurring during Read, Write, or Seek.
RECNT: DB 0 ;READ ERROR COUNT.
WECNT: DB 0 ;WRITE ERROR COUNT.
SECNT: DB 0 ;SEEK ERROR COUNT.
ERFLAG: DB 0 ;CPM BLOCKING ERROR FLAG
SIDEFLG: DB 0 ;HEAD 2 SELECT FLAG (0=SIDE 1, NZ=SIDE 2)
TRTAB: DB 0FFH,0FFH,0FFH,0FFH ;TRACK TABLE: PRESENT HEAD POSITION
;FOR FOUR DRIVES.
PASSADD:DB 15H ;PASS COUNT & CLOCK REG PTR
CLKDIR: DB 00H ;CLOCK DIGIT 'DIRECTOR'
CURDSK: DB 0 ;Currently Selected Disk (Init=A:)
UNACNT: DB 0 ;Blocking - Unallocated Record count
HSTACT: DB 0 ; - Hostbuffer Active flag
HSTWRT: DB 0 ; - Hostbuffer Write Pending flag
if TYPEAHEAD
ICOUNT: DB 0 ;INPUT QUEUE - number of characters
endif
if USER0
CHKUSR0: CALL CCGTUSR ;Get current user number
ORA A
JZ CCERR ;If already 0, print error message
MOV E,A ;Save user number
PUSH D
MVI E,0 ;Set user = 0
CALL CCSTUSR
CALL CCOPFCB ;Try to open file
POP D
PUSH PSW ;Restore user number
CALL CCSTUSR
POP PSW
JNZ CCLOAD ;If file found, get it
JMP CCERR ;Else print error
endif
;********************************************************
HSTBUF: ;Start of Host-Buffer (For 1 physical sector) *
;Reserve HSTSIZ bytes *
;The Cold-Boot routine here will be overwritten *
;********************************************************
BOOT: LXI H,WBOOT ;RE-DIRECT CBOOT TO WBOOT
SHLD CBOOT+1
LXI SP,7FH ;SET STACK POINTER.
MVI A,0A6H ;INIT 8251 I/O PORTS
CALL INITSIO
MVI A,40H
CALL INITSIO
LDA UARTT
OUT CSTAT
LDA UARTP
OUT LSTAT
LDA UARTM
OUT MSTAT
MVI A,27H
CALL INITSIO
MVI A,PPINIT;INIT 8255
OUT PPCMD
if not NOREVA
MVI A,41H ;TEST IF 8255 IS PRESENT
CALL TESTB ;IF SO, THIS IS REV B BOARD
CMA ;(TEST TWICE, TO BE SURE)
CALL TESTB ;
endif
XRA A ;SET DISK SELECT TO A: & USER# TO 0
STA SEKDSK
STA CDISC
LXI H,SYSFMT;INIT IOBYTE &SYSFMT
MOV A,M
ANI 4
RAR
RAR
MOV C,A
LDA IOBYTA
MOV B,A
ANI IOBMSK
ORA C
STA IOBYTE
MOV A,B
ANI SYSMSK
ORA M
MOV M,A
LXI H,SMSG ;PRINT OPENING MESSAGE.
CALL PMSG
LDA 07FH ;DISK OPTIONS: (temp addr. of density flag)
LXI H,VDD ; DBL-D
CPI 0DDH
DB JRZ,DEN1-$-1
LXI H,VDSD ; DBL-SD (always DBL-D)
CPI 0D0H
DB JRZ,DEN1-$-1
LXI H,VSD ; SINGL-D
DEN1: CALL PMSG
if not ONLY2
MOV A,B
ANI 1 ;DRIVE OPTIONS:
endif
LXI H,V2D ; 2DRIVE
if not ONLY2
DB JRZ,STAT2-$-1
LXI H,V1D ; 1DRIVE
endif
STAT2: CALL PMSG
MOV A,B ;PRINTER OPTIONS:
ANI 0C0H
LXI H,VPLL ; PARALLEL
DB JRZ,STAT5-$-1
CPI 80H
LXI H,VEA ; ETX-ACK
DB JRZ,STAT6-$-1
LXI H,VXO ; XON/XOFF OR NO
DB JRC,STAT7-$-1; CONSOLE, SAY NOTHING
STAT5: CALL PMSG
LXI H,PROTCL;'PRINTER PROTOCOL'
STAT6: CALL PMSG
if ZCPR3
LXI H,ENDISK-1 ;Clear rest of memory
LXI D,ENDISK
LXI B,0FFFFH-ENDISK+1
DW LDIR
endif
STAT7:
if P2DOS and ZCPR3
JMP P2CBT ;Do extra initialisation for P2DOS/ZCPR3
endif
if (not P2DOS) or (not ZCPR3)
JMP GOCPM
endif
INITSIO:
OUT CSTAT
OUT LSTAT
OUT MSTAT
RET
if not NOREVA
TESTB: MOV B,A ;TEST 8255 PORT B WITH BYTE IN A:
OUT PPORTB ; OUTPUT BYTE TO PORT.
IN PPORTB ; READ BACK IN.
CMP B ; IF SAME, TEST PASSES, RETURN.
RZ ;
MVI A,REVA ; ELSE CHANGE FLAG TO 'A' AND RETURN.
STA CPUREV ; (NOTE: FLAG IS IN SIGN-ON MESSAGE)
RET
endif
SMSG: DB CR, LF, LF, 'ACI '
DB MSIZE/10+'0', MSIZE MOD 10 +'0', 'K '
if P2DOS
DB 'P2DOS'
endif
if not P2DOS
DB 'CP/M'
endif
DB ' v'
DB REVNO/10+'0', '.', REVNO MOD 10 +'0'
if not NOREVA
CPUREV: DB 'B'
endif
if IBMB
DB 'I'
endif
if USER0
DB 'U'
endif
CRLF: DB CR,LF+80H
if not ONLY2
V2D: DB '2 drive,',' '+80H ;DRIVE OPTIONS
V1D: DB '1 drive,',' '+80H ;
endif
if ONLY2
V2D: DB '2 drive only,',' '+80H ;
endif
VPLL: DB 'PARALLE','L'+80H ;PRINTER OPTIONS
VXO: DB 'XON/XOFF(or NO',')'+80H ;
VEA: DB 'ETX/ACK' ;
PROTCL: DB ' printe','r'+80H ;
VSD: DB 'Single density,',' '+80H ;DISK OPTIONS
VDD: DB 'Double density,',' '+80H ;
VDSD: DB 'Double side,',' '+80H ;
if ZCPR3
DB 0 ;byte to clear mem to.
endif
ENDISK: ;End of CP/M image required to be stored on disk.
;************************************************************************
if not ((HSTSIZ-($-HSTBUF)) SHR 15)*TRUE ;If not enough *
DS (HSTSIZ-($-HSTBUF)) ;space is used, *
endif ;reserve it *
;************************************************************************
;****************************************************************
; THE REMAINDER OF THE CBIOS IS RESERVED UNINITIALIZED
; DATA AREA, AND DOES NOT NEED TO BE A PART OF THE
; SYSTEM MEMORY IMAGE (THE SPACE MUST BE AVAILABLE,
; HOWEVER AS SCRATCH RAM AREA FOR BDOS USE). INITIALIZATION
; IS DONE FOR 'CONVENIENCE', AND IS SET TO PROBABLY
; CORRECT VALUES (FOR SINGLE-DENSITY DISKS).
;****************************************************************
ERCNT: DB 0 ;ERROR COUNT FOR RETRIES.
SERCNT: DB 0 ;SEEK RETRY COUNTER.
SEKDSK: DB 0 ;CURRENTLY REQUESTED DISK. *DON'T
SEKTRK: DW 0 ;CURRENTLY REQUESTED TRACK. *RE-ARRANGE
SEKHST: DB 1 ;CURRENTLY REQUESTED HOST SECTOR*
SEKSEC: DB 1 ;CURRENTLY REQUESTED SECTOR. *
HSTDSK: DB 0FFH ;HOSTBUFFER DISK. *DON'T
HSTTRK: DW 0FFFFH ;HOSTBUFFER TRACK. *RE-ARRANGE
HSTSEC: DB 0FFH ;HOSTBUFFER SECTOR. *
DB 0FFH ;not used, reserved *
UNADSK: DB 0 ;LAST UNALLOCATED DISK. *DON'T
UNATRK: DW 0 ;LAST UNALLOCATED TRACK. *RE-ARRANGE
DB 0 ;not used, reserved *
UNASEC: DB 0 ;LAST UNALLOCATED SECTOR. *
CPMSPB: DB 8 ;BLOCKSIZE/128 *******BLOCKING PARMS********
SECMSK: DB 0 ;HSTSIZ/128-1 ** DON'T RE-ARRANGE **
SECSHF: DB 0+1 ;LOG2(HSTSIZ/128)+1 **PARMS ARE FOR LOGGED DISK**
CPMSPT: DB 26 ;TRACKSIZE/128 *****************************
LOGDEN: DB 2 ;DENSITY OF LOGGED DRIVE (2=SGL,1=DBL)
RSFLAG: DB 0 ;READ SECTOR FLAG
READOP: DB 0 ;READ OPERATION FLAG
WRTYPE: DB 0 ;WRITE OPERATION TYPE
DMAADD: DW 0080H ;CURRENT READ/WRITE ADDRESS.
PCOUNT: DB 80H ;COUNTER FOR ETXACK:
if TYPEAHEAD
ICHARQ: DS QSIZE ;INPUT CHARACTER QUEUE
endif
DIRBF: DS 128 ;SCRATCH DIRECTORY AREA
ALL00: DS 39 ;ALLOCATION VECTOR 0
ALL01: DS 39 ;ALLOCATION VECTOR 1
CHK00: DS 128/4 ;CHECK VECTOR 0
CHK01: DS 128/4 ;CHECK VECTOR 1
ADDRBF: DS 7 ;READ ADDRESS BUFFER (1 EXTRA BYTE RESERVED)
if P2DOS
;data buffer for P2DOS time function - doesn't need initialization
TBUFMO: DB 0,1 ;month
TBUFDY: DB 0,1 ;day
TBUFYR: DB 7,8 ;year
DB 0 ;day of week (Sunday)
TBUFHR: DB 0,0 ;hours 12-1-11 am, 52-41-51 pm
TBUFMI: DB 0,0 ;minutes
TBUFSC: DB 0,0 ;seconds
P2NDAY: DW 0 ;#days since 1/1/78
P2HR: DB 0 ;bcd hours
P2MIN: DB 0 ;bcd minutes
P2SEC: DB 0 ;bcd seconds
endif ;P2DOS
if ZCPR3
;This area needs to be cleared to all zeros on coldboot, with exceptions
;noted (and initialized by CBOOT. ZCPR3 must have these addresses defined
;in Z3BASE.HDR, exactly as they appear here.
;ZCPR3 Shell Stack
SHSTK: DS 4*32
;ZCPR3 Message Buffer
Z3MSG: DS 80
;80 byte command buffer for ZCPR3. Set Z3CL and Z3CLS (=80) in Z3BASE.HDR.
Z3CL: DW 0 ;(Must be initialized to Z3BF by CBOOT)
Z3SIZ: DB 0 ;(Must be initialized to 80 by CBOOT)
Z3CT: DB 0
Z3BF: DS 80
;Named directory buffer for ZCPR3. Set Z3NDIR and Z3NDIRS (=14) in Z3BASE.
Z3NDIR: DS 14*18 + 1
;External Stack for ZCPR3. Set EXTSTK in Z3BASE. Always uses 48 bytes.
EXTSTK: DS 48
;External FCB for ZCPR3. Set EXTFCB in Z3BASe. Always uses 36 byes.
EXTFCB: DS 36 ;(Could this be put in the end of P2DOS also?)
endif ;endif ZCPR3
if P2DOS
;External Stack for P2DOS. Set P2STK in P2DOS.MAC. Uses 62 bytes (v23)
P2STK: DS 62
endif ;endif P2DOS
if ZCPR3
ORG 0FF00H
;External ZCPR3 Environment
;Because this holds the pointers to the other data areas, this gets fixed
;at top of memory. It is initialized by the loader LDR.
Z3ENV: DS 2*128
endif ;endif ZCPR3
ORG BIOS-115 ;Overlay code on top of P2DOS blank area
;Only 115 bytes are available in P2DOS v23.
;Note: P2DOS MUST have external stack.
if P2DOS and ZCPR3
;ZCPR3 External Command Executive Name (CMDRUN option)
EXTRUN: DB 0 ;(A0:?)
DB 'CMDRUN '
DB 'COM'
;ZCPR3 External Search Path
EXTPATH: DB '$$' ;This drive, this user#
DB '$',0 ;This drive, user 0
DB 1,0 ;Drive A: user 0
DB 0
;ZCPR3 External Submit File FCB:
;EXTSUB in Z3BASE.LIB must be set either to the value given here for SUBFCB,
;or to zero. BE VERY SURE you aren't using this area for the ZCPR stack. The
;part of this that is commented out does not need to be initialised, there-
;fore it overlays the cold-boot code that may follow.
P2CWBT: LXI H,0 ;Clear Submit FCB
SHLD SUBEXT
JMP CCP
EXTSUB: DB 1 ;Default Drive A:
DB '$$$ ' ;Submit filename
DB 'SUB' ;Submit filetype
SUBEXT:
endif ;P2DOS and ZCPR3
if FALSE ;(force it to overlay)
DB 0 ;Extent number - clear this on warmboot
DB 0 ;s1
SUBFS2: DB 0 ;s2
SUBFRC: DB 0 ;record count
DS 16 ;Disk Group Map
SUBFCR: DS 1 ;Current Record Number
endif ;FALSE
if P2DOS and ZCPR3
;ZCPR3 Command Line Initialisation:
;Because this code is used during coldboot only, which precedes the use of
;either the Submit facility or ZCPR3, this code will be overlayed by the
;Submit FCB area from below, and possibly by the ZCPR3 Stack from above.
P2CBT: LXI H,Z3CNIT
LXI D,Z3CL
LXI B,P2CBTE-Z3CNIT
DW LDIR
JMP GOCPM ;Resume coldboot initialisation
Z3CNIT: DW Z3BF ;Command Line image, must be same size as Z3CL
DB 80 ;80 characters
DB 0 ;Character count
DB 'LDR SYS.ENV,SYS.NDR' ;coldboot command
P2CBTE:
endif ;ZCPR3 and P2DOS
ACIDOS EQU (ENDISK+OFFSET+0FFH)/100H ;'SAVE xx ACIDOS.COM'
END