PAGE ; B o o t C P / M f r o m d i s k. ; ; The CBOOT entry point gets control from the cold start ; loader and is responsible for the basic system initial- ; ization. This includes outputting a sign-on message and ; initializing the following page zero locations: ; ; 0 .. 3FF = Interrupt traps ; 380..383 = Irupt 224 for BDOS entry. ; 400..40F = (reserved for debuggers) ; ; Register CL must contain the selected drive, which is ; zero to select the A drive. The exit address is to ; the CCP routine. ; ; The WBOOT entry point gets control when a warm start ; occurs, a ^C from the console, a jump to BDOS (function ; 0), or a jump to location zero. The WBOOT routine does ; only a flush call to the deblocker. ; ; Entry CS= set by far jump. ; 40: (Set by BOOT) Board switch options. ; Exit to CCP or LDCPM ; (0:08) = Banger parameters ; (0:0A) = Board switch options. ; CCP+8 is MFORM M! command line. ; Cold boot exit is to CCP and Warm boot exit ; is to CCP+6 to skip "auto-vector". ; ; Disk layout Definition. ; Cylinder 0 Head 0 ; 0 thru 3 Boot program ; 4 thru 23 Reserved for CBIOS ; 24 Group header of LOADER.CMD ; 25 RESTART code loaded at FFF8:0080 ; ; 256 byte sectors -- Cylinder 1 Head 0: ; 0 thru 3 LDCPM ; 4 thru 17 LDBDOS ; 18 thru 25 **Reserved for CP/M expansion** ; ; 512 byte sectors -- Cylinder 1 Head 0: ; 0 thru 3 CCP ; 4 thru 11 BDOS ; 12 thru 15 **Reserved for CP/M expansion** ; ; 1024 byte sectors -- Cylinder 1 Head 0: ; 0 thru 1 CCP ; 2 thru 5,7 BDOS ; 6 **Reserved for CP/M expansion** space 4,10 REUSE EQU $ ;This space can be reused after cold boot ; Cold Start. CBOOT: proc MOV AX,CS ;Get code segment MOV ES,AX MOV SS,AX LD SP,#STACKP ;top of system space (temp. stack) CLD ;clear direction to forward XOR CX,CX MOV DS,CX LD BL,OPTS ;fetch board option switches MOV DS,AX STO BL,OPT_SW STO AX,DMASEG STO AX,BUFSEG ld ax,#sysend mov es,ax sto es,mrt+1 ld bx,#0 sizelp $es ld cl,[bx] $es stob #0,[bx] $es ld ch,[bx] $es sto cl,[bx] mov ax,es inc ax mov es,ax or ax,ax jz sizel1 or ch,ch jz sizelp sizel1 mov ax,es sub ax,#sysend+1 sto ax,mrt+3 mov ax,cs mov es,ax .hdrv IF HDRIVE ;size M-DRIVE/H board LD CL,#0FFH ; LD BX,#0FFF0H ;Use top of M-DRIVE/H board MSIZLP: ADD CL,#08 ;8 sectors per board MOV AL,CL CALL SET ;Go set M-DRIVE/H board INB HDATA ;get a byte MOV AH,AL ;Save the byte MOV AL,CL ;Get current count CALL SET XOR AL,AL ;CLEAR A OUTB HDATA ;out to memory drive MOV AL,CL ;Get Highest byte for set CALL SET ; INB HDATA ;Try and get a 0 CMP AL,#0 ;Was it 0 JNE SETDPB ;If so then done MOV AL,CL CALL SET MOV AL,AH ;Get saved byte OUTB HDATA ;And restore it CMP CL,#64-1 ;Max 8 boards (8*8=64) JNE MSIZLP ;And try for next board ADD CL,#8 ;For special case of 8 boards ; SETDPB: MOV AL,CL ;CL has # Sectors/track AND AL,#0111_1000B ; CMP AL,#8 ;There is one board JL NOBORD ;Table is OK JE SZDONE ;Else one board LD AH,#0 ; STO AX,DPBHMD+1 ;Set #sectors/track MOV CH,CL ;Save CL LD CL,#3 ;Shift 3 bits SHR AL,CL ; LD DX,#254 ;DSM is (# boards * 254) -1 MUL DX ; DEC AX ; and -1 STO AX,DPBHMD+6 ;Set DSM CMP CH,#32 ;If big M-DRIVE JL SETEXM ;if not go set EXM STO #256-1,DPBHMD+8 ;Set #dir entries STO #REV (0F000H),DPBHMD+10 ;Set reserved blocks SETEXM: STOB #0,DPBHMD+5 ;Set EXM to 0 JMP SZDONE NOBORD: LD AL,#0 ;Set no M drive STO AL,DSKMSK+('M'-'A') ; STO AL,DPBHMD+1 ;Set 0 SPT if no M drive SZDONE: .hdrv ENDIF .i1 IF INTER1 LD BL,OPT_SW CMP BL,#0 JNZ CBOOT3 ;If Interfacer 1 not selected LD SI,#J.I1ORG LD DI,#J.CST LD CX,#JLI1ORG REP MOVSB LD AX,#LISTST-J.LST-3 STO AX,J.LST+1 JMP CBOOTX CBOOT3: .i1 ENDIF LD BL,OPT_SW CMP BL,#1 JE CBOOT4 ;if BitBanger selected default to SYSTEM SUPPORT .s IF SMORG LD BL,OPT_SW CMP BL,#2 JNZ CBOOT5 ;If System support not selected CBOOT4: LD SI,# J.SMORG LD DI,# J.CST LD CX,# JLSMORG REP MOVSB LD AX,#I3LST-J.LST-3 STO AX,J.LST+1 .ldr IF @LDR CALL STINIT ;Initialize System Support CALL I3INIT ;INITIALIZE I/O 3 FOR LIST .ldr endif JMP CBOOTX CBOOT5: .s ENDIF .i3 IF INTER3 LD BL,OPT_SW CMP BL,#3 JNZ CBOOT6 ;If Interfacer 3 not selected LD SI,# J.I3ORG LD DI,# J.CST LD CX,# JLI3ORG REP MOVSB LD AX,# I3LST-J.LST-3 STO AX,J.LST+1 .ldr IF @LDR CALL I3INIT ;Initialize Interfacer 3 .ldr endif ; JMP CBOOTX CBOOT6: .i3 ENDIF CBOOTX: .ldr IF @LDR CALL SINTDIS ;Initialize 8259a's mask all interupts LD CX,#ZSEG MOV DS,CX ;Need to move to absolute low RAM STO #BDOSE,STRAP ;set BIOS interrupt vector MOV AX,CS STO AX,STRPSG ;BDOS code segment same as ours MOV DS,AX ;restore DataSeg LD BX,#SIGNON CALL PRINT ;display signon CALL BCPM ;load LOADER.CMD XOR CX,CX ;default drive JMP CCP+3 .ldr else ;Full BIOS coldstart tasks XOR AX,AX ;AX = 0 STO AL,IOBYTE MOV DS,AX ;Need to move to absolute low RAM MOV ES,AX STO #ITRAP,0 STO CS,2 LD DI,# 4 LD SI,# 0 LD CX,# 2*(256-1) REP ;propagate Trap to all 256 vectors MOVS STO #BDOSE,STRAP ;set BIOS interrupt vector MOV AX,CS MOV DS,AX ;restore segment regs MOV ES,AX ;Print signon messages mdrive size and memory size LD BX,#BEGIN CALL PRINT IF HDRIVE LD BX,#CRLF CALL PRINT ;Print some crlf's LD AX,DPBHMD+1 ;Get sectors per track CMP AX,#0 ;See if there is an MDRIVE JE NOMDRV ;If no mdrive LD CX,#64 MUL CX ;* 64 to make K message LD BX,#10 ;Base for conversion routine CALL PUTN ;Print and convert to ASCII LD BX,#KMESG ;And print rest of message CALL PRINT ; JMP PMEM NOMDRV: LD BX,#NOMDMS ;Print no memory drive message CALL PRINT ; PMEM: LD BX,#MEMMSG ;Memory message CALL PRINT LD AX,MRT+3 ADD AX,#SYSEND+1 LD BX,#MEGMSG ; CMP AX,#0H ;Special case of 1 meg JE PMEM1 ;If one megabyte LD CX,#6 ;6 bits is 1k SHR AX,CL LD BX,#10 ;Base for conversion CALL PUTN ;Convert to ASCII and print LD BX,#PRNTK ; PMEM1: CALL PRINT LD BX,#CRLF CALL PRINT IF DISK3 CALL D3INIT ;Must set up IOPB and warm up DISK3 ENDIF XOR CX,CX ;CX = 0 JMP CCP ;Enter Console Command Processor and ;execute anything in auto-vector. ENDIF BEGIN: DB CLRSCR, CR,LF ;Send clear screen to home CSIGN: DB 'CompuPro CP/M ';This string must stay as is!! IF CPM816 DB '8-16' ELSE DB '86' ENDIF db ' ',vers/10+'0','.',vers mod 10 + '0' db cbiosv+'@' db cbiosh+'@' DB 0 KMESG: DB 'K M-DRIVE/H Active as Drive "M".',CR,LF IF HARD IF gbc10 db '10' ENDIF IF gbc20 db '20' endif .D3 IF DISK3 IF ST506 DB '5' ENDIF IF Q540 DB '40' ENDIF .D3 ENDIF db ' Megabyte Hard Disk Active as Drive' IF ORDER = 0 if gbc10 db 's C and D.' endif if gbc20 db 's C, D and E.' endif .D3 IF DISK3 IF ST506 db ' C.' ENDIF IF Q540 DB 's C, D, E, F and G.' ENDIF .D3 ENDIF ENDIF IF ORDER =1 if gbc10 db 's A and B.' endif if gbc20 db 's A, B and C.' endif if ST506 db 's A.' endif if Q540 db 's A, B, C, D and E.' endif ENDIF db cr,lf ENDIF if HARD DB '2 ' endif if not HARD db '4 ' endif db '8-inch Floppies Active as Drives ' if Hard and (order=1) if gbc10 db 'C and D.' endif if gbc20 db 'D and E.' endif if st506 db 'B and C.' endif if Q540 db 'F and G.' endif else if hard and (order = 0) db 'A and B.' else db 'A, B, C and D.' endif endif ;CRLF is end of signon message CRLF: DB CR,LF,CR,LF,0 MEMMSG: DB 'Total Memory: ',0 PRNTK: DB 'K',0 MEGMSG: DB '1 MEGABYTE',0 NOMDMS: DB 'NO M-DRIVE/H Active',0AH,0DH,0 .ldr endif .i1 if inter1 j.i1org: loc j.cst jmp const jmp conin jmp conout jmp list jmp punch jmp reader loc *o jli1org equ *-j.i1org endif .s IF SMORG J.SMORG: LOC J.CST JMP sCONST JMP sCONIN JMP sCONOUT JMP I3LIST LOC *O JLSMORG = *-J.SMORG .s ENDIF .i3 IF INTER3 J.I3ORG: LOC J.CST JMP I3CONST JMP I3CONIN JMP I3CONOUT JMP I3LIST LOC *O JLI3ORG = *-J.I3ORG .i3 ENDIF SPACE 4,10 ; Boot CPM from disk ; ; Exit A = 0, load sucessful. ; Z bit = 1, load successful. .ldr IF @LDR BCPM: proc :0: LD CL,#'A'-'A' ;Select Disk 'A' LD DX,#0 ;Force disk type determination CALL SELDSK TEST BX,BX JZ :E ;If drive not selectable LD AL,SEKTYP ;Get disk type RCR AL ;Remove sided bit DEC AL JS :E ;If invalid boot type LD CH,#0 ; MOV CL,AL LD BX,#BSECT ;Boot sector table ADD BX,CX LD AL,[BX] ;Get number of sectors STO AL,NUMSEC STO #CCP,DMAADR ;Set destination address MOV AX,CS ;Set segment address = our CS STO AX,DMASEG LD AL,SEKTYP AND AL,#1 ;Mask sided bit ADD AL,#1 LD BH,#0 MOV BL,AL STO BX,SEKTRK ;Set track LD AL,#0 ;Set boot sector STO AL,SAVSEC CALL SETACT ;Move SEK to ACT LD AL,#F.RDAT+040h ;Read data CALL FINAL JNZ :E ;If read erros LD AL,#1 STO AL,NUMSEC XOR AL,AL ;Clear error indicator RET :E: LD BX,#:M CALL PRINT LD CX,#500 CALL DELAY ;Delay 500 milli-seconds OR AL,#1 ;Set error indicator JMP :0 ;try endlessly :M: DB CR,LF,BELCHR DB 'Can''t read Loader!' DB EOS N$DOSL = high (L$CCP+L$DOS+255) BSECT: DB N$DOSL*256/256 ;MFM 256 byte sectors DB N$DOSL*256/512 ;MFM 512 byte sectors DB N$DOSL*256/1024 ;MFM 1024 byte sectors IF HARD db n$dosl*256/1024 ; gbc10, gbc20, gbc26 ENDIF NUMSEC: DB 1 ;xfer length SIGNON: db cr,lf if cpm816 db 'CP/M 8-16 ' else db 'CP/M 86 ' endif db vers/10+'0','.',vers mod 10 + '0' db cbiosv+'@' db cbiosh+'@' db cr,lf db 'Copyright 1982 (C) Digital Research,',cr,lf db ' 1981 (C) Sorcim, and',cr,lf db ' 1982 (C) CompuPro',cr,lf db CR,LF,CR,LF,LF db 'Loading CPM.SYS' db CR,LF,0 space 4,10 .ldr ENDIF page ;********************************************************************* ; ; DISK3 Initialization ; ; This will reset the DISK3 and set it's link to our local iopb, ; send the specify for what ever drives are set to true, ; and home all drives. This D3IOPB is initialized by equates. ; ;********************************************************************* .d3 IF DISK3 D3INIT: PUSH ES ;Save ES LD AX,#0 MOV ES,AX ;Defiopb seg is 0 $ES ! PUSH [DEFIOPB+LINK] ;Save stuff that we will destroy $ES ! PUSH [DEFIOPB+LINK+2] PUSH ES MOV DX,CS ;Get our segment LD AX,#D3IOPB ;Get address of IOPB, DX has our seg CALL ADRCAL ;Make above into 3 byte address. STO AX,[D3IOPB+LINK] ;Set our IOPB to point to itself STO DL,[D3IOPB+LINK+2] $ES ! STO AX,[DEFIOPB+LINK] ;Set default IOPB to point to us $ES ! STO DL,[DEFIOPB+LINK+2]; ; STOB #D3NOOP,[D3IOPB+CMND] ;Do a NOP command to see if d3 exists STOB #BUSY,[D3IOPB+STAT] STOB #0,[D3IOPB+DRV] ;Clear drive byte LD AL,#RESET ;Reset the DISK3 board OUTB D3PORT LD AL,#ATTN ;And send warm up ATTN OUTB D3PORT ; LD CX,#0FFFFH ;If no response by this many times LD AL,#ATTN ; assume no DISK3 OUTB D3PORT D3WT1: CMPB [D3IOPB+STAT],#BUSY LOOPE D3WT1 JNE YESD3 NOD3: LD BX,#NOD3MSG ;Get no disk3 message CALL PRINT JMP EXIT1 YESD3: STOB #D3GLBL,[D3IOPB] ;Set up for global command STOB #0,[D3IOPB+ARG0+1] ;Arg1 sets mode (sectors & tracks) STOB #MRTRY,[D3IOPB+ARG0+2] ;Arg2 is number of retries STOB #4,[D3IOPB+ARG0+3] ;Arg3 is number of drives possible CALL D3EXEC ; ; Loop to home and specify all 4 drives LÄ CX,#NDISK³ ;Geô numbeò oæ driveó oî thå DISK3 SPECD3: DEC CX PUSH CX ADD CL,#'0' ;Add ascii bias for error messages STOB CL,[D3LTR1] ;Set drive number in message STOB CL,[D3LTR2] ; also second message STOB CL,[NOFMTLTR] ;Set ascii number in not formatted message STOB CL,[D3LTR3] ; STOB #00H,[D3PFLG] ;Clear print flag HOMD3: STOB #D3HOME,[D3IOPB+CMND] ;Home drives before using POP AX ! PUSH AX ;Retrieve/save drive number STOB AL,[D3IOPB+DRV] ;Put drive number in drive field XOR AX,AX ;Clear AX STO AX,[D3IOPB+ARG0+1] ;Clear remaining arguments STO AX,[D3IOPB+ARG0+3] STO AX,[D3IOPB+ARG0+5] STO AL,[D3IOPB+ARG0+7] CALÌ D3EXEC LD AL,[D3IOPB+STAT] ;Get status byte in AL CMPB AL,#COMPL ;See if complete JE D3WT4 CMPB AL,#2 ;See if drive not ready JE D3WT6 ;If drive not ready print not ready msg LD BX,#D3BAD ;Fatal disk3 error MESSAGE ADD AL,#'0' ;Add ascii bias to error number STO AL,[D3ERNM] ;Store that in message CALL PRINT JMP D3WT5 ;Goon with next drive ; D3WT6: CMPB [D3PFLG],#0FFH ;See if message printed yet JE D3WT7 ;Only print message once LD BX,#D3NOTRDY ;Print drive not ready message CALL PRINT D3WT7: STOB #0FFH,[D3PFLG] ;Set flag so message is printed only once CALL J.CST ;See if console abort JZ HOMD3 ;Try again until ready or console abort JMP D3WT5 ; D3WT4: LD BX,#CIOPB STOB #1,[BX+0] ;Set command as read POP CX ! PUSH CX ;Recover and restore drive number STOB CL,[BX+1] ;Set drive number STO #0,[BX+2] ;Track 0 STO #1,[BX+4] ;Sector 0 MOV AX,DS STO AX,[BUFSEG] STO #HSTBUF,[BUFADR] ;Read into directory buffer CALL HDFNL ;Perform transfer JZ D3WT10 ;Jump if no error LD BX,#SPECERR CALL PRINT JMP D3WT5 ; D3WT10: MOV AX,DS ;ES has been saved so set = to our MOV ES,AX ;Data seg for movs and compares LD CX,#64/2 ;Get 1st 64 bytes in sector 0 LD SI,#HSTBUF LD DI,#DIRBUF ;Use 1st 64 bytes, stack is 2nd 64 REP ! MOVS ;Move needed data to safe place STO #2,[CIOPB+4] ;Read sector 1,remaining values set CALL HDFNL ;Perform transfer also into HSTBUF JZ D3WT11 LD BX,#SPECERR CALL PRINT JMP D3WT5 ; D3WT11: LD SI,#DIRBUF ;Start is "CompuPro" LD DI,#CSIGN ;Get start of "CompuPro" in signon LD CX,#8 ;CompuPro is 8 bytes long REPE ! CMPSB ;Verify that disk has been formatted JE D3WT8 ;If all 8 compared, disk is formatted LD BX,#NOFMT ;Else Drive not formatted CALL PRINT JMP D3WT5 ;Go do next drive D3WT8: LD AX,#DIRBUF+16 ;Point to specify block MOV DX,CS CALL ADRCAL ;Turn that into a 3 byte number STO AX,[D3IOPB+D3DMA] ;Put in data field STOB DL,[D3IOPB+D3DMA+2] STOB #D3SPEC,[D3IOPB+CMND] ;Use specify command CALL D3EXEC ; LD AX,#HSTBUF ;Get start of badmap MOV DX,CS CALL ADRCAL ;Turn it into a 24 bit number STO AX,[D3IOPB+D3DMA] ;Put in data field STOB DL,[D3IOPB+D3DMA+2] STOB #D3MAP,[D3IOPB] ;Set map command CALL D3EXEC CMPB [D3IOPB+STAT],#COMPL ;Set error status D3WT5: POP CX JCXZ EXIT1 ;If CX is 0 exit JMP SPECD3 ;Else do more drives ; EXIT1: POP ES $ES ! POP [DEFIOPB+LINK+2] ;Restore default IOPB $ES ! POP [DEFIOPB+LINK] POP ES ;And fix stack JNE EXIT2 RET EXIT2: JMP D3ERROR ;Go process error and return from there ; D3EXEC: STOB #0,[D3IOPB+STAT] ;Clear status byte LD AL,#ATTN OUTB D3PORT,AL ;Send attention to DISK3 D3EXWT: CMPB [D3IOPB+STAT],#BUSY ;Wait for status to be not busy JE D3EXWT RET ; ;Calculate a 3 byte DMA address from a segment(DX) and offset(AX) ; return msb in DL, rest in AX ADRCAL: LD CL,#4 ;Want to get uppermost nibble ROL DX,CL ; Into lowermost nibble MOV CX,DX ;Save in CX for later AND DL,#0FH ;Isolate what was highest nibble AND CX,#0FFF0H ;And separate rest of segment ADD AX,CX ;Add segment to offset ADC DL,#0 ;Add any carry to msb RET NOD3MSG: DB CR,LF,'NO DISK3 BOARD RESPONDING!!',CR,LF,0 D3NOTRDY: DB CR,LF,'Hard disk unit ' D3LTR1: DB 'X not ready. ',CR,LF,0 D3BAD: DB 'Unable to home hard disk unit D3LTR2: DB 'Y, error number ' D3ERNM: DB '0. ',CR,LF,0 NOFMT: DB CR,LF,'Hard disk unit ' NOFMTLTR: DB 'X not formatted!.',CR,LF,0 SPECERR: BADERR: DB 'Error reading in sector 0 or 1 on hard disk unit D3LTR3: DB 'X.',CR,LF,0 D3PFLG: DB 0 .d3 ENDIF ; End of inititialized areas. ; No more initialized data after here. ; Check for exceeding boot track capacity (when LOADER.CMD). BIDLWA: IF @LDR ; ASSERT BIDLWA <= BIOS+900h ;COPYSYS restriction MSG 'Track 0 space needed= ', BIDLWA-BIOS, 'h' if bidlwa < bios+900h ds bios+900h-bidlwa-1 db 0 endif ENDIF