TITLE SCSI Interface fuer RUC 180 Karte
INCLUDE HD64180.LIB
.LIST
;****************************************************************
;
; S C S I
;
; Elementare Ein- und Ausgaben auf dem SCSI Interface
;
; Version 0.7, R. Ellerbrake
; Version 0.8 vom 31.12.86, M.Staubermann
;
; Copyright (C) 1985 by R. Ellerbrake
;
; Vers. 0.2: Kommando Transfer per DMA wieder eingebaut
; Vers. 0.3: Reset Signal implementiert
; Vers. 0.4: automatische Erkennung 40/80 Spuren Archiv
;
;****************************************************************
; Conditional Switches
FALSE EQU 0
TRUE EQU NOT FALSE
DMA EQU TRUE ;-1 = Daten nur per DMA ausgeben
EUMEL EQU TRUE ;EUMEL Version
SEC8 EQU FALSE ;-1 = 8 Sektor Floppy
TRK40 EQU FALSE ;-1 = Voreinst. 2x40 Spuren
DEBUG EQU FALSE ; Retries bei DMA/Hardwarefehler
;----------------------------------------------------------------
; Globale Adressen
GLOBAL SCSIIO, PHYSADR, INITS
GLOBAL HDIO, FDIO, INIFLP, INITS1, PARKHD
;
;----------------------------------------------------------------
; Externe Adressen
IF EUMEL
EXTERNAL WARTE
ENDIF
;----------------------------------------------------------------
; Port-Adressen
CIOAD EQU 52H ;Z8536 (CIO) Kanal A Daten
CIOCD EQU 50H ;Z8536 (CIO) Kanal C Daten
CIOCTL EQU 53H ;Z8536 (CIO) Control Register
SCSIP EQU 80H ;SCSI I/O Port
;................................................................
; Masken und Bits fuer CIO
MBUSY EQU 08H ;BUSY-Signal von SCSI Schnittstelle
MMSG EQU 10H ;Message-Signal von SCSI Schnittstelle
MDC EQU 20H ;Data(0)/Command(1) Sig. von SCSI
MREQ EQU 80H ;REQ-Signal vom SCSI-Controller
MIO EQU 04H ;I/O Signal von SCSI (0=Tr. Host -> SCSI)
MSELS EQU 02H ;Select Signal zum SCSI Interface
BSELS EQU 1 ;Bitnummern
BIO EQU 2
BBUSY EQU 3
BMSG EQU 4
BDC EQU 5
BREQ EQU 7
BRESS EQU 3 ;Reset-Signal fuer SCSI Controller
MRESS EQU 78H ;Maske zum Bit setzen (Bit 3)
PCOMA EQU 8 ;Port A Command and Status
;................................................................
; SCSI-Kommandos
TST_RDY EQU 0 ;Drive Ready pruefen
RECALIBR EQU 1 ;Drive recalibrieren
REQ_STAT EQU 3 ;Fehlerstatus holen
FORMAT EQU 4 ;Diskette oder Harddisk formatieren
CHK_FORM EQU 5 ;Harddisk Format kontrollieren
FRM_TRKS EQU 6 ;Spuren formatieren
SREAD EQU 8 ;Sektoren lesen (1 od. mehrere)
SVREAD EQU 9 ;Read Verify
SWRITE EQU 10 ;Sektoren schreiben (")
SEEK EQU 11 ;Auf Block positionieren
WBUFFER EQU 15 ;Write Controller Buffer
INITDRV EQU 17 ;Disk Parameter setzen
RINIT EQU 18 ;Disk Parameter lesen
FD48TPI EQU 6*32+4 ;Floppy im Doppelstepmodus betreiben
FD96TPI EQU 6*32+3 ;Floppy im Singlestepmodus betreiben
FDDRIV EQU 0 ;Floppy Laufwerk Nr.
;................................................................
; Werte fuer SCSIIO-Aufruf
DMATRA EQU 4000H ;Datentransfer per DMA
;DMATRA EQU 0 ;** TEST **
RDDAT EQU 8000H ;Lesen vom Controller
;................................................................
; DMA-Controller Werte
ENABDMA EQU 90H ;Enable Kanal 1 DMA (keine Interrupts)
DISDMA EQU 10H ;Disable Kanal 1 DMA (-> DSTAT)
DE1 EQU 7 ;Bitnummer in DSTAT
CH1MSK EQU 0F4H ;Nicht fuer Kanal 1 wichtige Bits maskieren
CHGDIR EQU 2 ;Aenderung der Transferrichtung (-> DCNTL)
;................................................................
; Fehlernummern
WPROTE EQU 13H ; Diskette Schreibgeschuetzt
TSNF EQU 14H ; Target Sector not found
HARD EQU 0F0H ;Kennung Hardware bzw. Kommandofehler
NOCONT EQU 0 ;SCSI-Controller nicht angeschlossen
TIMOUT EQU 1 ;Timeout Fehler bei SCSI I/O
ENDERR EQU 2 ;Falsches Kommandoende
ILLD EQU 3 ;Falsche Datenrichtung
EARLYE EQU 4 ;vorzeitiges Kommandoende
ILLCOM EQU 5 ;Fehler bei Kommandoausgabe
STRERR EQU 6 ;Fehler beim Status lesen
DMAERR EQU 7 ;Fehler beim DMA Transfer
UNKNOWN EQU 8 ;undefinierte Fehlerfaelle
MULCNT EQU 10 ; Reset nach 10 hardwarefehlern
;----------------------------------------------------------------
; Lokale Daten
DSEG
SCSIST: DEFS 4 ;4 Byte Stati
CODALN: DEFW 0 ;Datenlaenge
SEMA: DEFB 0 ;Zugriffs-Semaphor
TOFLG: DEFB 0 ;Timeoutflag
IF DEBUG
RETRCN: DEFB 4 ;Retry Flag
HERCNT: DEFB 10 ;Hardwarefehlerzaehler
ENDIF
CSEG
;****************************************************************
;
; SCSIIO
;
; Elementare Ausgabe auf SCSI-Interface
;
; Entry: HL = Zeiger auf Datenbereich (falls vorhanden)
; DE = Zeiger auf Kommandobereich (immer 6 Byte)
; BC = Groesse des Datenbereichs (0=nicht vorhanden)
; B Bit 7: 1 = Lesen vom SCSI-Controller
; 0 = Schreiben auf SCSI-Controller
; B Bit 6: 1 = Datentransfer per DMA
; 0 = Datentransfer per Programm
;
; Exit: A = Status (0 = ok, <>0 = Fehlercode)
; alle anderen Register (ausser AF) unveraendert
;
SCSIIO:
IF DEBUG
LD A,3 ;Retries bei Unknown Error
ENDIF
NRETSC:
IF DEBUG
LD (RETRCN),A
ENDIF
PUSH HL
PUSH BC
PUSH DE
CALL SCSI2 ;Kommando ausfuehren
LD L,A
AND 9FH ;Drive Code ausmaskieren
JR Z,EOCOM ;Kein Fehler ->
CP 2 ;SCSI-Fehler ?
LD A,L
JR NZ,EOCOM ;Nein -> fertig
POP HL ;Kommandotab.-Adr.
PUSH HL
LD A,(HL) ;altes Kommando retten
PUSH AF
LD A,HARD+STRERR ;Fehler beim Status lesen annehmen
LD (SCSIST),A
LD (HL),REQ_STAT ;Kommando 3: Request Status
EX DE,HL
LD BC,4+RDDAT ;4 Byte Status Informationen
LD HL,SCSIST ;Statusbereich
CALL SCSI2
POP AF
POP HL
LD (HL),A ;altes Kommando zurueckschreiben
PUSH HL
LD A,(SCSIST)
RES 7,A
AND A ;Meldung: kein Fehler ?
JR NZ,EOCOM
; kein Fehler: falsche Meldung da vorher einer aufgetreten war !!
LD A,HARD+UNKNOWN ;unbekannnter Fehler melden
EOCOM:
POP DE
POP BC
POP HL
IF DEBUG
CP HARD+ENDERR
JR C,RETSCSI
LD A,(RETRCN)
DEC A
JR NZ,NRETSC ;Retries bei "Unknown Error"
LD A,HARD+UNKNOWN
RETSCSI:
PUSH HL
LD HL,HERCNT ;Hardware Fehler Zaehler
CP HARD ;Hardware Fehler ?
JR C,NOHER ;Nein ->
DEC (HL)
JR NZ,EOHER ;nicht mehrere Hardwarefehler hintereinander
LD (HL),MULCNT
PUSH AF
PUSH DE
PUSH BC
CALL INITS1 ;Schnittstelle neu initialisieren
POP BC
POP DE
POP AF
JR EOHER
NOHER:
LD (HL),MULCNT
EOHER:
POP HL
ENDIF
AND A
RET
;................................................................
;
; SCSI2
;
; Kommandoausgabe auf dem SCSI-Interface
;
; Entry-Parameter wie SCSIIO
;
; Exit: A = 0: alles ok
; A = 2: Fehler ist aufgetreten
; A >= F0H: Hardware oder Bedienungsfehler
;
SCSI2:
PUSH BC ;Laenge retten
; Pruefen ob letzter DMA beendet wurde
IN0 A,(DSTAT) ;DMA beendet ?
BIT DE1,A
JR Z,DMAOK ;Ja ->
LD A,DISDMA ;Reset Kanal 1 DMA
OUT0 (DSTAT),A
DMAOK:
LD BC,CIOAD ;B=0 !
JR TENDLP
; "Bus free", Controller selektieren
BUSYOK:
IN A,(C)
SET BSELS,A ;Select Leitung aktivieren
OUT (C),A
RES BSELS,A ;und wieder zuruecknehmen
OUT (C),A
; "Command Phase"
XOR A
WAIREQ:
PUSH AF ;Auf Kommandoanforderung warten
IN A,(C)
AND MDC+MREQ+MIO+MMSG
CP MDC+MREQ
JR Z,RDYCOM ;Ok ->
POP AF
DEC A
JR NZ,WAIREQ
; keine Reaktion der Schnittstelle: Versuchen Restbytes einzulesen falls
; dies nicht der 2. Timeout ist.
LD A,(TOFLG) ;Timeoutflag gesetzt ?
AND A
LD A,HARD+TIMOUT ;Timeout Fehler
JP NZ,POPRET ;bereits gesetzt ->
LD (TOFLG),A ;Timeoutflag setzen
; ggf. letztes Kommando abschliessen
TENDLP:
IN0 A,(CIOAD) ;"Bus free" ?
BIT BBUSY,A
JR Z,BUSYOK ;Ja -> neu selektieren
CALL CHKREQ
BIT BIO,A
JR NZ,INPU
XOR A
OUT0 (SCSIP),A
JR TENDLP
INPU:
IN0 A,(SCSIP)
JR TENDLP
ILLMOD:
LD A,HARD+ILLCOM ;Fehler bei Kommandoausgabe
JP POPRET
; Kommando Ausgabe
RDYCOM:
POP AF ;Clear Stack
LD BC,SCSIP+6*256 ;6 Bytes ausgeben
EX DE,HL
CMNON:
CALL CHKREQ
CP MDC
JR NZ,ILLMOD ;keine Kommandoausgabe -> Fehler
DI
OTIM ;Kommando ausgeben
EI
JR NZ,CMNON ;Nicht fertig ->
; "Data Phase"
POP HL ;B=0!
PUSH HL
LD A,H ;Datenlaenge = 0 ?
AND 3FH ;Bit 6 und 7 ausblenden
OR L
JP Z,NODAT ;Ja -> keine Datenphase
IF NOT DMA
BIT 6,H ;Datentransfer per DMA ?
JR Z,DTAPROG ;Nein -> per Programm
ENDIF
; CIO Pattern Match Logik aktivieren
DI
LD C,CIOCTL ;CIO Control Register
LD A,PCOMA ;Port A Command Register
OUT (C),A
LD A,20H ;Clear IP & IUS
OUT (C),A
EI
;* IF DMA AND EUMEL
;* BIT 7,H ;schreiben ?
;* JR Z,POLWRIT
;* ENDIF
; DMA-Kanal 1 initialisieren (I/O Adresse wird in SCINIT gesetzt)
CALL DMASTUP ;DMA-Adressen eintragen
;* IF NOT EUMEL
BIT 7,H ;lesen ?
JR Z,ISWRITE ;Nein ->
;* ENDIF
OR CHGDIR ;Richtung aendern (I/O -> Memory)
ISWRITE:
OUT0 (DCNTL),A
LD A,ENABDMA ;DMA aktivieren
OUT0 (DSTAT),A
; Auf Kommandoende warten
; Die CIO ist so initialisiert dass der SCSI-Status "Status lesen"
; einen Pattern Match Zustand erzeugt
WEND2:
LD C,CIOCTL ;auf Pattern Match warten
WAIEND:
IN0 L,(DSTAT) ;DMA Status pruefen
DI
LD A,PCOMA ;Port A Command Register
OUT (C),A
IN A,(C) ;CIO Status lesen (Port A Statusregister)
BIT 5,A ;Interrupt pending ?
JR NZ,DATRDY ;Ja -> Datentransfer beendet
EI
IN0 A,(CIOAD)
BIT BBUSY,A ;steht Busy noch an ?
JR Z,ILLEND
BIT DE1,L ;DMA beendet ?
JR Z,DMAEND
NOEND:
IF EUMEL
CALL WARTE ;andere Tasks zulassen
ENDIF
JR WAIEND
; Pruefen ob ein DMA-Fehler aufgetreten ist
DMAEND:
IN0 A,(CIOAD)
BIT BREQ,A ;Anforderung ?
JR Z,NOEND ;Nein -> warten
AND MDC+MIO+MMSG
CP MDC+MIO ;Statusanforderung ?
JR Z,CMNST ;Ja -> alles in Ordnung
; Fehler beim DMA-Transfer
LD L,HARD+DMAERR
JR WENDLP
DATRDY:
IN A,(C) ;Pattern match testen
EI
BIT 1,A
JR Z,ENDKL ;Nein -> DMA hat Status geklaut
CMNST:
IN0 L,(SCSIP) ;Status holen
; Letztes Statusbyte holen (Kommandoende)
CALL CHKREQ
IN0 H,(SCSIP) ;letzten Status einlesen (Dummy Read)
CP MDC+MIO+MMSG ;wirklich letzter Status ?
JR Z,ENDOK ;Ja ->
ILLEND:
LD L,HARD+ENDERR
ENDOK:
LD A,L ;Status in A
POPRET:
POP BC
; Interrupt Daisy Chain der CIO freigeben
DI
LD L,PCOMA ;Port A Command
OUT0 (CIOCTL),L
LD L,20H ;Clear IP & IUS
OUT0 (CIOCTL),L
EI
RET
ENDKL:
; DMA anhalten falls dieser nicht beendet wurde
LD L,DISDMA ;Reset Kanal 1 DMA
OUT0 (DSTAT),L
LD L,2 ;Error Status
WENDLP:
IN0 A,(CIOAD) ;"Bus free" ?
BIT BBUSY,A
JR Z,ENDOK ;Ja -> fertig
CALL CHKREQ
BIT BIO,A
JR NZ,INPU2
XOR A
OUT0 (SCSIP),A
JR WENDLP
INPU2:
IN0 A,(SCSIP) ;Dummy Read
JR WENDLP
IF NOT DMA
; Datentransfer bei Schreiben per Programm
POLWRIT:
CALL CHKREQ
JR NZ,NODAT ;Kein Datentransfer -> Fehler
BIT BIO,A ;Lesen von SCSI ?
JR NZ,DIRERR ;Ja -> falsche Richtung
LD A,(DE) ;Daten holen
OUT0 (SCSIP),A ;und ausgeben
INC DE ;Datenadresse inkrementieren
DEC HL ;Datenlaenge dekrementieren
LD A,H ;Fertig ?
AND 3FH
OR L
JR NZ,POLWRIT ;Nein -> naechstes Byte holen
JP WEND2
; Falsche Datenrichtung (falsches Kommando)
DIRERR:
LD A,HARD+ILLD
JR POPRET
; Datentransfer per Programm
DTAPROG:
CALL CHKREQ
JR NZ,NODAT ;Kein Datentransfer -> Fehler
BIT BIO,A ;Lesen von SCSI ?
JR NZ,RDSCSI ;Ja ->
BIT 7,H ;Schreiben definiert ?
JR NZ,DIRERR ;Nein -> falsche Richtung !!
LD A,(DE) ;Daten holen
OUT0 (SCSIP),A ;und ausgeben
JR CMDIO
RDSCSI:
BIT 7,H ;Lesen definiert ?
JR NZ,RDSOK ;Ja ->
; Falsche Datenrichtung (falsches Kommando)
DIRERR:
LD A,HARD+ILLD
JR POPRET
RDSOK:
IN0 A,(SCSIP) ;Daten holen
LD (DE),A
CMDIO:
INC DE ;Datenadresse inkrementieren
DEC HL ;Datenlaenge dekrementieren
LD A,H ;Fertig ?
AND 3FH
OR L
JR NZ,DTAPROG ;Nein -> naechstes Byte holen
ENDIF
; Status lesen
NODAT:
CALL CHKREQ
CP MDC+MIO ;Status Anforderung ?
JR NZ,ILLEND ;Nein -> Fehler
JR CMNST
;................................................................
;
; Pruefen ob Busy und Request anstehen
;
; Exit: A = CIO Port A SCSI-Status Leitungen (ohne BUSY und REQ)
; F = Z: Datentransfer
;
CHKREQ:
IN0 A,(CIOAD)
BIT BBUSY,A ;Busy aktiv ?
JR Z,INCOMPL ;Nein -> vorzeitiges Kommandoende
BIT BREQ,A ;Anforderung ?
JR Z,CHKREQ ;Nein -> warten
AND MDC+MIO+MMSG
BIT BDC,A
RET
INCOMPL:
POP HL ;Skip Return Adresse
LD A,HARD+EARLYE ;vorzeitiges Ende
JR POPRET
;................................................................
;
; DMASTUP
;
; Adressen des DMA-Kanals 1 eintragen
;
; Entry: DE = log. Adresse
; DE = 0: auf 6502 Bereich FC00 schalten
;
; Exit: A = (DCNTL) Kanal 1
;
DMASTUP:
DI
LD A,D
OR E
JR NZ,DOCHG
LD A,6
LD D,0FDH ; 6FD00..6FEFF ist SCSI-Puffer
JR NOCHG
DOCHG:
CALL PHYSADR ;Physikalische Adresse bestimmen (in ADE)
NOCHG:
LD C,MAR1L ;Adressen eintragen
OUT (C),E ;Speicheradresse eintragen (LSB)
INC C
OUT (C),D ;mittleres Byte
INC C
OUT (C),A ;upper Byte
LD C,BCR1L
OUT (C),L ;Byte Zaehler (LSB)
INC C
LD A,H
AND 3FH
OUT (C),A ;MSB
IN0 A,(DCNTL) ;DMA-Richtung setzen
AND CH1MSK ;nur DMA-Kanal 1 Bits veraendern !
EI
RET
;................................................................
;
; P H Y S A D R
;
; Umrechnung der logischen in eine physikalische Adresse
;
; Entry: DE = logische Adresse im 64K Adressraum
;
; Exit: DE = niederwertiger Teil der phys. Adr. im 512K Adr.-raum
; A = hoechstwertiges Nibble der phys. Adr.
; alle anderen Register bleiben unveraendert
;
PHYSADR:
INC D ;Fuer Vergleiche
IN0 A,(CBAR) ;Common Bank Area Register
PUSH AF
AND 0F0H ;Common Area Teil ausmaskieren
CP D ;D >= Common Area 1 Anfang ?
JR C,COMA1 ;Ja -> (Stack!!)
POP AF
AND 0FH ;Bank Area Teil ausmaskieren
RLCA
RLCA
RLCA
RLCA ;und ins MSN schieben
CP D ;D >= Bank Area Anfang ?
JR C,BAR ;Ja ->
; Common Area 0 (unveraenderte Adresse)
DEC D ;D wieder korrigieren
XOR A
RET
; Bank Area
BAR:
DEC D
IN0 A,(BBR) ;Bank Base Register
CMND:
PUSH BC
LD B,0
SLA A
RL B
SLA A
RL B
SLA A
RL B
SLA A
RL B ;B = MSN Phys. Adr., A = mittleres MSB
ADD A,D ;+ Offset zum Area Anfang
LD D,A ;wieder in D (mittleres MSB der phys. Adr.)
LD A,B ;A = MSN
ADC A,0 ;ggf. 64K-Uebertrag beruecksichtigen
POP BC
RET
; Common Area 1
COMA1:
DEC D ;D wieder korrigieren
POP AF ;Clear Stack
IN0 A,(CBR)
JR CMND
IF EUMEL
;................................................................
;
; C H K A C C
;
; Auf Freiwerden des SCSI-Controllers warten
;
CHKACC:
LD A,(SEMA) ;SCSI-Zugriffssemaphor
AND A ;0=frei
JR Z,ISFREE ;Ja ->
CALL WARTE
JR CHKACC
ISFREE:
DEC A
LD (SEMA),A ;Semaphor sperren
RET
ENDIF
;................................................................
;
; I N I T S
;
; Initialisierung der SCSI-Schnittstelle
;
; CIO und DMA Kanal 1 werden initialisiert
; Floppy Parameter werden gesetzt
;
; Exit: AF', BC, DE und HL werden veraendert
; AF = Status des Floppy Parameters setzens
;
INITS1:
IF NOT EUMEL
CALL INICIO
ENDIF
INITS:
IF EUMEL
XOR A
LD (SEMA),A ;Semaphor initialisieren
ENDIF
LD C,DISDMA
OUT0 (DSTAT),C ;Kanal 1 stoppen, beide Kanaele keine
; Interrupts zulassen
; DMA - Kanal 0 intialisieren (Memory <--> Memory Transfer)
LD C,2 ; Memory <--> Memory im Burst Mode
OUT0 (DMODE),C
; DMA - Kanal 1 initialisieren (Memory <--> SCSI I/O - Transfer)
LD BC,SCSIP ;DMA-Kanal 1 I/O Adresse auf SCSI setzen
OUT0 (IAR1L),C
OUT0 (IAR1H),B
; Warten bis Harddisk hochgelaufen ist
IF NOT EUMEL
WRTHRD:
LD DE,TESTRD
LD BC,0
CALL SCSIIO
AND A ;Drive not Ready ?
JR NZ,WRTHRD ;Ja -> warten
ENDIF
; Teil der bei Controller RESET neu initialisert werden muss
SCINIT:
; Floppy Parameter setzen
LD DE,FLPINI ;Initialize Kommando
LD HL,FLPDAT ;Parameter
LD BC,PARALNG ;Anzahl der Parameter Bytes
CALL SCSIIO
LD L,A
LD A,(FLPTRKS)
CP 40 ;40 Tracks ?
LD A,L
LD BC,0
LD DE,SGLSTEP ; Floppy im Doppelstep Modus
JR NZ,NODBLS ;Nein -> kein Double Step
LD DE,DBLSTEP
NODBLS:
JP SCSIIO
;................................................................
;
; I N I C I O
;
IF NOT EUMEL
INICIO:
DI
; CIO initialisieren
IN0 C,(CIOCTL) ;Dummy Read
LD B,INILNG
LD HL,INITAB ;CIO Initialisierungstabelle
INILOP:
LD C,(HL) ;Wert holen
OUT0 (CIOCTL),C ;und ausgeben
INC HL
DJNZ INILOP
RET
ENDIF
;................................................................
;
; P A R K H D
;
; Harddisk in Parkposition fahren
;
PARKHD:
LD BC,0
LD DE,PARSEK ; seek (0)
CALL SCSIIO
LD DE,RECAL ; Recalibrate
JP SCSIIO
IF 0
LD HL,INIHDT
LD DE,RDINI
LD BC,RDDAT+PARALNG
CALL SCSIIO ;Harddisk Konfiguration lesen
LD HL,(INIHDT) ;Spuranzahl (H=LSB!)
PUSH HL
INC H ;um 1 erhoehen
JR NZ,INCOK
INC L
INCOK:
LD (INIHDT),HL
LD HL,RDINI
LD DE,INIHDT
LD (HL),INITDRV ;Init-Schreibkommando eintragen
EX DE,HL
LD BC,PARALNG
CALL SCSIIO ;neue, groessere, Konfiguration setzen
POP HL
LD D,L
LD L,H
LD H,D ;Spuranzahl richtig
LD A,(INIHDT+2) ;Kopfanzahl
LD E,L
HDLOP:
DEC A
JR Z,HDAOK
ADD HL,DE
JR HDLOP
HDAOK:
XOR A
ADC HL,HL
RLCA
ADC HL,HL ;*4
RLCA
ADC HL,HL ;*8
RLCA
ADC HL,HL ;*16
RLCA
ADC HL,HL ;*32
RLCA
; max. Blocknr. in AHL
DEC HL ;-1: 1.Block hinter formatiertem Bereich
LD (BKNR),A
LD A,L
LD L,H
LD H,A
LD (BKNR+1),HL ;Blocknr. eintragen
LD BC,0 ;keine Daten
LD DE,PARSEK
JP SCSIIO ;Drive parken
ENDIF
;................................................................
;
; H D I O
;
; Lesen / Schreiben eines Blocks (512 Byte) auf der Harddisk
;
; Entry: A = Kommandocode (0 = Lesen, 1 = Schreiben)
; HL = Hauptspeicheradresse
; BC = Pointer auf Drive und Offset (256 Byte Bloecke)
; DE = (512 Byte-) Blocknummer (ohne Offset)
;
; BC + 2 -> Low (Block Offset)
; BC + 1 -> Middle (Block Offset)
; BC + 0 -> High (BLock Offset) + Drive * 32
;
; Exit: A = Status (0=ok, sonst SCSIIO-Fehlercode)
; BC, DE, HL, AF' = veraendert
;
FDIO:
HDIO:
PUSH AF
XOR A
LD (TOFLG),A ;Timeoutflag ruecksetzen
IF EUMEL
CALL CHKACC ;Pruefen ob SCSI-Controller bereits belegt ist
ENDIF
LD A,(BC)
BIT 6,A ;Floppy Drive ?
JP NZ,FDIO1 ;Ja ->
POP AF
CP 2
JR C,COMOK1
LD A,20H ;illegal Command Code
RET
COMOK1:
PUSH HL
PUSH BC
CALL CMSCOM ;Kommandonr. umrechnen
LD (HDIOTB),A ;Kommando eintragen
POP BC
LD HL,(CODALN) ;Datenlaenge
PUSH HL
LD HL,HDIOTB+3 ;Harddisk Read Command
SLA E ;Blocknummer * 2 (256 Byte Bloecke)
RL D
CMFDIO:
INC BC
INC BC
LD A,(BC) ;Low Offset
ADD A,E ;+ Low Block No.
LD (HL),A ;eintragen
DEC HL
DEC BC
LD A,(BC) ;Middle Offset
ADC A,D ;+ Block No.
LD (HL),A
DEC HL
DEC BC
LD A,(BC)
LD (HL),A ;Drive + High Blocknr.
DEC HL
EX DE,HL ;DE = Read Command Adresse
POP BC ;Datenlaenge
POP HL ;Hauptspeicheradresse
CALL SCSIIO
IF EUMEL
PUSH AF
XOR A
LD (SEMA),A ;Semaphor freigeben
POP AF
ENDIF
RET
;................................................................
;
; I N I F L P
;
; Blockanzahl der Floppy ermitteln (nur BC, A und HL veraendern !!)
;
; Eingang:A = Anzahl Spuren, Voreinstellung (40 oder 80)
; Exit: BC = Blockanzahl der Floppy (in 512 Byte Bloecken)
; A = 0 = ok, <> 0 = SCSI-Fehlercode
;
INIFLP:
PUSH AF ; Anzahl Spuren Voreinstellung (40, 80)
IF EUMEL
CALL CHKACC ;keine Doppelzugriffe !!
ENDIF
XOR A
LD (TOFLG),A ;Timeoutflag ruecksetzen
POP AF
PUSH HL
PUSH DE
LD (FLPTRKS),A ;Spuren eintragen
CALL SCINIT ;Floppy Parameter setzen
LD A,2 ;Retry-Anzahl
RETR1:
PUSH AF
LD DE,SEK18 ; Auf Block 18 (Track 2)
LD BC,RDDAT+512
LD HL,0
LD A,1
CALL NRETSC ;Read ohne Retries
AND 7FH
LD C,A
JR Z,OKA ; Format ok
CP TSNF ; Target Sector not found ?
CALL Z,TOB ; anderes Format (B) versuchen
POP AF ; Anderer Floppy Fehler, Retries
DEC A
JR NZ,RETR1
XOR A
LD (SEMA),A
LD A,C ; permanenter Fehler
LD BC,0
POP DE
POP HL
RET
; auf B Spuren umschalten
TOB:
LD A,(FLPTRKS)
XOR 01111000B ; aus 40 wird 80, aus 80 wird 40
LD (FLPTRKS),A
CALL SCINIT ;Floppy Parameter setzen
LD C,TSNF
RET
OKA:
POP AF
POP DE
POP HL
LD BC,(FLPTRKS)
IF SEC8
LD B,8
ELSE
LD B,9
ENDIF
MLT BC
SLA C ;*2: 2 Seiten
RL B
XOR A
IF EUMEL
LD (SEMA),A ;Sempahor wieder freigeben
ENDIF
RET
;................................................................
;
; F D I O
;
; Lesen oder Schreiben eines Blocks (512 Byte) auf der Floppy Disk
;
; Entry: A = Kommandocode (0=Lesen, 1=Schreiben, 2=Formatieren)
; HL = Hauptspeicheradresse
; BC = Pointer auf Drive und Offset (512 Byte Bloecke)
; DE = (512 Byte-) Blocknummer (ohne Offset)
;
; BC + 2 -> Low (Block Offset)
; BC + 1 -> Middle (Block Offset)
; BC + 0 -> High (BLock Offset) + Drive * 32
;
; Exit: A = Status (0=ok, sonst SCSIIO-Fehlercode)
; BC, DE, HL, AF' = veraendert
;
FDIO1:
POP AF
CP 3
JR C,COMOK
LD A,20H ;illegal Command Code
RET
COMOK:
PUSH HL
PUSH BC
CP 2
CALL Z,SW80 ;Beim Formatieren immer 2x80 Spuren
CALL CMSCOM ;Kommando und Datenlaenge best.
LD (FDIOTB),A ;Kommandocode eintragen
LD A,C
LD (FDIOTB+4),A ;Block Count / Skew Faktor eintragen
; DE enthaelt Blocknummer x aus EUMEL-Sicht.
; Block x meint die 512 Bytes ab 512*x auf Floppy.
;
; Aus Blocknummer: Spur, Sector, Seite berechnen
;
; EUMEL behandelt, im Gegensatz zum SCSI-Controller,
; zunaechst die Oberseite der Floppy und erst dann die Unterseite.
LD H,D
LD L,E
XOR A
IF SEC8
LD DE,8
ELSE
LD DE,9 ;Anzahl der Sektoren pro Spur
ENDIF
DIVLOP:
AND A
SBC HL,DE
JR C,DIVDON
INC A
JR DIVLOP
DIVDON:
ADD HL,DE
; A = Spurnummer; HL = sector/seite
LD BC,(FLPTRKS) ;Spuren pro Seite (B undefiniert !)
CP C ;Rueckseite ?
JR C,NOBACK ;Nein -> alles ok
; Rueckseite: Spurnummer := Spurnummer - Spuranzahl
; Sektornummer := Sektornummer + Sektoranzahl (9)
SUB C ;tatsaechliche Spurnummer
ADD HL,DE ;HL = sector (cylinder)
; SCSI Blocknummer aus Spur und Sektor ausrechnen
NOBACK:
LD D,A
IF SEC8
LD E,16
ELSE
LD E,18
ENDIF
MLT DE ;DE = Spur * 18
ADD HL,DE ;HL = Spur * 18 + Sektor (cylinder)
EX DE,HL
; SCSI Blocknummer in DE
POP BC ;Offsetadresse wiederherstellen
LD HL,(CODALN)
PUSH HL
LD HL,FDIOTB+3 ;Floppy Read Command
JP CMFDIO
SW80:
PUSH AF
PUSH BC
PUSH DE
PUSH HL
LD A,80 ; 80 Tracks
LD (FLPTRKS),A
CALL SCINIT
POP HL
POP DE
POP BC
POP AF
RET
;................................................................
;
; C M S C O M
;
; Entry: A = Funktionsnr.
;
; Exit: A = SCSI-Kommandonr.
; C = Block Count / Skew Faktor
; HL = veraendert
; B = veraendert
; (CODALN) = Datenlaenge
;
CMSCOM:
LD BC,LGTAB ;Datenlaenge ermitteln
LD L,A
LD H,0
ADD HL,HL ;16 Bit Werte
ADD HL,BC
LD C,(HL)
INC HL
LD B,(HL)
LD (CODALN),BC
LD HL,COMTB ;Kommandonr. umrechnen
ADD A,L
LD L,A
LD A,H
ADC A,0
LD H,A
LD A,(HL) ;SCSI-Kommando holen
LD BC,BCSKTB-COMTB
ADD HL,BC
LD C,(HL) ;Block Count ./. Skew Faktor holen
RET
;****************************************************************
;
; SCSI-Kommandotabellen
;
; Achtung: Die Schreib- und Lesetabellen werden vom Programm
; geaendert (muessen im RAM stehen)
;
COMTB:
DEFB SREAD ;Lesekommando
DEFB SWRITE ;Schreibkommando
DEFB FORMAT ;Formatierkommando
LGTAB:
DEFW 512+DMATRA+RDDAT ;Datenlaenge Lesen
DEFW 512+DMATRA ;Datenlaenge schreiben
DEFW 0 ;Datenlaenge formatieren
BCSKTB:
DEFB 1 ;1 Block lesen (nur Floppy)
DEFB 1 ;1 Block schreiben (")
DEFB 4 ;Skew 4 (nur Floppy)
;................................................................
;
IF NOT EUMEL
TESTRD:
DEFB 0,0,0,0,0,0 ;Test Ready (Harddisk)
ENDIF
FDIOTB: ;Lesen / Schreiben auf Floppy Disk
DEFB SREAD ;Lesekommando (wird ueberschrieben)
DEFB FDDRIV*32+40H ;Floppy Drive (wird ueberschrieben)
DEFB 0, 0 ;Block Middle und Low (")
DEFB 1 ;Block Count / Interleave (Format)
DEFB 80H ;keine Retries
HDIOTB: ;Lesen / Schreiben auf Harddisk
DEFB SREAD ;Lesekommando (wird ueberschrieben)
DEFB 0 ;Harddisk Drive (wird ueberschrieben)
DEFB 0, 0 ;Block Middle und Low (")
DEFB 2 ;Block Count
DEFB 0H ;Retries
IF 0
RDINI:
DEFB RINIT ;Harddisk Konfiguration lesen
DEFB 0 ;Harddisk Drive
DEFB 0,0,0,0
INIHDT:
DEFB 0,0,0,0,0
DEFB 0,0,0,0,0
ENDIF
RECAL:
DEFB RECALIBR ;Drive recalibrieren
DEFB 0 ; Harddisk
DEFB 0,0,0,80H ; keine Retries
PARSEK:
DEFB SEEK
DEFB 0 ;Harddisk
DEFB 0,0,0
DEFB 80H ;keine Retries
FLPINI: ;Setze Floppy Parameter
DEFB INITDRV ;Initialize Kommando
DEFB FDDRIV*32+40H ;Floppy Drive
DEFB 0, 0, 0, 0 ;nicht benutzt
FLPDAT: ;Floppy Disk Parameter zu INIFLP
DEFB 0
FLPTRKS:
IF TRK40
DEFB 40 ;Spuranzahl
ELSE
DEFB 80
ENDIF
DEFB 2 ;2 Koepfe (doppelseitig)
DEFB 1*16+3 ;4 ms Steprate, MFM
DEFB 3 ;512 Byte/Sektor
DEFB 15 ;Head Unload Time (240ms)
DEFB 10 ;Motor Start Time (0.1 s)
DEFB 23 ;Head Load Time (46 ms)
DEFB 3 ;Motor off time (3 s)
IF SEC8
DEFB 0 ;8 Sektoren/Spur
ELSE
DEFB 1 ;9 Sektoren/Spur
ENDIF
PARALNG EQU $-FLPDAT
DBLSTEP:
DEFB FD48TPI ;Doppel Step aktivieren
DEFB FDDRIV*32+40H ;Floppy Drive
DEFB 0, 0, 0, 0 ;nicht benutzt
SGLSTEP:
DEFB FD96TPI ;auf Single Step zurueckschalten
DEFB FDDRIV*32+40H
DEFB 0, 0, 0, 0 ;nicht benutzt
SEK18:
DEFB SREAD ;auf Block positionieren
DEFB FDDRIV*32+40H ;Floppy Drive
DEFB 0,18,1,80H ;Track 2, ein Block, keine Retries
;...........................................................................
;
; CIO Initialisierungs Tabelle
;
IF NOT EUMEL
INITAB:
;* DEFB 0,1 ;Set Reset Bit
DEFB 0,0 ;Reset Reset Bit
DEFB 1,0 ;Master configuration control
; SCSI-Interface-Leitungen
DEFB 20H,00000010B ;Port A Mode Reg.
DEFB 22H,01000010B ;Port A Data Path Polarity Reg.
DEFB 23H,10111101B ;Port A Data Direction Reg.
DEFB 24H,0 ;Port A Special I/O Control
DEFB 25H,10101100B ;Port A Pattern Polarity
DEFB 26H,0 ;Port A Pattern Transition
DEFB 27H,10101100B ;Port A Pattern Mask
DEFB 0DH,0 ;Port A Data
DEFB 02H,18H ;Port A Interrupt Vector (** TEST **)
DEFB PCOMA,11100000B ;Port A Command: Clear IE
DEFB PCOMA,00100000B ;Port A Command: Clear IUS & IP
; General Purpose Port (Centronics, SCSI, 6502-IRQ-Maske)
DEFB 06H,00000001B ;Port C Data Direction Reg.
DEFB 05H,00001000B ;Port C Data Path Polarity Reg.
DEFB 07H,0 ;Port C Special I/O Control
DEFB 0FH,4 ;Port C Data Register
; Centronics Interface
DEFB 28H,10010000B ;Port B Mode
DEFB 29H,01000000B ;Port B Handshake: Strobed
DEFB 09H,00100000B ;Port B Command: Clear IUS & IP
DEFB 2AH,0 ;Port B Data Path Polarity
DEFB 2CH,0 ;Port B Special I/O Control
DEFB 03H,30H ;Port B Interrupt Vektor
; Deskew Timer
IF 0
DEFB 1EH,00000010B ;Counter 3 Mode Specification
DEFB 0CH,00100000B ;Counter 3 Command and Status
DEFB 1AH,0 ;Counter 3 Time Constant MSB
DEFB 1BH,7 ;Counter 3 Time Constant LSB (2,268 us)
DEFB 0CH,11100100B ;Counter 3 Gate Enable
ENDIF
; Timer
DEFB 1CH,10000000B ;Counter/Timer 1 Mode Spec. Reg.
DEFB 1DH,10000000B ;Counter/Timer 2 Mode Spec. Reg.
DEFB 0AH,00100000B ;Counter/Timer 1 Command: Clear IP & IUS
DEFB 0BH,00100000B ;Counter/Timer 2 Command: Clear IP & IUS
DEFB 16H,HIGH 38400 ;Time Constant 1 MSB
DEFB 17H,LOW 38400 ;Time Constant 1 LSB
DEFB 18H,0 ;Time Constant 2 MSB, mit Timer 1 zus. 50ms
DEFB 19H,4 ;Time Constant 2 LSB
DEFB 04H,18H ;Interrupt Vector Counters
; CIO-Interrupts freigeben
DEFB 01H,11110111B ;Master Config. Register
DEFB 00H,10000010B ;Master Interrupt Enable
DEFB 09H,11000000B ;Port B Command: Set IE
DEFB 0BH,11000110B ;Counter/Timer 2 Command: Set IE
DEFB 0AH,11100110B ;Counter/Timer 1 Command: Clear IE
INILNG EQU $-INITAB
ENDIF
;****************************************************************
END