; 31 Mar 86.. fsw ; * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * SCSI/Floppy/Hard Disk Boot ROM * ; * * ; * Copyright (C) 1983, 1984, 1985 * ; * AMPRO Computers, Inc. * ; * All rights reserved. * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * ; ; ; Revision history: ; ; Ver Date Who Description ; --- -------- --- ----------------------------------------- ; 1.2 03/27/86 fsw Changed scsi select routine to current bios ; 3.6 routines. Added SCSI retries. Fixed ; arbitration to provide exit if scsi reset ; occures during arbitration time. ; ; 1.1 10/18/85 fsw Corrected problem booting from 96 tpi disk. ; Added 5 tries for floppy disk reads and ; jmp for drive prameters initialization. ; ; 1.0 9/17/85 fsw Initial release. ; ; ; ; DESCRIPTION ; ; This ROM will boot from floppy, hard disk, or SCSI disk server, ; and is based on the orginal AMPRO boot ROM and the SCSI routines ; in Version 3 BIOS. Arbration is used in the SCSI routines. ; ; No alteration to boot sector is required to boot from floppy. ; Booting from hard disk requires the use of the HGEN utility, to ; install a sector on the hard disk containing hard disk system ; configuration info, and to add code to the boot loader for hard ; disk configuration initialization. ; ; THEORY OF OPERATION ; ; The ROM on reset begins execution at 0000H. It first relocates ; itself to 8000H then continues executation above 8000H. ; The ROM then loads in a "boot loader" sector from floppy, hard disk, ; or other SCSI device. ; ; The first attempt is to load a boot loader from side 0, track 0 ; sector one of floppy drive "A" (drive select "1"), if a floppy ; is present in that drive. If the first byte of that sector is not ; an LXI H or MVI A op code, then an attempt to load a boot loader ; from an SCSI device is made. SCSI ID 0 is used as the SCSI boot ; device if the board's ID is jumpered as 7. Otherwise, SCSI ID 7 ; is used for the attempt to boot from SCSI. ; ; If the appropriate SCSI device is not able to ; provide a legal boot loader (with LXI H or MVI A op code as first ; byte), then the process begins again, looping until a legal "boot ; loader" is obtained. ; ; The boot loader is stored at 9000H, followed by a jump to that ; address. The contents of the boot loader determine what happens ; next. Normally the ROM is switched off first thing. ; ; This accommodates: ; ; o Hard disk drive spinup ; o User choice of boot device ; o Networking ; o Odd-ball applications! ; ; ; MISC NOTES ; ; Supports floppy drive step rate of 6 msec only for compatability ; with the 1770 or 1772 fdc. ; ; Supports hard disk with 512 byte sectors only. Each call to read ; track reads one AMPRO track of 16 sectors when booting from hard ; disk. ; ; Requires the use of SCSI self-initializing controllers, such as ; Adaptec ACB-4000, Shugart 1610-4, Xebec OWL drive/controller, etc. ; ; FEATURES ; ; Test for presence of 177x floppy disk controller and ; for 5380 SCSI controller. ; ; Test for presence of boot sector on the disk it has read. ; ; Test for properly formated floppy disk in drive. ; ; If unable to boot from floppy disk will try SCSI, if ; unable to boot from SCSI, starts over. This sequence ; will repeat untill sucessful. ; ; ; SCSI ID CONVENTIONS ; ; SCSI Master mode: Set board SCSI ID to 7 (refer to board manual). ; When the board's SCSI ID is 7, the boot ROM issues an SCSI ; bus reset, and then uses the device at SCSI ID 0 as the ; SCSI boot device, if floppy boot attempt fails. ; ; SCSI Slave mode: Set board SCSI ID to anything other than 7. ; When the board's SCSI ID is not 7, the boot ROM does not ; issue an SCSI bus reset. In this case the device at SCSI ; ID 7 is used as the SCSI boot device if the floppy boot ; attempt fails. This might be a disk server rather than ; a disk controller. ; ; In all cases if will boot from floppy in drive "A" if a legal boot ; sector is present (as defined above) ;******************************************************************** ; YES EQU 1 NO EQU 0 MSEC EQU 167 CR EQU 0DH LF EQU 0AH CONT EQU 0 ; system control port SID1 EQU 10H ; select side one of disk SDEN EQU 20H ; select single density ROMOFF EQU 40H ; turn rom off BOOT EQU 8000H ; origin of this program RAM EQU 9000H ; beginning of scratch ram STACK EQU RAM ; stack pointer CTCA EQU 40H ; counter/timer CTCA0 EQU CTCA CTCA1 EQU CTCA+10H CTCA2 EQU CTCA+20H CTCA3 EQU CTCA+30H SIO EQU 80H ; serial io SIOAD EQU SIO SIOBD EQU SIO+8 SIOAC EQU SIO+4 SIOBC EQU SIO+12 CMND EQU 0C0H WTRK EQU CMND+1 WSEC EQU CMND+2 WDAT EQU CMND+3 STAT EQU CMND+4 RTRK EQU CMND+5 RSEC EQU CMND+6 RDAT EQU CMND+7 REST EQU 08H STEPI EQU 58H RDSEC EQU 88H RDID EQU 0C8H FI EQU 0D0H ERMSK EQU 18H ID EQU 29H ; Little board SCSI id ; ; NCR 5380 controller equates ; NCRBASE EQU 20H ; Base address of NCR 5380 NCRCSD EQU NCRBASE+0 ; (R) Current SCSI data register NCRODR EQU NCRBASE+0 ; (W) Output data register NCRICR EQU NCRBASE+1 ; (RW) Initiator command register NCRMR EQU NCRBASE+2 ; (RW) Mode register NCRTCR EQU NCRBASE+3 ; (RW) Target command register NCRCSBS EQU NCRBASE+4 ; (R) Current SCSI bus status NCRSER EQU NCRBASE+4 ; (W) Select enable register NCRBSR EQU NCRBASE+5 ; (R) Bus & status register NCRSDS EQU NCRBASE+5 ; (W) Start DMA send NCRIDR EQU NCRBASE+6 ; (R) Input data register NCRSDTR EQU NCRBASE+6 ; (W) Start DMA target receive NCRRPI EQU NCRBASE+7 ; (R) Reset parity/interrupt NCRSDIR EQU NCRBASE+7 ; (W) Start DMA initiator receive NCRDACK EQU NCRBASE+8 ; (RW) DACK pseudo-DMA register ; Current SCSI bus status (NCRCSBS) NCRRST EQU 10000000B ; Reset NCRBSY EQU 01000000B ; Busy NCRREQ EQU 00100000B ; Request NCRMSG EQU 00010000B ; Message NCRCD EQU 00001000B ; Control/Data NCRIO EQU 00000100B ; Input/Output NCRSEL EQU 00000010B ; Select NCRDBP EQU 00000001B ; Data bus parity ;............................................................... ORG BOOT JMP START -BOOT ; power on or re-boot JMP SETUP ; setup disk drive JMP STEPIN ; step in one track JMP SIDEONE ; select side one JMP FDCLR ; clear the fdc JMP SETDMA ; set new dmaadr (hl) JMP READTRK ; read current track at dmaadr JMP READSEC ; read current sector at dmaadr JMP READID ; read next sector address JMP SETPRAM ; pass the hard disk prameters to the ; scsi controller, for dumb controllers. DMAADR: DS 2 IDSV: DS 6 SELBYT: DS 1 TRACK: DS 1 SECTOR: DS 1 STATUS: DS 1 TWOSID: DS 1 SBIAS: DS 1 START: DI XRA A OUT CONT ; clear system control register LXI H,0 LXI D,BOOT RELOC: MOV A,M STAX D INX H INX D MOV A,H CPI 16 ; relocate 16 pages JNZ RELOC -BOOT ; this code runs at address 0 JMP INITSYS ; this code runs relative to boot ; copyright declaration DB 'SCSI Boot Rom Version 1.2 - (C) 1983,1984,1985,1986 ' DB '- AMPRO Computers, Inc. - All rights reserved. ' INITSYS:LXI SP,STACK ; set local stack LXI H,CTCTBL CTCINT: MOV A,M INR A JZ SIOINT DCR A OUT CTCA0 OUT CTCA1 INX H JMP CTCINT CTCTBL: DB 47H,13,255 ;9600 ;CTCTBL: DB 3,0,255 ;19200 SIOINT: LXI H,SIOTBL SIOLP: MOV A,M INR A JZ CBOOT DCR A OUT SIOAC OUT SIOBC INX H JMP SIOLP SIOTBL:DB 4,46H,5,0EAH,3,0C1H,255 ;9600 ;SIOTBL: DB 4,84H,5,06AH,3,0C1H,255 ;19200 ; cboot is the start of the read disk routines. ; ; check little board id, if id = 7 do SCSI reset, if id not=7 ; no reset is issued. ; ; a 1 second time delay is invoked prior to SCSI reset to allow ; various SCSI devices do their powerup initialization before ; the SCSI reset is issued. ; CBOOT: IN ID ; get little board SCSI id ani 07h ; mask off inr a ; make 1 thru 8 mov b,a ; set 'b' for count xra a stc ; set carry setid: ral dcr b jnz setid sta myid cpi 80h ; scsi id 7 mvi a,10000000b ; target id=7 jnz resetnot MVI A,4 ; 4 x .25 sec CALL TIMER mvi a,80h ; scsi reset out ncricr ; set reset line high holdit: dcr a jnz holdit ; 50 usec min out ncricr ; clear reset line in ncrrpi ; and the interrupt line mvi a,00000001b ; target id=0 ; ; has target id in 'a'. if little board id=7 boot from device 0. ; if little board id not=7, boot from device 7. ; resetnot: sta target ; device to boot from xra a out ncricr ; clear the 5380 registers out ncrmr out ncrtcr out ncrser in ncrmr ; read the mode register ; mode register should equal 0 if ; 5380 is present. sta scsi ; set scsi to zero or non-zero to ; show presence of ncr 5380 ; ; everything on the SCSI buss should have completed initialization and ; SCSI reset may have been issued. ; ; test for presence of 177x floppy disk controller. ; MVI A,0AAH ; test for presence of fdc OUT WSEC ; write pattern to sector reg MOV B,A ; save in 'b' ANI 0FH ; set up loop value CLOOP: DCR A ; give the 177x time for the sec reg JNZ CLOOP ; to set up. IN RSEC ; read the sector reg CMP B ; see if same as written to sec reg JZ CBOOT2 ; JMP try$hd$dvr ; do hard disk, no fdc present ; ; floppy disk controller present try to boot from floppy ; MVI A,5 STA TRIES ; set up try count CBOOT2: CALL SETUP CALL READID CALL ERROR JNZ CBOOT2 ; try to read id 5 times MVI A,5 STA TRIES ; reset floppy try counter LDA IDSV+2 ; get sector # CPI 17 MVI A,0 JC CB0 INR A CB0: STA TWOSID ORA A RAL RAL RAL RAL STA SBIAS ; 0 if single sided, 16 if 2 sided LXI H,RAM SHLD DMAADR INR A ; sector 1 ( or 17 ) OUT WSEC CALL READSEC CALL ERROR LDA TWOSID JNZ CB0 ; error occured try to read again lda ram ; see if boot record there cpi 21h ; starts with lxi h,xxxx jz ram cpi 3eh ; other choice is mvi a,xx jz ram jmp try$hd$dvr ; see if can do hard disk SETUP: MVI A,'A'-40H OUT CONT ; select a:, side 0 STA SELBYT ; save it CALL FDCLR MVI A,REST ; restore CALL OUTCMD ; to fdc JMP FDWAIT ; Wait for command to complete and ret ; ; Read current track at dmaadr ; READTRK: lda idsv+3 ; sector size cpi 3 lxi h,skwtbl1 ; 96 tpi disk jz rtloop LXI H,SKWTBL ; sector skew table RTLOOP: mvi a,5 ; sta tries ; set floppy try counter MOV C,M INX H INR C RZ ; finished DCR C LDA SBIAS ADD C STA SECTOR OUT WSEC RSAGN: PUSH H ; save skew table pointer CALL READSEC ; read the sector CALL ERROR ; check for errors JNZ RSAGN1 ; try to read the sector again LHLD DMAADR ; get current dmaadr address SHLD DMA ; save current dma addr POP H ; restore skew table pointer JMP RTLOOP ; next sector ; ; if error on read sector, restores old dma address and attempts ; to read the same sector again. ; RSAGN1: LHLD DMA ; get old dmaadr dma address SHLD DMAADR ; restore dma address POP H ; restore stack JMP RSAGN ; SKWTBL: DB 1,2,3,4,5,6,7,8,9,10,255 skwtbl1:db 1,2,3,4,5,255 ; ; read id twice, once to see if disk in drive, the second for ; the id value. ; READID: IN STAT IN RDAT MVI A,RDID CALL OUTCMD call fdwait ; See if will time out CPI 255 ; no floppy sta status ; if timeout error, set error status rz ; if timeout just return IN STAT ; clear fdc reg IN RDAT LXI H,IDSV MVI A,RDID CALL OUTCMD CALL RD MOV A,B STA STATUS RET READSEC:IN STAT ; clear status IN RDAT ; clear any trash LHLD DMAADR CALL FDCLR MVI A,RDSEC ; read sector command CALL OUTCMD ; to fdc CALL RD ; read loop MOV A,B STA STATUS SHLD DMAADR RET RD: IN STAT MOV B,A ; save status RAR RNC ; return when fdc not busy RAR JNC RD ; wait for drq IN RDAT MOV M,A INX H JMP RD STEPIN: LDA TWOSID ORA A JZ STPI CALL SIDEONE LXI H,TRACK DCR M LXI H,MSEC ; wait one millisecond JMP WT ; wt returns to caller STPI: MVI A,STEPI ; step in command CALL OUTCMD STLP: IN STAT RAR JC STLP RET FDCLR: MVI A,FI OUT CMND MVI A,0 CL: DCR A JNZ CL IN STAT IN RDAT RET OUTCMD: OUT CMND MVI A,19 OC0: DCR A JNZ OC0 ; wait 66.5 usec for fdc to set-up RET SETDMA: SHLD DMAADR SHLD DMA RET SIDEONE:LDA SELBYT ORI SID1 OUT CONT RET ; ; floppy error checking enters here. Returns with zero flag NZ if ; error, or Z if no error. Floppy routines must set STATUS for error ; conditions. ; ERROR: LDA STATUS ANI ERMSK RZ PUSH H LXI H,TRIES ; point to tries DCR M ; tries -1 POP H RNZ ; try again LDA SCSI ; get 5380 present byte ANA A JZ HD$DVR ; Try hard disk, have timed out on floppy ; disk at least 5 times ; ; floppy error falls thru to here also hard disk errors enter here to ; start the hole proceedure over and over again. ; ERROR1: XRA A ; make sure prom is turned on OUT CONT JMP 0 ; jmp to prom ; WAIT: LXI H,100 * MSEC WT: DCX H MOV A,H ORA L JNZ WT RET ; ; This routine will wait for a for the FDC to go not busy, showing ; completion of a command. After 1 seconds time out, a FORCE INTERRUPT ; command will be issued to the FDC. Routines will come through here ; at least 5 times before final error occures. Total time out 5 seconds. ; FDWAIT: LXI H,TIMEOUT ; Point to timeout location MVI M,3 ; Set major loops for timeout ; 3 = about 1 sec. DLOOP: IN STAT ; Get FDC status RAR ; test busy bit RNC ; . zero status if busy non-active RAR ; see if byte to be read JC FREAD ; read the byte DCX H ; See if enough minor loops MOV A,H ; . (Approx 34,000 times) ORA L ; . JNZ DLOOP ; Not done with minor loop LXI H,TIMEOUT ; Decrement major loop counter DCR M ; . (timeout loop count) JNZ DLOOP ; . CALL FDCLR ; force fdc clear XRA A ; Set A to 0FFH and status to NZ OUT CONT ; deselect so floppy select light DCR A ; will go out RET ; ; FREAD: IN RDAT ; get the data byte from the fdc JMP DLOOP ; just loop till command over ; ; timer entered with 'a' equal to number of major loops wanted ; each major loop = aprox .25 sec ; TIMER: LXI H,TIMEOUT MOV M,A ; save major loop value TIMER0: LXI H,41668 TIMER1: DCX H ; 1.5 MOV A,L ; 1.0 ORA H ; 1.0 JNZ TIMER1 ; 2.5 ;total = 6 usec X 41668 LXI H,TIMEOUT DCR M RZ JMP TIMER0 ; ;--------------------------------------------------------------- ; Send bytes to console until zero encountered ; use to insert messages when debuging ; format is ; call puts ; db 'your message',0; must terminate with '0' ; ;PUTS: pop h ; 'hl' has address of msg ; mov c,m ; get char ; inx h ;CONOUT: ; MVI A,01H ; Check "all sent" bit in register 1 ; OUT 84H ; . ; IN 84H ; . ; ANI 01H ; "ALL SENT" is bit 0 ; JZ CONOUT ;TRANSMIT BUFFER NOT READY ; MOV A,C ;CHARACTER TO REGISTER A ; OUT 80H ; mov a,m ; ana a ; returns with char in 'a', null = end ; jnz puts+1 ; pchl ; hl has return address ;----------------------------------------------------------------- ; ; if no boot sector is present on the floppy disk, floppy timeout ; has occured, floppy read error, or no floppy disk controller is ; present, entry to the hard disk (scsi) driver is here. ; ; starts with 5 second timer to prevent hammering the scsi buss ; with possible scsi resets. ; TRY$HD$DVR: MVI A,20 ; 20 x .25 seconds = 5 sec CALL TIMER ; ; Hard disk driver ; HD$DVR: LXI SP,STACK ; reset stack lxi h,hdtrk shld boot+19 ; patch readtrk xra a ; zero 'a' lxi h,ram ; address to read sector mov m,a ; clear anything at this address sta hdsect ; zero hard disk sector shld dmaadr call scsi$rd ; read boot sector lda ram cpi 21h ; should be lxi h,xxxx jz ram cpi 3eh ; other choice is mvi a,xx jz ram jmp error1 ; no boot sector go try floppy again ; ; Read hard disk system to memory. Do 16 sectors at a time. One AMPRO ; hd track. The boot loader will call this routine twice. ; First pass read sectors 0 thru 15, second pass read 16 thru 31 for ; 32 sectors total. ; HDTRK: call scsi$rd cpi 0ffh ; see if return has timeout error jz error1 ; start all over lhld dmaadr lxi d,512 ; update dma address dad d shld dmaadr lda hdsect ; see if two tracks (32 sectors) inr a ; next sector to read cpi 32 ; have already read 512x32 bytes rz ; cpi 16 ; see if one "track" has been read sta hdsect ; update sector new sector, the boot ; loader reads two tracks. rz ; return to boot jmp hdtrk ; loop till through ; ; ; SCSI return sense data command (Cmd 03) ; SCSI$STAT$CMD: DB 3 ; 00 - REQUEST SENSE COMMAND DB 0 ; 01 - LOGICAL UNIT DB 0 ; 02 - RESERVED DB 0 ; 03 - RESERVED DB 4 ; 04 - NUMBER OF BYTES DB 0 ; 05 - RESERVED ; ; SCSI read/write command (Cmd 08/0A) ; SCSI$RD$CMD: EQU 08H ; 08 IS READ DATA SCSI$RW$CMD: DB SCSI$RD$CMD ; 00 - 08=Read, 0A=Write HIGH$ADDR: DB 0 ; 01 - High address MED$ADDR: DB 0 ; 02 - Middle address LOW$ADDR: DB 0 ; 03 - Low address DB 1 ; 04 - Number of sectors STEP$RATE: DB 0 ; 05 - Step rate (Xebec) ; ; Init scsi controller prameters ; ; When called HL = address of scsi command ; DE = address of prameter table ; SETPRAM: SHLD CMDPTR ; set address of scsi command XCHG ; 'de' to 'hl' SHLD DATPTR ; save address of prameters to pass JMP SCSI$CMD ; ; Read from the hard disk ; SCSI$RD: LXI H,SCSI$RW$CMD ; Get command string SHLD CMDPTR ; Save the command pointer CALL BLD$SCSI$SCTR ; Build SCSI sector address ; ; Exits with status in A. 0FFH = timeout error ; SCSI$CMD: LXI H,TRIES ; set up retry count MVI M,2 SCSI$CMD$RETRY: CALL SELECT ; Perform the SCSI operation LDA STATUS ; Get the return status STA ERFLAG ; save error CPI 0FFH ; Timeout? JZ SCSI$DONE ; Yes, go save timeout status ANI 2 ; Check for SCSI error status JZ SCSI$DONE ; No error -- finish up LHLD CMDPTR SHLD SAVE$CMDPTR ; save old command pointer LXI H,SCSI$STAT$CMD ; get sense SHLD CMDPTR ; set command pointer LHLD DMAADR SHLD SAVE$DMA ; save the current LXI H,MESSAGE ; message area SHLD DMAADR CALL SELECT ; do operation LXI H,TRIES DCR M ; tries -1 LHLD SAVE$DMA ; get dma address back SHLD DMAADR ; restore dma address LHLD SAVE$CMDPTR SHLD CMDPTR ; restore command pointer JNZ SCSI$CMD$RETRY ; MVI A,0FFH SCSI$DONE: ORA A ; Set Z/NZ for user RET ; and return ; ; ; Build 2-byte SCSI sector number starting with 00 ; ; NOTE: This routine uses only a block number starting with 00 ; and read a maximun of ffh sectors. ; BLD$SCSI$SCTR: lda hdsect sta low$addr ret ; ; Select controller, and fall through to phase if selected ok. ; ; busbsy: equ 40h ; SELECT: xra a out ncricr ; Clear initiator command register out ncrtcr ; . and target command register clear$arbit: xra a out ncrmr ; . in ncrrpi ; reset interrupts arbitrate: lda my$id ; Assert my ID (the initiator) out ncrodr ; . mvi a,1 ; start arbitration out ncrmr ; . in$progress: in ncricr ; Wait for "arbitration in ani 40h ; . progress" bit jnz arbitrate$won ; we have argitration in ncrbsr ani 10h ; see if scsi reset has occured jz in$progress jmp clear$arbit arbitrate$won: nop ; Arbritration delay nop in ncricr ; Check for lost arbitration ani 20h ; . jnz clear$arbit ; We lost -- start over lda my$id mov b,a in ncrcsd ; See if we're the highest priority sub b ; . remove my addr sub b ; . compare my addr to bus data jm i$win ; We win if result < 0 jmp clear$arbit ; . otherwise we lose -- start over i$win: in ncricr ; Check again for lost arbitration ani 20h ; . (just in case) jnz clear$arbit ; We lost -- start over mvi a,08h ; set assert BSY bit in icr out ncricr ; . in ncricr ori 04h ; OR in SEL to ICR out ncricr nop ; wait one bus clear delay lda my$id ; Select target: get our ID, mov b,a ; . lda target ; . or in target ID ora b ; . out ncrodr ; . and send to NCR chip mvi a,0dh ; Assert data bus out ncricr ; . (along with SEL & BSY) in ncrmr ; Reset arbitration bit ani 0feh ; . out ncrmr ; . mvi a,05h ; Release BSY, keep SEL out ncricr ; . and assert data bus nop lxi b,6000h ; 250 ms loop (1M cycles) stim: in ncrcsbs ; Wait for BSY ani busbsy ; . jnz select$ok ; Got him! dcr c jnz stim ; inner loop: 41*256 = 10496 cycles dcr b jnz stim ; outer loop: 10510*96 = 1M cycles xra a ; Select timeout -- clear bus out ncrodr dcr a ; set 'a' to 0ffh sta status ; Save status timeout. jmp all$done ; and clear the registers select$ok: xra a ; Set good status all$done: mov b,a ; temp save status mvi a,01h ; Release SEL out ncricr ; . xra a ; Remove address from data bus out ncricr ; . mov a,b ; Get status back ora a ; Set status rnz dcr a ; set 'a' to ffh sta status ; clear scsi status to timeout.. ; SCSI.011 ; * * * * * ; * --------\ NOTE: we fall through if we successfully ; * --------/ selected the controller!! ; * * * * * MVI A,00000110B ; Set DMA mode and Monitor Busy OUT NCRMR ; . SCSI$RDY: ; Wait for either a 5380 "Interrupt" or a REQ from Target. ; The REQ is needed since it may have come too soon after ; selection to register an Interrupt. IN NCRBSR ; Check for "Interrupt" ANI 00010000B ; . JNZ SCSI$INT IN NCRCSBS ; Check for REQ ANI NCRREQ ; . JZ SCSI$RDY ; Wait for Interrupt or REQ JMP PHASE ; Process phase vector SCSI$INT: ; Determine cause of 5380 "Interrupt". Either phase ; changed, busy dropped, or bus was reset. If bits 2 and 3 ; of the NCRBSR are not 0's when the Interrupt flag (bit 4) ; is set, then it is either a loss of BUSY or an SCSI RESET. XRA A OUT NCRICR ; Release data bus IN NCRBSR ; Read 5380 Bus and Stat Reg ANI 00001100B ; Keep interesting bits JNZ SCSI$EXIT ; Reset or Busy Loss: Exit ; 00 --> Process phase vector PHASE: ; DMA mode and Monitor Busy must be cleared prior to clearing ; of the 5380 Interrupt Flag. Then mode register is restored. ; Otherwise the interrupt flag may not clear and the DMA Mode ; may not be useable. XRA A ; Clear 5380 Mode Register OUT NCRMR ; . IN NCRRPI ; Reset interrupts MVI A,00000110B ; Set DMA mode and Monitor Busy OUT NCRMR ; . IN NCRCSBS ; Update phase... ANI 00011100B ; Mask all but phase bits, clear carry bit RAR ; Rotate over for target MOV E,A ; . (Save for use with jump table) RAR ; . OUT NCRTCR ; Set phase MVI D,0 ; E is already set (6 ins ago) LXI H,PHASE$TABLE ; Get phase jump table base DAD D ; Add offset for this phase MOV A,M ; Get phase pointer into HL INX H ; . MOV H,M ; . MOV L,A ; Pointer is now together MVI D,01000000B ; DMA request mask (used by RSCSI and WRSCSI) PCHL ; Go to it! PHASE$TABLE: DW PHASE0 DW PHASE1 DW PHASE2 DW PHASE3 DW PHASE4 DW PHASE5 DW PHASE6 DW PHASE7 PHASE0: ; Data out phase LHLD DATPTR ; to pass prameters to scsi controller JMP WSCSI ; Execute SCSI write routine PHASE1: ; Data in phase ... LHLD DMAADR ; Use data pointer JMP RSCSI ; Execute SCSI read routine PHASE2: ; Command out phase ... LHLD CMDPTR ; Use command pointer JMP WSCSI ; Execute SCSI write routine PHASE3: ; Status in phase ... LXI H,STATUS ; Use status pointer JMP RSCSI ; Execute SCSI read routine PHASE7: ; Message in phase ... LXI H,MESSAGE ; Use message pointer JMP RSCSI ; Execute SCSI read routine ; Currently unused phases PHASE4: PHASE5: PHASE6: SCSI$EXIT: XRA A ; clean up 5380 and exit OUT NCRTCR OUT NCRMR IN NCRRPI ; reset unterrupts RET ; Generalized SCSI read routine ; Initiator command reg is already ininialized by phase ; RSCSI: OUT NCRSDIR ; Start DMA initiator receive ; Wait for DMA request, keeping an eye on phase. Note: we must do ; a check for DMA request before checking for a phase change, since ; a byte may be queued up waiting to be DACKed prior to the phase ; change. RSCSI1: SHLD DATPTR ; Save (new) data ptr for multi-sector IN NCRBSR MOV C,A ; Keep for phase change checking ANA D ; Mask for DMA request JZ RSCSI2 ; ; All transfer is one byte at a time ; IN NCRDACK MOV M,A INX H JMP RSCSI1 ; Read until phase changes ; ; This code skipped when data is being transferred ... ; RSCSI2: MOV A,C ; Check phase ANI 00010000B ; . JZ RSCSI1 ; Wait for DMA request JMP SCSI$INT ; Process "interrupt" flag ; ; Generalized SCSI write routine ; WSCSI: MVI A,1 ; Assert data bus OUT NCRICR OUT NCRSDS ; Start DMA send ; ; Wait for DMA request, keeping an eye on phase. Note that the NCR ; will not issue an ACK, nor will it generate DMA requests once the ; phase changes, so it is best to treat DMA request checking as a ; higher priority than phase change checking. ; WSCSI1: SHLD DATPTR ; Save (new) data ptr WSCI11: IN NCRBSR MOV C,A ; Save status for use below ANA D ; Check for DMA request JZ WSCSI2 mov a,m out ncrdack inx h JMP WSCSI1 ; Write more bytes until phase changes ; ; This code skipped when data is being transferred ... ; WSCSI2: MOV A,C ; Check phase ANI 00010000B ; . JZ WSCSI1 ; Wait for dma request JMP SCSI$INT ; Process "interrupt" ; ; Tempory storage ; TRIES: DB 5 ; number of tries DMA: DS 2 ; save for dma address TIMEOUT: DS 1 MYID: DS 1 TARGET: DS 1 ERFLAG: DS 1 HDSECT: DS 1 DATPTR: DS 2 CMDPTR: DS 2 MESSAGE: DS 4 SCSI: DS 1 SAVE$DMA: DS 2 SAVE$CMDPTR: DS 2 END