; Listing in data sheet seems to generate stupid opcodes for the LSR mnemonic. ; The opcodes do not disassemble into anything plausible. ; ; LSR should create just one byte, but the datasheet listing has three, ; and not the same three every time. ; ; define this flag true if you want to generate the stupid opcodes: ; stupid equ 0 ; ; ; NCR 5380 SCSI PROTOCOL DRIVER ; ; SUPPORTS BOTH INITIATOR AND TARGET ROLES ; ; ASSUMES THAT THE COMMAND BLOCK (CDB), ; DATA BLOCK(DBLK), AND THE EXPECTED PHASE ; TABLE HAVE BEEN SPECIFIED IN MEMORY ; ; SLFAIL = $01 ; SELECTION FAILED STATUS DISCNT = $02 ; DISCONNECTED STATUS PRTYER = $03 ; PARITY ERROR STATUS BUSRST = $04 ; SCSI BUS RESET STATUS CHIPFL = $05 ; CHIP FAILURE STATUS MESSAG = $06 ; MESSAGE IN BYTE BEING RETND DIFFPH = $07 ; UNEXPECTED PHASE REQUESTED CMDCPL = $00 ; COMMAND COMPLETE MESSAGE DATA0 = $00 ; DATA OUT PHASE CMD = $08 ; COMMAND PHASE STATUS = $0C ; STATUS PHASE DATAI = $04 ; DATA IN PHASE MESSO = $18 ; MESSAGE OUT PHASE MESSI = $1C ; MESSAGE IN PHASE DISCON = $80 ; FLAG TO DISCONNECT SELECT = $40 ; FLAG TO WAIT FOR SELECTION S5380 = $DE00 ; 5380 ADDRESS SPACE SDMA = $DE0C ; PSEUDO DMA ADDRESS IID = $DE08 ; INIT. ID EXT. LATCH SRST = $DF00 ; NCR5380 DEVICE RESET BPNTR = $FB ; DATA BLOCK POINTER ;DATAB .WORD DBLK ; *= $C000 ; PROGRAM SPACE ORIGIN org $C000 ; PROGRAM SPACE ORIGIN TID ds 1 ; * = *+1 ; TARGET ID SPACE ICRVAL ds 1 ; * = *+1 ; INIT. CMD REG. STORAGE INITFL ds 1 ; * = *+1 ; INITIATOR FLAG OCFLAG ds 1 ; * = *+1 ; OPEN COLL. FLAG PTYFLG ds 1 ; * = *+1 ; PARITY FLAG ATNFLG ds 1 ; * = *+1 ; ATN FLAG PHSIDX ds 1 ; * = *+1 ; EXPECTED PHASE INDEX XPTPHS: ds 30 ; * = *+30 ; EXPECTED PHASE TABLE COUNT ds 1 ; * = *+1 ; BYTE COUNT XCNT ds 1 ; * = *+1 ; BYTE COUNT MULTIPLIER CDB: ds 12 ; * = *+12 ; CMD BLOCK STORAGE DBLK: ds 512 ; * = *+512 ; DATA BLOCK STAT dw 1 ; * = *+2 ; STATUS BYTES CDBS: dw CDB, DBLK, STAT ; ; ; INITIALIZATION ; START: LDA #00 ; ZERO ACCUM STA PHSIDX ; INITIALIZE PHASE INDEX LDA SRST ; RESET 5380 NUMBER LDA #00000100b ; ENABLE MONITOR BSY INT LDX PTYFLG ; LOAD PARITY FLAG BEQ NOPTY ; IF ZERO, NO PARITY ORA #00110000b ; OR IN CHECK PARITY BITS NOPTY: STA S5380+2 ; STORE IN MODE REGISTER ; LDX PHSIDX ; LOAD VALUE OF PHASE INDEX LDA #SELECT ; GET VALUE OF SEL CMD CMP XPTPHS,X ; COMPARE W/CURRENT PHASE BNE INIT ; IF NOT = BEGIN ARBITRATION JMP TARSEL ; ELSE, WAIT FOR TARGET SELECT ; ; BEGIN SCSI BUS ARBITRATION ; INIT: LDA S5380+2 ; READ MODE REG. AND #11111110b ; MASK ARB BIT STA S5380+2 ; RESET ARBITRATION BIT ARB: LDA IID ; BEGIN ARBITRATION STA S5380+0 ; LOAD ID INTO ODR LDA S5380+2 ; READ MODE REG. ORA #00000001b ; SET ARBITRATION BIT STA S5380+2 ; STORE IN MODE REG. ; ; HAS BUS GONE FREE? ; NFREE: BIT S5380+1 ; BUS FREE? BVC NFREE ; NO LOOP UNTIL FREE ; NOP ; YES, WAIT AN ARB DELAY (2.2 USECONDS) LDA S5380+1 ; LOAD INIT CMD REG. AND #00100000b ; MASK All BUT LA BIT BNE INIT ; IF LOST ARB, RESTART ; ; CHECK FOR HIGHER PRIORITY ID? ; LDA S5380+0 ; LOAD CURRENT DATA REG. SEC ; SET CARRY BIT SBC IID ; SUB YOUR ID FROM DATA REG. BEQ WIN ; IF EQUAL TO ZERO, WIN ARB SEC ; NOT, SOMEONE ELSE IS ARB-ING SBC IID ; SUBTRACT YOUR ID AGAIN BMI WIN ; IF NEG, YOUR ID WAS HIGHER BNE INIT ; OTHERWISE, RESTART ; ; RECHECK LOST ARBITRATION ; ; LOAD INIT. CMD REG. ; WIN: LDA S5380+1 ; LOAD INIT. CMD REG. AND #00100000b ; MASK ALL BUT LA BIT BNE INIT ; IF LOST ARB, RESTART ; LDA #00001100b ; LOAD VALUE TO SET SEL SIGNAL LDX ATNFLG ; LOAD ATN FLAG ; BEQ WOATN ; IF ZERO, SEL W/O ATN ORA #00000010b ; OR IN ATN BIT WOATN: STA S5380+1 ; TURN ON SEL LINE ; ; WAIT 2.2 USEC ; NOP LDA INITFL ; LOAD IN A SOFTWARE FLAG BNE SEL ; IF FLAG SET, PERFORM INIT. SEL ; ; ELSE, TARGET RESELECTION ; LDA S5380+2 ; READ MODE REG. ORA #01000000b ; ENABLE TARGET MODE STA S5380+2 ; SET TARGET MODE LDA #$01 ; ENABLE ASSERT I/O STA S5380+3 ; SET ASSERT I/O ; SEL: LDA IID ; LOAD INITIATOR ID ORA TID ; OR IN TARGET ID STA S5380+0 ; LOAD INT & TAR ID'S INTO ODR ; ; TEST FOR DIFFERENTIAL PAIR ; LDA #00000101b ; SEL & DATA BUS BITS BNE OPNCOL ; LOAD IN A SOFTWARE FLAG LDX OCFLAG ; IF FLAG SET, OPEN COLLECTOR ; ; DIFFERENTIAL PAIR ; ORA #00100000b ; ? OR IN DIFF. ENBL BITS OPNCOL: STA S5380+1 ; SET SEL, DATA BUS, & (DIFF. PAI STA ICRVAL ; RETAIN VALUE OF INIT CMD REG. ; ; RESET ARBITRATION BIT ; LDA S5380+2 ; READ MODE REGISTER AND #11111110b ; MASK ARB BIT STA S5380+2 ; RESET ARB BIT ; ; DISABLE THE SEL EN REGISTER TO AVOID A SEL INT. ; LDA #$00 ; ZERO ACCUM. STA S5380+4 ; ZERO SELECT ENABLE REG. ; ; RELEASE BUSY ; LDA ICRVAL ; GET INIT CMD REG VALUE ;-------------------- AND #11110111b ; MASK OUT BSY BIT STA S5380+1 ; RESET BSY STA ICRVAL ; RETAIN ICR VALUE ; ; NOW WAIT 400NSEC AND BEGIN LOOKING FOR BSY ; LDY #$60 ; LOAD UP Y REG FOR COUNTER RELD: LDX #$FF ; LOAD UP X REG FOR COUNTER STIM: BIT S5380+4 ; SAMPLE BSY BIT BVS SLECT ; IF BSY ACTIVE, SELECTED ; ; WAIT 250 MSEC ; DEX ; DELAY BNE STIM ; IF NOT ZERO LOOP DEY BNE RELD ; IF Y NOT ZERO RELOAD X ; ; SELECTION TIMEOUT ; LDA #$00 ; TAR. DID NOT RESPOND TO SEL STA S5380+0 ; RESET ID BITS LDX #$20 ; LOAD 200 USEC COUNTER CHK: BIT S5380+4 ; CHECK BSY AGAIN BVS SLECT ; IF SET SELECTION OK DEX BNE CHK ; ; SELECTION FAILED ; LDA #SLFAIL ; LOAD STATUS IN ACCUM. RTS ; RETURN TO CALLING PRGM ; ; SUCCESSFUL (RE)SELECTION ; SLECT: LDA ICRVAL ; GET VALUE OF INIT CMD REG. LDX INITFL ; GET INIT FLAG BNE IF ; IF INITIATOR JUMP ORA #00001000b ; AND SET BSY IF TARGET. STA S5380+1 ; 5 WRITE TO ICR STA ICRVAL ; UPDATE PRESENT ICR VALUE IF: LDA #00101000b ; MASK TO RESET SEL & DATA BUS AND ICRVAL ; AND WITH ICR VPLUE STA S5380+1 ; RESET SEL & DATA BUS STA ICRVAL ; UPDATE NEW ICR VALUE ; ; BEGIN TRANSFERS ; DEX ; DEC INITIATOR FLAG BEQ PDMA ; IF ZERO, INITIATOR ROLE JMP RES ; ELSE, TARGET ROLE ; ; INITIATOR ROLE ; ; USE PSEUDO DMA MODE ;-------------------- PDMA: LDA #DATA0 ; LOAD TCR W/DATA OUT PHASE STA S5380+3 ; NXT: LDA S5380+2 ; GET MODE REGISTER ORA #00000010b ; OR IN DMA MODE BIT STA S5380+2 ; SET DMA MODE BIT LDX PHSIDX ; LOAD X W/PHASE INDEX LDA XPTPHS+1,X ; STA COUNT ; STORE IN PHASE COUNT BYTE LDA XPTPHS+2,X ; GET COUNT MULTIPLIER STA XCNT ; STORE IN MULTIPLIER ; ; WAIT FOR PHASE MISMATCH INT. ; WAIT: LDA S5380+5 ; SAMPLE BUS & STATUS REG. AND #00010000b ; LOOK FOR INT. REQ. BEQ WAIT ; IF NOT SET, WAIT ; ; IRQ IS ACTIVE ; LDA S5380+2 ; GET MODE REG. AND #11111101b ; RESET DMA MASK STA S5380+2 ; RESET DMA MODE BIT LDA S5380+5 ; GET BUS & STATUS REG if stupid LDA S5380+5 ; GET BUS & STATUS REG LDA S5380+5 ; GET BUS & STATUS REG LDA S5380+5 ; GET BUS & STATUS REG else LSR ; SHIFT RIGHT 3 TIMES LSR LSR endif BCS EBUSY ; LOSS OF BUSY ERROR if stupid db $B0,$15,$DE else LSR ; SHIFT endif BCC PHSMM ; IF CARRY CLEAR, MISMATCH if stupid db $90,$76,$DE db $90,$76,$DE else LSR ; SHIFT TWICE LSR endif BCS EPRTY ; IF SET, PARITY ERROR BIT S5380+4 ; GET CURRENT SCSI BUS STATUS BMI BRST ; IF BIT 7 SET, BUS RESET OCCURED JMP FAIL ; SHOULD NOT GET HERE ; ; RETURN ERROR STATUS TO CALLING PROGRAM ; EBUSY: LDA #DISCNT ; SET DISCONNECT FLAG RTS EPRTY: LDA ICRVAL ; GET INIT. CMD REG. VALUE ORA #00000010b ; TURN ON ATN SIGNAL STA S5380+1 ; SET ATN STA ICRVAL ; LDA #PRTYER ; SET PARITY ERROR RTS ; BRST: LDA #BUSRST ; SET BUS RESET ERROR RTS FAIL: LDA #CHIPFL ; SET CHIP FAIL ERROR RTS ; RETURN TO CALLING PRGM ; ; WAIT FOR TARGET SELECTION ; TARSEL: LDA S5380+2 ; GET MODE REG. ;-------------------- ORA #01000000b ; SET TARGET MODE MASK STA S5380+2 ; SET TARGET MODE BIT LDA IID ; GET TARGET ID STA S5380+4 ; STORE IN SELECT ENABLE REG. LOOK: LDA S5380+5 ; SAMPLE BUS & STATUS REG. AND #00010000b ; LOOK FOR INT REQ BEQ LOOK ; KEEP WAITING ; ; CHECK FOR MORE THAN TWO IDS ACTIVE ; LDA S5380+0 ; READ SCSI DATA BUS LDX #$09 ; SHIFT COUNT LDY #$00 ; INITIALIZE BIT COUNT if stupid UP: db $A0,$00,$DE else UP: LSR ; SHIFT BIT INTO CARRY BIT endif DEX ; DECR. SHIFT COUNT BEQ OUT ; IF ZERO, DONE COUNTING BCC UP ; IF CARRY NOT SET, DO NEXT INY ; IF CARRY SET BUMP BIT CNT BCS UP ; GET NEXT BIT OUT: SEC ; SET CARRY BIT TYA ; PUT Y IN ACCUM SBC #$03 ; SUBTRACT 3 FROM BIT COUNT BMI CI ; IF MINUS, OK LDA S5380+7 ; NOT MINUS, RESET IRQ. JMP LOOK ; WAIT FOR GOOD SELECTION ; ; CHECK INTERRUPT ; CI: LDA S5380+5 ; SAMPLE AGAIN AND #00100000b ; MASK PARITY BIT BEQ EPRTY ; PARITY SELECTION ERROR LDA S5380+4 ; GET CURRENT SCSI BUS ST AND #00000010b ; CHECK SEL BEQ FAIL ; IF NOT SET, FAILURE LDA #00001000b ; SET BSY MASK STA S5380+1 ; SET BSY SEL COMPLETE STA ICRVAL ; RETAIN ICR VALUE LDA S5380+7 ; RESET INTERRUPT JMP RES ; LOAD X WITH PHASE POINTER ; ; PHASE MISMATCH CONDITION ; PHSMM: LDX PHSIDX ; LOAD CURRENT SCSI BUS STATUS LDA S5380+4 ; MASK ALL BUT PHASE BITS AND #00011100b ; COMPARE TO XPTED PHASE CMP XPTPHS,X ; YES, PHASE MATCHES BEQ PHSMTH ; DIFFERENT PHASE JMP DP ; ; PHASE MATCHES EXPECTED PHASE ; if stupid PHSMTH: db $4C,$B4,$C4 db $4C,$B4,$C4 else PHSMTH: LSR ; SHIFT TO TCR REG. FORMAT LSR endif STA S5380+3 ; STORE IN TCR ;-------------------- LDA S5380+7 ; RESET INTERRUPT LDA #MESSO ; LOAD MESSOUT VALUE CMP XPTPHS,X ; WAS PHASE MATCH MESS. OUT LDA #MESSO ; IF NOT MESS. OUT, CONTINUE ; ; MESSAGE OUT, RESET ATN ; LDA ICRVAL ; GET INITIATOR CMD. REG AND #11111101b ; MASK OFF ATN STA S5380+1 ; TURN OFF ATN STA ICRVAL ; UPDATE ICR VALUE GMR: LDA S5380+2 ; GET MODE REG ORA #00000010b ; SET DMA MODE BIT STA S5380+2 ; STORE IN TCR LDA S5380+3 ; GET PHASE AGAIN AND #00000001b ; SET I/O MASK BEQ IDMAO ; IF ZERO, DMA OUTPUT ; ; INITIATOR DMA INPUT ; IDMAI: STA S5380+7 ; START INIT. RCV. LDY #00 ; INITIALIZE Y JSR DMAIN ; PERFORM DMA INPUT JMP NXT ; PREPARE FOR NEXT PHASE ; ; INITIATOR DMA OUTPUT ; IDMAO: JSR DMAOUT ; PERFORM DMA OUTPUT STA SDMA ; EXTRA WRITE FOR ACK TO GO OFF JMP NXT ; PREPARE FOR NEXT PHASE ; ; TARGET OPERATION ; RES: LDA S5380+2 ORA #00000010b STA S5380+2 LDX PHSIDX LDA XPTPHS+1,X ; GET PHASE COUNT STA COUNT ; STORE IN PHASE COUNT BYTE LDA XPTPHS+2,X ; GET COUNT MULTIPLIER STA XCNT ; STORE IN MULTIPLIER ; LDA S5380+5 ; GET BUS & STATUS REG. AND #00000010b ; MASK ATN BIT BNE MESSOT ; ATN ACTIVE DO MESS OUT PHASE LDX PHSIDX ; GET CURRENT PHASE INDEX LDA #DISCON ; GET DISCONNECTED VALUE CMP XPTPHS,X ; COMPARE W/PHASE VALUE BEQ DISCTD ; IF =, TIME TO DISCONNECT LDA XPTPHS,X ; GET PHASE if stupid LDA XPTPHS,X LDA XPTPHS,X else LSR ; SHIFT TO TCR FORMAT LSR ; endif STA S5380+3 ; STORE IN TARGET COMMAND REG. AND #00000001b ; SAVE I/O BIT BEQ TDMAO ; IF ZERO, DMA OUTPUT ; ; TARGET DMA INPUT ; TDMAI STA S5380+6 ; START DMA TARGET RCV LDY #01 ; SET Y TO ONE, SO NO EXTRA REG JSR DMAIN ; PERFORM DMA INPUT ; HANDLE LAST BYTE TO PREVENT EXTRA REQUEST LSTDRQ: BIT S5380+5 ; LOOK FOR DRQ BVC LSTDRQ ; LOOP TILL ON LDA S5380+2 ; GET MODE REG AND #1111110b ; MASK DMA MODE BIT STA S5380+2 ; RESET DMA MODE BIT LDA SDMA ; GET LAST BYTE FROM CHIP STA (BPNTR),Y ; STORE LAST BYTE JMP RES ; DO NEXT PHASE ; ; TARGET DMA OUTPUT ; TDMAO: JSR DMAOUT ; PERFORM DMA OUTPUT LDA S5380+2 ; GET DMA MODE AND #11111101b ; MASK DMA MODE BIT STA S5380+2 ; RESET DMA MODE BIT JMP RES ; DO NEXT PHASE ; ; TARGET DISCONNECT ; DISCTD: LDA #00 ; RESET BSY & OTHER SIGNALS STA S5380+1 ; DISCONNECTED STATUS LDA #DISCNT ; RETURN TO CALLING PRGM RTS ; ; MESSOUT PHASE (TARGET) ; MESSOT: LDA #MESSO ; GET VALUE OF MESSAGE OUT if stupid LDA #MESSO db $DE LDA #MESSO db $DE else LSR ; SHIFT TO TCR FORMAT LSR ; endif STA S5380+3 ; MESSOUT PHASE LDA #1 ; LOAD MULTIPLIER/COUNTER VALUE DEX ; MOVE POINTER STA XPTPHS,X ; STORE MULTIPLIER DEX ; MOVE POINTER TO COUNT VALUE STA XPTPHS,X ; STORE COUNT DEX ; MOVE TO PHASE STX PHSIDX ; UPDATE MOVED PHASE INDEX JMP TDMAO ; DO DMA OUT ; ; DIFFERENT PHASE ; DP: LDA #MESSI ; LOAD VALUE OF MESSAGE IN PHASE CMP XPTPHS,X ; IS THIS A MESSAGE IN PHASE BEQ MESSIN ; IF =, READ MESSAGE LDA #DIFFPH ; LOAD DIFFERENT PHASE ST. RTS ; RETN W/UNEXPECTED PHASE STATUS ;-------------------- ; ; MESSAGE IN PHASE ; if stupid MESSIN: db $60,$07,$C0 db $60,$07,$C0 else MESSIN: LSR ; SHIFT TO TCR FORMAT LSR endif STA S5380+3 ; LOAD TCR LDA S5380+7 ; RESET INT. POLL: LDA S5380+4 ; READ CURRENT BUS STATUS AND #00100000b ; LOOK FOR REQ. BEQ POLL ; IF ZERO, NO REQ. LDA ICRVAL ; GET CURRENT ICR VALUE ORA #00010000b ; OR IN ASSERT ACK STA S5380+1 ; ASSERT ACK STA ICRVAL ; UPDATE ICR STILON: LDA S5380+4 ; READ CURRENT BUS STATUS AND #00100000b ; LOOK FOR NOT REQ BNE STILON ; IF NOT ZERO, STILL ON LDA #CMDCPL ; LOAD COMMAND COMPLETE ; ; LEAVE ACK ACTIVE SO MESSAGE CAN BE REJECTED ; CMP S5380+6 ; COMPARE W/MESSAGE BNE DIFMES ; IF NOT CMD COMPLTE, DIFF. LDA ICRVAL ; GET ICR VAL AND #11101111b ; MASK ACK BIT STA S5380+1 ; RESET ACK STA ICRVAL ; UPDATE ICR JMP NXT ; GO TO NEXT PHASE ; ; NOT MESSAGE COMPLETE, RETURN FOR EVALUATION ; DIFMES: LDX S5380+6 ; GET MESSAGE VALUE LDA #MESSAG ; LOAD MESSAGE RETN STATUS RTS ; RETURN FOR MESSAGE EVALUATION ; ; DMA INPUT ; DMAIN: LDA #00 ; ZERO ACCUM. TAX ; ZERO X ; ; RESET ASSERT DATA BUS ; LDA ICRVAL ; GET ICR VALUE AND #11111110b ; MASK ASSERT DATA BUS STA S5380+1 ; RESET ASSERT DATA BUS BIT STA ICRVAL ; UPDATE ICR ; ; WAIT FOR DRQ ; REPT1: BIT S5380+5 ; TEST FOR DRQ BVC REPT1 ; IF NOT THERE, LOOP ; GOI: LDA SDMA ; READ DMA PORT STA (BPNTR),Y ; STORE DATA IN BUFFER ;-------------------- INY ; INCR. POINTER CPY COUNT ; DONE? BNE REPT1 ; IF NOT ZERO, REPEAT INX ; ZERO, CHECK MULTIPLIER CPX XCNT ; COMPARE X WITH MULTIPLIER BEQ NXTPHS ; IF EQUAL, COUNT DONE BUMP: ; GREATER THAN 256 BYTES BUMP MSB INC BPNTR+1 JMP GOI ; GET MORE BYTES ; ; DMA OUTPUT ; DMAOUT: LDA #00000001b ; SET MASK ORA ICRVAL ; OR WITH ICR VALUE STA S5380+1 ; SET ASSERT DATA BUS BIT STA ICRVAL ; UPDATE ICR VALUE STA S5380+5 ; START DMA INIT SEND ; ; LOOK FOR DMA REQ (DRQ) ; LDA #00 ; ZERO ACCUM TAY ; ZERO Y TAX ; ZERO X REPT: BIT S5380+5 ; SAMPLE DRQ BVC REPT ; IF NOT SET, REPEAT GO: LDA (BPNTR),Y ; GET BYTE FROM BLOCK STA SDMA ; WRITE BYTE TO CHIP INY ; INC Y POINTER CPY COUNT ; COMPARE WITH BYTE CNT BNE REPT ; IF Y NOT EQ. SEND MORE INX ; IF EQUAL. INCR. X CPX XCNT ; COMPARE W/ MULTIPLIER BEQ NXTPHS ; IF EQ, NEXT PHASE MORE THAN 256 BUMP MSB INC BPNTR+1 ; SEND MORE DATA JMP GO ; ; NEXT PHASE ; NXTPHS: INC PHSIDX ; PHASE POINTER INDEX +3 INC PHSIDX INC PHSIDX RTS ; RETN TO INIT OR TRGT OPER .end