home *** CD-ROM | disk | FTP | other *** search
- *
- * IEC.asm - IEC-Bus-Routinen, 1541-Emulation
- *
- * Copyright (C) 1994-1995 by Christian Bauer
- *
-
- *
- * Anmerkungen:
- * ------------
- *
- * Aufrufkonventionen:
- * - Die Routinen IECOut#? und IECIn geben in d0 den Status zurück.
- * Dieser wird von den aufrufenden Routinen mit dem C64-Statusbyte
- * ($90) verodert.
- * - Die Routinen dürfen nur d0-d1/a0-a1 verändern
- *
- * Funktionsweise:
- * - Am IEC-Bus gibt es drei Sorten von Geräten: Controller, Listener
- * und Talker. Der Controller sind immer wir, zusätzlich können wir
- * wahlweise Talker und Listener sein. Es kann immer nur einen Talker
- * und einen Listener geben (am echten IEC-Bus sind mehrere Listener
- * erlaubt, aber hier nicht).
- * - Die Geräte, die angesprochen werden, sind entweder real am IEC-Kabel
- * oder werden hier emuliert. Für jedes emulierte Laufwerk existiert
- * eine eigene Datenstruktur (Drv?Data). Ein Zeiger darauf wird bei
- * Talk/Listen in TalkerData/ListenerData gespeichert und steht den
- * nachfolgend aufgerufenen Routinen zur Verfügung, damit sich diese
- * um das jeweils angesprochene Laufwerk kümmern.
- * - Bei Geräten am Kabel wird #?Data nicht benutzt, da die Routinen
- * dann die Daten im wesentlichen einfach an den IEC-Bus durchreichen
- *
- * EOI/EOF:
- * - Im Gegensatz zum Amiga, wo der EOF-Zustand erst nach dem Lesen
- * des letzten Bytes erkannt wird, wird beim IEC-Bus das EOF
- * gleichzeitig mit dem letzten Byte gesendet. Daher verwenden die
- * Leseroutinen einen Puffer, in dem immer ein Byte bereitsteht.
- *
- * DRVDATA/drv_Type/drv_#?Proc:
- * - Jedem Laufwerk (8-11) ist eine Datenstruktur DRVDATA zugeordnet, die
- * u.a. den Typ des Laufwerks enthält (Amiga-Dateisystem, .d64-Datei,
- * IEC-Kabel).
- * - Je nach Typ werden die sechs Prozedurzeiger drv_InitProc, drv_ExitProc,
- * drv_OpenProc, drv_CloseProc, drv_ReadProc und drv_WriteProc gesetzt, um
- * entweder die Emulation im Amiga-Dateisystem oder in einer .d64-Datei
- * auszuwählen. Nur für Geräte am IEC-Kabel erfolgt die Ein-/Ausgabe
- * direkt hier, für die anderen Typen ist sie in den Include-Files
- * "1541fs.i" und "1541d64.i" gekapselt.
- * - Die drv_#?Proc-Zeiger bilden eine transparente Schnittstelle zur
- * Implementation eines Gerätes (im Prinzip ließe sich so auch eine
- * Druckeremulation einbauen):
- * drv_InitProc bereitet die Emulation vor
- * drv_ExitProc beendet die Emulation
- * drv_OpenProc öffnet einen Kanal
- * drv_CloseProc schließt einen Kanal
- * drv_ReadProc liest aus einem Kanal
- * drv_WriteProc schreibt in einen Kanal
- *
- * Inkompatibilitäten/Verbesserungen:
- * - Es kann nur ein Listener gleichzeitig aktiv sein
- *
-
- MACHINE 68020
-
- INCLUDE "exec/types.i"
- INCLUDE "exec/macros.i"
- INCLUDE "exec/memory.i"
- INCLUDE "dos/dos.i"
- INCLUDE "dos/dosasl.i"
- INCLUDE "resources/misc.i"
- INCLUDE "hardware/cia.i"
-
- XREF _SysBase
- XREF _DOSBase
- XREF _CiaBase
- XREF _MiscBase
- XREF _UtilityBase
-
- XREF _ciaaprb
- XREF _ciaaddrb
-
- XREF _FS_Init ;1541fs.o
- XREF _FS_Exit
- XREF _FS_Open
- XREF _FS_Close
- XREF _FS_Read
- XREF _FS_Write
-
- XREF _D64_Init ;1541d64.o
- XREF _D64_Exit
- XREF _D64_Open
- XREF _D64_Close
- XREF _D64_Read
- XREF _D64_Write
-
- XDEF InitIEC
- XDEF ExitIEC
- XDEF ChangedIECPrefs
- XDEF IECOut
- XDEF IECOutATN
- XDEF IECOutSec
- XDEF IECIn
- XDEF IECSetATN
- XDEF IECRelATN
- XDEF IECTurnaround
- XDEF IECRelease
- XDEF IECIsOpen
-
- XDEF Dir8 ;Prefs
- XDEF Dir9
- XDEF Dir10
- XDEF Dir11
- XDEF Drv8Type
- XDEF Drv9Type
- XDEF Drv10Type
- XDEF Drv11Type
- XDEF OtherIEC
- XDEF MapSlash
-
- XREF PDir8 ;Für ChangedIECPrefs
- XREF PDir9
- XREF PDir10
- XREF PDir11
- XREF PDrv8Type
- XREF PDrv9Type
- XREF PDrv10Type
- XREF PDrv11Type
-
- SECTION "text",CODE
-
-
- **
- ** Definitionen
- **
-
- ; 1541-Fehlercodes (genauer: Die Nummer des zugeh. Fehlertextes)
- ERR_OK = 0 ;00: OK
- ERR_WRITEERROR = 1 ;25: WRITE ERROR
- ERR_WRITEPROTECT = 2 ;26: WRITE PROTECT ON
- ERR_SYNTAX30 = 3 ;30: SYNTAX ERROR (Unbekannter Befehl)
- ERR_SYNTAX33 = 4 ;33: SYNTAX ERROR (Wildcards beim Schreiben)
- ERR_WRITEFILEOPEN = 5 ;60: WRITE FILE OPEN
- ERR_FILENOTOPEN = 6 ;61: FILE NOT OPEN
- ERR_FILENOTFOUND = 7 ;62: FILE NOT FOUND
- ERR_ILLEGALTS = 8 ;67: ILLEGAL TRACK OR SECTOR
- ERR_NOCHANNEL = 9 ;70: NO CHANNEL
- ERR_STARTUP = 10 ;73: Einschaltmeldung
-
- ; Datenstruktur für ein Laufwerk
- STRUCTURE DRVDATA,0
- BYTE drv_Type ;Laufwerks-Typ (DRTYPE_*)
- BYTE drv_ReadChar ;Byte-Puffer zum Lesen aus Dateien
- BYTE drv_NameLen ;Bisher empfangene Länge des Dateinamens
- BYTE drv_ErrorLen ;Restliche Länge der Fehlermeldung
- APTR drv_NamePtr ;Zeiger in Dateinamen, für Open/IECOut
- APTR drv_ErrorPtr ;Zeiger in Fehlermeldung
- APTR drv_Lock ;Lock des Verzeichnisses des Laufwerks
- ; bzw. Handle der .d64-Datei
-
- ;Prozeduren:
- APTR drv_InitProc ; Initialisieren
- APTR drv_ExitProc ; Beenden
- APTR drv_OpenProc ; Kanal öffnen
- APTR drv_CloseProc ; Kanal schließen
- APTR drv_ReadProc ; Byte lesen
- APTR drv_WriteProc ; Byte schreiben
-
- STRUCT drv_CmdBuffer,44 ;Eingabepuffer für Kommandos
- LONG drv_CmdLen ;Länge des bisher empfangenen Kommandos
-
- STRUCT drv_Handle,16*4 ;FS: FileHandles für alle 16 Kanäle
-
- STRUCT drv_ChanMode,16 ;D64: Kanalmodus
- STRUCT drv_ChanBufNum,16 ;D64: Nummer des Puffers des Kanals
- STRUCT drv_ChanBuf,16*4 ;D64: Zeiger auf Puffer des Kanals
- STRUCT drv_BufPtr,16*4 ;D64: Aktuelle Position im Puffer
- STRUCT drv_BufLen,16*4 ;D64: Restliche Anzahl Bytes im Puffer
-
- APTR drv_RAM ;D64: 2KB RAM für das Laufwerk
- STRUCT drv_BufFree,4 ;D64: Puffer 0..3 frei?
-
- LONG drv_ImageHeader ;D64: Länge des Headers der Image-Datei (.d64: 0, .x64: 64)
-
- APTR drv_BAM ;D64: Zeiger auf Puffer für BAM (Puffer 4, $700)
- STRUCT drv_DIR,256 ;D64: Temporärer Puffer zum Directory-Lesen und -Scannen
- LABEL drv_SIZEOF
-
- ; Drv?Type
- DRTYPE_DIR = 0 ;1541-Emulation in Amiga-Verzeichnis
- DRTYPE_D64 = 1 ;1541-Emulation in .d64-Datei
- DRTYPE_IEC = 2 ;Echte 1541 am IEC-Kabel
-
- ; C64-Status-Codes
- ST_OK = 0 ;Alles klar
- ST_READ_TIMEOUT = $02 ;Timeout beim Lesen
- ST_TIMEOUT = $03 ;Timeout
- ST_EOF = $40 ;End of file
- ST_NOTPRESENT = $80 ;Device not present
-
- ; IEC-Befehlscodes
- CMD_DATA = $60
- CMD_CLOSE = $e0
- CMD_OPEN = $f0
-
- ; Länge des Namenspuffers, muß zwischen 32 und 256 liegen
- NAMEBUF_LENGTH = 256
-
- ; Makros für IEC-Kabel
- DATA_HI MACRO
- bclr #5,_ciaaprb
- ENDM
-
- DATA_LO MACRO
- bset #5,_ciaaprb
- ENDM
-
- CLOCK_HI MACRO
- bclr #4,_ciaaprb
- ENDM
-
- CLOCK_LO MACRO
- bset #4,_ciaaprb
- ENDM
-
- ATN_HI MACRO
- bclr #3,_ciaaprb
- ENDM
-
- ATN_LO MACRO
- bset #3,_ciaaprb
- ENDM
-
- LINE_RELEASE MACRO
- ATN_HI
- bsr Wait40us
- CLOCK_HI
- DATA_HI
- ENDM
-
- ; Data -> Carry, Clock -> Negative
- GET_DATA_CLOCK MACRO
- \@1$ move.b _ciaaprb,d0
- cmp.b _ciaaprb,d0
- bne \@1$
- add.b d0,d0
- ENDM
-
- WAIT_CLOCK_HI MACRO
- \@1$ GET_DATA_CLOCK
- bpl \@1$
- ENDM
-
- WAIT_CLOCK_LO MACRO
- \@1$ GET_DATA_CLOCK
- bmi \@1$
- ENDM
-
- WAIT_DATA_HI MACRO
- \@1$ GET_DATA_CLOCK
- bcc \@1$
- ENDM
-
- WAIT_DATA_LO MACRO
- \@1$ GET_DATA_CLOCK
- bcs \@1$
- ENDM
-
-
- **
- ** IEC-Emulation starten
- **
- ** Rückgabe: d0=0 Alles OK
- ** d0=1 Parallelport belegt
- ** d0=2 Kein Timer frei
- **
-
- ; Emulation aller 4 Laufwerke vorbereiten
- InitIEC lea Drv8Data,a0
- move.w Drv8Type,d0
- bsr SetDrvProcs
-
- pea Dir8
- pea Drv8Data
- move.l Drv8Data+drv_InitProc,a0
- jsr (a0)
- addq.l #8,sp
-
- lea Drv9Data,a0
- move.w Drv9Type,d0
- bsr SetDrvProcs
-
- pea Dir9
- pea Drv9Data
- move.l Drv9Data+drv_InitProc,a0
- jsr (a0)
- addq.l #8,sp
-
- lea Drv10Data,a0
- move.w Drv10Type,d0
- bsr SetDrvProcs
-
- pea Dir10
- pea Drv10Data
- move.l Drv10Data+drv_InitProc,a0
- jsr (a0)
- addq.l #8,sp
-
- lea Drv11Data,a0
- move.w Drv11Type,d0
- bsr SetDrvProcs
-
- pea Dir11
- pea Drv11Data
- move.l Drv11Data+drv_InitProc,a0
- jsr (a0)
- addq.l #8,sp
-
- ; Flag setzen
- st.b IECInited
-
- ; Resourcen für das IEC-Kabel belegen, wenn nötig
- bra CheckCablePrefs
-
-
- **
- ** IEC-Emulation beenden
- **
-
- ; Resourcen des IEC-Kabels freigeben
- ExitIEC bsr CloseIECBus
-
- ; Emulation aller 4 Laufwerke beenden
- tst.b IECInited
- beq 1$
-
- pea Drv8Data
- move.l Drv8Data+drv_ExitProc,a0
- jsr (a0)
- addq.l #4,sp
-
- pea Drv9Data
- move.l Drv9Data+drv_ExitProc,a0
- jsr (a0)
- addq.l #4,sp
-
- pea Drv10Data
- move.l Drv10Data+drv_ExitProc,a0
- jsr (a0)
- addq.l #4,sp
-
- pea Drv11Data
- move.l Drv11Data+drv_ExitProc,a0
- jsr (a0)
- addq.l #4,sp
- 1$
-
- ; Temporäre Datei löschen
- move.l _DOSBase,a6
- move.l #TempFileName,d1
- JMPLIB DeleteFile
-
-
- **
- ** IEC-Einstellungen wurden verändert
- ** Rückgabe: d0=0 Alles OK
- ** d0=1 Parallelport belegt
- ** d0=2 Kein Timer frei
- **
-
- ; Laufwerke schließen und neu öffnen, wenn sich die Einstellungen geändert haben
- ChangedIECPrefs lea Drv8Data,a3
- lea Dir8,a4
- lea PDir8,a5
- move.w PDrv8Type,d4
- bsr DrvReInit
-
- lea Drv9Data,a3
- lea Dir9,a4
- lea PDir9,a5
- move.w PDrv9Type,d4
- bsr DrvReInit
-
- lea Drv10Data,a3
- lea Dir10,a4
- lea PDir10,a5
- move.w PDrv10Type,d4
- bsr DrvReInit
-
- lea Drv11Data,a3
- lea Dir11,a4
- lea PDir11,a5
- move.w PDrv11Type,d4
- bsr DrvReInit
-
- ; Einstellungen übertragen
- CheckCablePrefs moveq #0,d1
-
- cmp.w #DRTYPE_IEC,PDrv8Type
- seq d0
- or.b d0,d1
-
- cmp.w #DRTYPE_IEC,PDrv9Type
- seq d0
- or.b d0,d1
-
- cmp.w #DRTYPE_IEC,PDrv10Type
- seq d0
- or.b d0,d1
-
- cmp.w #DRTYPE_IEC,PDrv11Type
- seq d0
- or.b d0,d1
-
- or.w OtherIEC,d1 ;d1: Flag: IEC-Kabel wird benötigt
-
- ; IEC öffnen, wenn mindestens ein Gerät mit IEC laufen soll,
- ; sonst schließen
- tst.b d1
- beq CloseIECBus
- bra OpenIECBus
-
-
- *
- * Auf Benutzung des IEC-Kabels vorbereiten
- * Rückgabe: d0=0 Alles OK
- * d0=1 Parallelport belegt
- * d0=2 Kein Timer frei
- *
-
- OpenIECBus move.l a6,-(sp)
- tst.b IECIsOpen ;Kann auch mehrmals aufgerufen werden
- bne OIECOK
-
- ; Parallelport belegen
- move.l _MiscBase,d0
- beq OIECNoPort
- move.l d0,a6
- moveq #MR_PARALLELPORT,d0
- lea ParPortName,a1
- JSRLIB AllocMiscResource
- tst.l d0
- bne OIECNoPort
-
- move.b #$00,_ciaaprb ;Port inaktiv
- move.b #$38,_ciaaddrb ;DDR konfigurieren
-
- ; Timer A belegen
- move.l _CiaBase,a6
- lea TimerInterrupt,a1
- moveq #CIAICRB_TA,d0
- JSRLIB AddICRVector
- tst.l d0
- bne 1$
-
- ; Gelungen
- move.b #CIAICRB_TA,WhichTimer
- move.b #CIAICRF_TA,WhichTimerMask
- move.l #$bfe401,CiaTimerReg
- move.l #$bfee01,CiaControlReg
- bra 3$
-
- ; Nicht gelungen, dann Timer B probieren
- 1$ lea TimerInterrupt,a1
- moveq #CIAICRB_TB,d0
- JSRLIB AddICRVector
- tst.l d0
- bne 2$
-
- ; Gelungen
- move.b #CIAICRB_TB,WhichTimer
- move.b #CIAICRF_TB,WhichTimerMask
- move.l #$bfe601,CiaTimerReg
- move.l #$bfef01,CiaControlReg
- bra 3$
-
- ; Nicht gelungen, dann Parallelport wieder freigeben
- 2$ move.b #$00,_ciaaddrb ;Port auf Eingabe
-
- move.l _MiscBase,a6
- moveq #MR_PARALLELPORT,d0
- JSRLIB FreeMiscResource
-
- moveq #2,d0 ;Kein Timer frei
- move.l (sp)+,a6
- rts
-
- ; Alles klar, Timer-Interrupt abschalten und Timer stoppen
- 3$ move.b WhichTimerMask,d0
- JSRLIB AbleICR
-
- move.l CiaControlReg,a0
- and.b #$80,(a0)
-
- st.b IECIsOpen
- OIECOK moveq #0,d0 ;Alles OK
- move.l (sp)+,a6
- rts
-
- OIECNoPort moveq #1,d0 ;Parallelport belegt
- move.l (sp)+,a6
- rts
-
-
- *
- * Benutzung des IEC-Kabels beenden
- * Rückgabe: d0=0
- *
-
- CloseIECBus tst.b IECIsOpen
- beq 1$
-
- move.b #$00,_ciaaddrb ;Port auf Eingabe
-
- move.l a6,-(sp) ;Parallelport freigeben
- move.l _MiscBase,a6
- moveq #MR_PARALLELPORT,d0
- JSRLIB FreeMiscResource
-
- move.l CiaControlReg,a0 ;Timer stoppen
- and.b #$80,(a0)
-
- move.l _CiaBase,a6
- lea TimerInterrupt,a1
- move.b WhichTimer,d0
- JSRLIB RemICRVector
-
- move.l (sp)+,a6
- clr.b IECIsOpen
-
- 1$ moveq #0,d0
- rts
-
-
- *
- * Laufwerk neu initialisieren, falls nötig
- *
- * a3.l: Zeiger auf DRVDATA
- * a4.l: Alter Verzeichnis-String
- * a5.l: Neuer Verzeichnis-String
- * d4.w: Neues Drv?Type
- *
-
- DrvReInit move.l _UtilityBase,a6
-
- move.l a4,a0 ;Hat sich das Verzeichnis/die Datei geändert?
- move.l a5,a1
- move.l #255,d0
- JSRLIB Strnicmp
- tst.l d0
- bne 1$
-
- cmp.b drv_Type(a3),d4 ;Nein, hat sich der Typ geändert?
- beq 2$
-
- 1$ move.l a3,-(sp) ;Ja, Exit aufrufen
- move.l drv_ExitProc(a3),a0
- jsr (a0)
- addq.l #4,sp
-
- move.l a3,a0 ;Neue Prozeduren setzen
- move.w d4,d0
- bsr SetDrvProcs
-
- move.l a5,-(sp) ;Und neues Init aufrufen
- move.l a3,-(sp)
- move.l drv_InitProc(a3),a0
- jsr (a0)
- addq.l #8,sp
- 2$ rts
-
-
- *
- * Prozeduren in DRVDATA je nach Typ setzen
- *
- * a0.l: Zeiger auf DRVDATA
- * d0.w: Drv?Type
- *
-
- SetDrvProcs move.b d0,drv_Type(a0) ;Typ setzen
-
- cmp.w #DRTYPE_D64,d0
- beq 1$
-
- move.l #_FS_Init,drv_InitProc(a0)
- move.l #_FS_Exit,drv_ExitProc(a0)
- move.l #_FS_Open,drv_OpenProc(a0)
- move.l #_FS_Close,drv_CloseProc(a0)
- move.l #_FS_Read,drv_ReadProc(a0)
- move.l #_FS_Write,drv_WriteProc(a0)
- rts
-
- 1$ move.l #_D64_Init,drv_InitProc(a0)
- move.l #_D64_Exit,drv_ExitProc(a0)
- move.l #_D64_Open,drv_OpenProc(a0)
- move.l #_D64_Close,drv_CloseProc(a0)
- move.l #_D64_Read,drv_ReadProc(a0)
- move.l #_D64_Write,drv_WriteProc(a0)
- rts
-
-
- **
- ** IECOut - Ein Byte ausgeben
- ** d0.b: Byte
- ** d1.b: <0: EOI-Flag
- **
-
- IECOut tst.b ListenerIsIEC ;Listener am IEC-Kabel?
- bne IECByteOut ;Ja, dann Byte über Kabel senden
- tst.b ListenerActive ;Wurde ein Gerät angesprochen?
- beq 1$
-
- cmp.b #CMD_OPEN,ReceivedCmd
- beq OpenOut
- cmp.b #CMD_DATA,ReceivedCmd
- beq DataOut
-
- 1$ move.b #ST_TIMEOUT,d0 ;Kein Listener aktiv oder kein gültiger Befehl
- rts
-
-
- **
- ** IECOutATN - Ein Byte mit ATN ausgeben (Talk/Listen/Untalk/Unlisten)
- ** d0.b: Byte
- **
-
- IECOutATN clr.b SecAddr ;Befehl kommt mit der Sekundäradresse danach
- clr.b ReceivedCmd
-
- move.b d0,d1
- and.b #$0f,d0 ;d0.b: Gerätenummer
- and.b #$f0,d1 ;d1.b: Funktion
-
- st.b Listening ;Funktion auswerten
- cmp.b #$20,d1 ;Bei Listen ist das Flag Listening gesetzt
- beq Listen
- clr.b Listening
- cmp.b #$30,d1
- beq Unlisten
- cmp.b #$40,d1
- beq Talk
- cmp.b #$50,d1
- beq Untalk
-
- move.b #ST_TIMEOUT,d0 ;Ungültige Funktion
- rts
-
-
- **
- ** IECOutSec - Sekundäradresse ausgeben
- ** d0.b: Sekundäradresse
- **
-
- IECOutSec tst.b Listening ;Nach Listen oder nach Talk?
- beq 1$
-
- tst.b ListenerIsIEC ;Nach Listen: Listener am IEC-Kabel?
- bne IECByteOutSec
- tst.b ListenerActive ;Wurde ein Gerät angesprochen?
- beq 2$
-
- move.b d0,d1
- and.b #$0f,d0 ;Sekundäradresse
- move.b d0,SecAddr
- and.b #$f0,d1 ;und Befehlscode speichern
- move.b d1,ReceivedCmd
- bra SecListen ;Sek.adr nach Listen
-
- 1$ tst.b TalkerIsIEC ;Nach Talk: Talker am IEC-Kabel?
- bne IECByteOutSec
- tst.b TalkerActive ;Wurde ein Gerät angesprochen?
- beq 2$
-
- move.b d0,d1
- and.b #$0f,d0 ;Sekundäradresse
- move.b d0,SecAddr
- and.b #$f0,d1 ;und Befehlscode speichern
- move.b d1,ReceivedCmd
- bra SecTalk ;Sek.adr nach Talk
-
- 2$ move.b #ST_TIMEOUT,d0 ;Es erfolgte kein Listen/Talk
- rts
-
-
- **
- ** IECIn - Ein Byte einlesen
- ** RÜckgabe: d1.b: Byte
- **
-
- IECIn tst.b TalkerIsIEC ;Talker am IEC-Kabel?
- bne IECByteIn
- tst.b TalkerActive ;Wurde ein Gerät angesprochen?
- beq 1$
-
- cmp.b #CMD_DATA,ReceivedCmd
- beq DataIn
-
- 1$ move.b #ST_TIMEOUT,d0 ;Kein Talk bzw. kein CMD_DATA
- clr.b d1
- rts
-
-
- **
- ** IECSetATN - ATN setzen (für Untalk)
- **
-
- IECSetATN tst.b TalkerIsIEC ;Nur bei IEC-Geräten etwas machen
- beq 1$
- CLOCK_LO
- ATN_LO
- 1$ rts
-
-
- **
- ** IECRelATN - ATN wegnehmen
- **
-
- IECRelATN tst.b IECIsOpen
- beq 1$
- ATN_HI
- bsr Wait20us
- 1$ rts
-
-
- **
- ** IECTurnaround - Talk-attention turn around
- **
-
- IECTurnaround tst.b TalkerIsIEC ;Nur bei IEC-Geräten etwas machen
- beq 1$
- move.l a6,-(sp)
- move.l _SysBase,a6
- JSRLIB Disable
- DATA_LO
- bsr Wait20us
- ATN_HI
- CLOCK_HI
- WAIT_CLOCK_LO
- bsr Wait60us
- JSRLIB Enable
- move.l (sp)+,a6
- 1$ rts
-
-
- **
- ** IECRelease - System line release
- **
-
- IECRelease tst.b IECIsOpen
- beq 1$
- LINE_RELEASE
- 1$ rts
-
-
- *
- * Listen
- * d0.b: Gerätenummer
- * d1.b: Funktion
- *
-
- Listen cmp.b #8,d0 ;Gerät zwischen 8 und 11?
- blo ListenOther
- cmp.b #11,d0
- bhi ListenOther
-
- moveq #0,d1 ;Ja, Zeiger auf Datenbereich holen
- move.b d0,d1
- subq.b #8,d1
- move.l (DrvTab,d1.w*4),a0
- cmp.b #DRTYPE_IEC,drv_Type(a0) ;IEC-Gerät?
- beq ListenIEC
- tst.l drv_Lock(a0) ;Nein, Verzeichnis vorhanden?
- beq ListenNotPr
-
- move.l a0,ListenerData ;Ja, Zeiger auf Datenbereich sichern
- st.b ListenerActive ;Listener ist aktiv
- clr.b ListenerIsIEC
- moveq #ST_OK,d0
- rts
-
- ; Anderes Gerät außer 8..11
- ListenOther tst.w OtherIEC
- beq ListenNotPr
-
- ; Listen über IEC-Kabel
- ListenIEC move.l a0,ListenerData ;Zeiger auf Datenbereich sichern
-
- moveq #$20,d1 ;Listen über Kabel senden
- bsr IECByteOutATN
- cmp.b #ST_NOTPRESENT,d0
- beq ListenNotPr
- st.b ListenerIsIEC ;Gelungen, Listener ist aktiv
- rts
-
- ; Gerät nicht vorhanden
- ListenNotPr move.b #ST_NOTPRESENT,d0
- clr.b ListenerActive
- clr.b ListenerIsIEC
- rts
-
-
- *
- * Talk
- * d0.b: Gerätenummer
- * d1.b: Funktion
- *
-
- Talk cmp.b #8,d0 ;Gerät zwischen 8 und 11?
- blo TalkOther
- cmp.b #11,d0
- bhi TalkOther
-
- moveq #0,d1 ;Ja, Zeiger auf Datenbereich holen
- move.b d0,d1
- subq.b #8,d1
- move.l (DrvTab,d1.w*4),a0
- cmp.b #DRTYPE_IEC,drv_Type(a0) ;IEC-Gerät?
- beq TalkIEC
- tst.l drv_Lock(a0) ;Nein, Verzeichnis vorhanden?
- beq TalkNotPr
-
- move.l a0,TalkerData ;Ja, Zeiger auf Datenbereich sichern
- st.b TalkerActive ;Talker ist aktiv
- clr.b TalkerIsIEC
- moveq #ST_OK,d0
- rts
-
- ; Anderes Gerät außer 8..11
- TalkOther tst.w OtherIEC
- beq TalkNotPr
-
- ; Talk über IEC-Kabel
- TalkIEC move.l a0,TalkerData ;Zeiger auf Datenbereich sichern
-
- moveq #$40,d1 ;Talk über Kabel senden
- bsr IECByteOutATN
- cmp.b #ST_NOTPRESENT,d0
- beq TalkNotPr
- st.b TalkerIsIEC ;Gelungen, Talker ist aktiv
- rts
-
- ; Gerät nicht vorhanden
- TalkNotPr move.b #ST_NOTPRESENT,d0
- clr.b TalkerActive
- clr.b TalkerIsIEC
- rts
-
-
- *
- * Unlisten
- * d0.b: Gerätenummer
- * d1.b: Funktion
- *
-
- Unlisten tst.b ListenerIsIEC ;Listener am IEC-Kabel?
- beq 1$
- bsr IECByteOutATN ;Ja, Unlisten über Kabel senden
- bra 2$
-
- 1$ moveq #ST_OK,d0
- 2$ clr.b ListenerActive ;Gerät nicht mehr aktiv
- clr.b ListenerIsIEC
- rts
-
- *
- * Untalk
- * d0.b: Gerätenummer
- * d1.b: Funktion
- *
-
- Untalk tst.b TalkerIsIEC ;Talker am IEC-Kabel?
- beq 1$
- bsr IECByteOutATN ;Ja, Untalk über Kabel senden
- bra 2$
-
- 1$ moveq #ST_OK,d0
- 2$ clr.b TalkerActive ;Gerät nicht mehr aktiv
- clr.b TalkerIsIEC
- rts
-
-
- *
- * SecListen - Sekundäradresse nach Listen
- * d0.b: Sekundäradresse
- * d1.b: Befehlscode
- *
-
- SecListen cmp.b #CMD_OPEN,d1
- beq SecListenOpen
- cmp.b #CMD_CLOSE,d1
- beq SecListenClose
-
- moveq #ST_OK,d0
- rts
-
-
- *
- * Open-Befehl: Auf Empfang des Dateinamens vorbereiten
- *
-
- SecListenOpen move.l ListenerData,a0
- move.l #NameBuf,drv_NamePtr(a0)
- clr.b drv_NameLen(a0)
- moveq #ST_OK,d0
- rts
-
-
- *
- * Close-Befehl: Kanal schließen
- *
-
- SecListenClose move.l ListenerData,a0
- moveq #0,d0
- move.b SecAddr,d0
- move.l d0,-(sp)
- move.l a0,-(sp)
- move.l drv_CloseProc(a0),a0
- jsr (a0)
- addq.l #8,sp
- rts
-
-
- *
- * SecTalk - Sekundäradresse nach Talk
- * d0.b: Sekundäradresse
- * d1.b: Befehlscode
- *
-
- SecTalk moveq #ST_OK,d0
- rts
-
-
- *
- * Byte nach Open-Befehl: Zeichen im Dateinamen speichern, bei EOI Datei öffnen
- * d0.b: Byte
- * d1.b: EOI-Flag
- *
-
- OpenOut move.l ListenerData,a0
- cmp.b #NAMEBUF_LENGTH-1,drv_NameLen(a0) ;Noch genügend Platz im NameBuffer?
- bhs 2$
- move.l drv_NamePtr(a0),a1 ;Ja, Zeichen speichern
- move.b d0,(a1)+
- move.l a1,drv_NamePtr(a0)
- addq.b #1,drv_NameLen(a0)
-
- 2$ tst.b d1 ;EOI?
- bpl 1$
-
- move.l ListenerData,a0 ;Ja, Datei öffnen
- move.l drv_NamePtr(a0),a1 ;Dateiname mit Nullbyte abschließen
- clr.b (a1)
- pea NameBuf
- moveq #0,d0
- move.b SecAddr,d0
- move.l d0,-(sp)
- move.l a0,-(sp)
- move.l drv_OpenProc(a0),a0
- jsr (a0)
- lea 12(sp),sp
-
- 1$ moveq #ST_OK,d0
- rts
-
-
- *
- * Zeichen aus Datenkanal lesen
- * RÜckgabe: d1.b: Byte
- *
-
- DataIn move.l TalkerData,a0
- moveq #0,d0
- move.b SecAddr,d0
- pea DataInBuf
- move.l d0,-(sp)
- move.l a0,-(sp)
- move.l drv_ReadProc(a0),a0
- jsr (a0)
- lea 12(sp),sp
- move.b DataInBuf,d1
- rts
-
-
- *
- * Byte nach Data-Befehl: Zeichen in Datei schreiben
- * d0.b: Byte
- * d1.b: EOI-Flag
- *
-
- DataOut move.l ListenerData,a0
- move.l d1,-(sp)
- move.l d0,-(sp)
- moveq #0,d0
- move.b SecAddr,d0
- move.l d0,-(sp)
- move.l a0,-(sp)
- move.l drv_WriteProc(a0),a0
- jsr (a0)
- lea 16(sp),sp
- rts
-
-
- *
- * Byte mit ATN über IEC-Kabel senden
- * d0.b: Gerätenummer
- * d1.b: Funktion
- *
-
- IECByteOutATN tst.b IECIsOpen
- bne 1$
- move.b #ST_NOTPRESENT,d0
- rts
-
- 1$ movem.l d2/d7/a6,-(sp)
- move.b d0,d2
- or.b d1,d2 ;d2: Auszugebendes Byte
-
- move.l _SysBase,a6
- JSRLIB Disable
-
- DATA_HI
- ATN_LO
- bra IECByteOutSec2 ;ATN response abwarten und Byte ausgeben
-
-
- *
- * Sekundäradresse über IEC-Kabel senden
- * d0.b: Sekundäradresse
- *
-
- IECByteOutSec tst.b IECIsOpen
- bne 1$
- move.b #ST_NOTPRESENT,d0
- rts
-
- 1$ movem.l d2/d7/a6,-(sp)
- move.b d0,d2 ;d2: Auszugebendes Byte
-
- move.l _SysBase,a6
- JSRLIB Disable
-
- IECByteOutSec2 CLOCK_LO
- DATA_HI
- bsr Wait1ms ;Max ATN response abwarten
- moveq #0,d1 ;Kein EOI
- bra IECByteOut2 ;Byte ausgeben
-
-
- *
- * Byte über IEC-Kabel senden
- * d0.b: Byte
- * d1.b: EOI-Flag
- *
-
- IECByteOut tst.b IECIsOpen
- bne 1$
- move.b #ST_NOTPRESENT,d0
- rts
-
- 1$ movem.l d2/d7/a6,-(sp)
- move.b d0,d2 ;d2: Auszugebendes Byte
-
- move.l _SysBase,a6
- JSRLIB Disable
-
- ; Übertragung einleiten
- IECByteOut2 move.b d1,d7 ;d7: EOI-Flag
- DATA_HI
- GET_DATA_CLOCK ;Data bleibt high -> Device not present
- bcs IBODevNotPr
- CLOCK_HI ;Talker ready
-
- WAIT_DATA_HI ;Warten auf Listener ready for data
-
- tst.b d7 ;EOI?
- bpl 1$
-
- WAIT_DATA_LO ;Ja, EOI-Handshake abwarten
- WAIT_DATA_HI
-
- 1$ CLOCK_LO ;Talker sending
-
- bsr Wait40us ;Wichtige Verzögerung, aber wozu?
-
- ; 8 Bits übertragen
- moveq #7,d7 ;d7: Bitzähler
- IBOBitLoop GET_DATA_CLOCK ;Data low -> Time out
- bcc IBOTimeOut
-
- lsr.b #1,d2 ;Nächstes Bit holen
- bcc 1$ ;und ausgeben
- DATA_HI
- bra 2$
- 1$ DATA_LO
- 2$
- bsr Wait40us ;Bit set-up talker delay
-
- CLOCK_HI ;Data valid
-
- bsr Wait20us ;Data valid delay
-
- DATA_HI
- CLOCK_LO
-
- dbra d7,IBOBitLoop ;Nächstes Bit
-
- ; 1ms auf Bestätigung warten
- bsr Start1ms ;Timer starten
-
- IBODACLoop bsr TimerDoneQ ;Timer abgelaufen?
- bne IBOTimeOut ;Ja, dann Time out
- GET_DATA_CLOCK ;Auf Listener data accepted warten
- bcs IBODACLoop
-
- ; Alles OK
- moveq #ST_OK,d0
- bra IBODone
-
- ; Fehlerbehandlung
- IBODevNotPr LINE_RELEASE
- move.b #ST_NOTPRESENT,d0
- bra IBODone
-
- IBOTimeOut LINE_RELEASE
- move.b #ST_TIMEOUT,d0
-
- IBODone JSRLIB Enable
-
- movem.l (sp)+,a6/d2/d7
- rts
-
-
- *
- * Byte über IEC-Kabel empfangen
- * Rückgabe: d1.b: Empfangenes Byte
- *
-
- IECByteIn tst.b IECIsOpen
- bne 1$
- move.b #ST_NOTPRESENT,d0
- rts
-
- 1$ movem.l d2/d3/d7/a6,-(sp)
- moveq #ST_OK,d3 ;d3: Status
- move.l _SysBase,a6
- JSRLIB Disable
-
- CLOCK_HI
- WAIT_CLOCK_HI
-
- ; Auf Beginn der Übertragung warten
- bsr Start250us ;Timer starten
- DATA_HI ;Listener ready for data
-
- IBIWaitTalker bsr TimerDoneQ ;Timer abgelaufen?
- bne IBIEOI ;Ja, EOI empfangen
- GET_DATA_CLOCK ;Warten auf talker sending
- bmi IBIWaitTalker
- bra IBIReceive
-
- ; EOI empfangen, Handshake senden und erneut auf Beginn warten
- IBIEOI move.b #ST_EOF,d3
- DATA_LO ;EOI handshake
- CLOCK_HI
- bsr Wait60us ;EOI response hold time
-
- bsr Start250us ;Timer starten
- DATA_HI ;Listener ready for data
-
- IBIWaitTalker2 bsr TimerDoneQ ;Timer abgelaufen?
- bne IBITimeOut ;Ja, dann Time out
- GET_DATA_CLOCK ;Warten auf talker sending
- bmi IBIWaitTalker2
-
- ; 8 Bits empfangen
- IBIReceive moveq #7,d7 ;d7: Bitzähler
- moveq #0,d2 ;d2: Empfangenes Byte
-
- IBIBitLoop WAIT_CLOCK_HI ;Auf Data valid warten
- roxr.b #1,d2 ;Datenbit holen
- WAIT_CLOCK_LO
- dbra d7,IBIBitLoop
-
- ; Empfang bestätigen
- DATA_LO ;Listener data accepted
- btst #6,d3 ;EOI empfangen?
- beq IBIDone
- LINE_RELEASE ;Ja, Leitung freigeben
- bra IBIDone
-
- ; Fehlerbehandlung
- IBITimeOut or.b #ST_READ_TIMEOUT,d3
- LINE_RELEASE
-
- IBIDone move.b d3,d0 ;Status holen
- move.b d2,d1 ;Byte holen
- JSRLIB Enable
- movem.l (sp)+,d2/d3/d7/a6
- rts
-
-
- *
- * 20µs/40µs/60µs/1ms warten
- *
-
- ; Timer auf 20µs setzen
- Wait20us move.l CiaControlReg,a0
- and.b #$80,(a0)
- move.l CiaTimerReg,a0
- move.b #14,(a0)
- move.b #0,$100(a0)
- bra StartTimer
-
- ; Timer auf 40µs setzen
- Wait40us move.l CiaControlReg,a0
- and.b #$80,(a0)
- move.l CiaTimerReg,a0
- move.b #29,(a0)
- move.b #0,$100(a0)
- bra StartTimer
-
- ; Timer auf 60µs setzen
- Wait60us move.l CiaControlReg,a0
- and.b #$80,(a0)
- move.l CiaTimerReg,a0
- move.b #43,(a0)
- move.b #0,$100(a0)
- bra StartTimer
-
- ; Timer auf 1ms setzen
- Wait1ms move.l CiaControlReg,a0
- and.b #$80,(a0)
- move.l CiaTimerReg,a0
- move.b #$cc,(a0)
- move.b #2,$100(a0)
- move.l CiaControlReg,a0
-
- ; Timer anwerfen (One-Shot) und auf Ablauf warten
- StartTimer move.l a6,-(sp)
- move.l _CiaBase,a6
-
- move.b WhichTimerMask,d0
- JSRLIB SetICR
-
- move.l CiaControlReg,a0
- move.b #CIACRAF_LOAD|CIACRAF_RUNMODE|CIACRAF_START,(a0)
-
- 1$ moveq #0,d0
- JSRLIB SetICR
- and.b WhichTimerMask,d0
- beq 1$
-
- move.l (sp)+,a6
- rts
-
-
- *
- * Timer starten, 1ms/250µs
- *
-
- Start1ms move.l a6,-(sp)
- move.l _CiaBase,a6
- move.l CiaControlReg,a0
- and.b #$80,(a0)
-
- move.l CiaTimerReg,a0
- move.b #$cc,(a0)
- move.b #2,$100(a0)
-
- move.b WhichTimerMask,d0
- JSRLIB SetICR
-
- move.l CiaControlReg,a0
- or.b #CIACRAF_LOAD|CIACRAF_RUNMODE|CIACRAF_START,(a0)
- move.l (sp)+,a6
- rts
-
- Start250us move.l a6,-(sp)
- move.l _CiaBase,a6
- move.l CiaControlReg,a0
- and.b #$80,(a0)
-
- move.l CiaTimerReg,a0
- move.b #$b3,(a0)
- move.b #0,$100(a0)
-
- move.b WhichTimerMask,d0
- JSRLIB SetICR
-
- move.l CiaControlReg,a0
- or.b #CIACRAF_LOAD|CIACRAF_RUNMODE|CIACRAF_START,(a0)
- move.l (sp)+,a6
- rts
-
-
- *
- * Timer abgelaufen?
- * bne: Ja
- *
-
- TimerDoneQ move.l a6,-(sp)
- move.l _CiaBase,a6
- moveq #0,d0
- JSRLIB SetICR
- and.b WhichTimerMask,d0
- move.l (sp)+,a6
- tst.b d0
- rts
-
-
- *
- * Dummy-Timer-Interrupt-Routine
- *
-
- IntTimer moveq #0,d0
- rts
-
-
- *
- * SetError: 1541-Fehlermeldung bereitstellen
- *
- * a0.l: Zeiger auf DRVDATA
- * d0.l: Fehlercode
- *
-
- XDEF _SetError
- _SetError move.l 4(sp),a0
- move.l 8(sp),d0
- lea ErrorTab,a1
- move.l (a1,d0.l*4),a1
- move.l a1,drv_ErrorPtr(a0)
-
- move.l a2,-(sp)
- move.l a1,a2
- 1$ tst.b (a2)+
- bne 1$
- sub.l a1,a2
- move.l a2,d0
- subq.l #1,d0
- move.b d0,drv_ErrorLen(a0)
- move.l (sp)+,a2
- rts
-
-
- **
- ** Konstanten
- **
-
- ; Tabelle für Fehlermeldungen (Index: ErrorCode)
- CNOP 0,4
- ErrorTab dc.l OKText
- dc.l WriteErrText
- dc.l WriteProtText
- dc.l Syntax30Text
- dc.l Syntax33Text
- dc.l WrFileOpenText
- dc.l FileNotOpenText
- dc.l FileNotFText
- dc.l IllegalTSText
- dc.l NoChannelText
- dc.l StartupText
-
- ; Fehlertexte
- OKText dc.b "00, OK,00,00",13,0
- WriteErrText dc.b "25,WRITE ERROR,00,00",13,0
- WriteProtText dc.b "26,WRITE PROTECT ON,00,00",13,0
- Syntax30Text dc.b "30,SYNTAX ERROR,00,00",13,0
- Syntax33Text dc.b "33,SYNTAX ERROR,00,00",13,0
- WrFileOpenText dc.b "60,WRITE FILE OPEN,00,00",13,0
- FileNotOpenText dc.b "61,FILE NOT OPEN,00,00",13,0
- FileNotFText dc.b "62,FILE NOT FOUND,00,00",13,0
- IllegalTSText dc.b "67,ILLEGAL TRACK OR SECTOR,00,00",13,0
- NoChannelText dc.b "70,NO CHANNEL,00,00",13,0
- StartupText dc.b "73,CBM DOS V2.6 1541,00,00",13,0
- CNOP 0,4
-
- ; Tabelle mit Zeigern auf die Laufwerks-Datenstrukturen
- CNOP 0,4
- DrvTab dc.l Drv8Data
- dc.l Drv9Data
- dc.l Drv10Data
- dc.l Drv11Data
-
- ; Name der temporären Datei für das Directory
- TempFileName dc.b "T:Frodo$File",0
-
- ; Name für AllocMiscResource
- ParPortName dc.b "Frodo Parallel Port",0
-
- ; Name des Timer-Interrupts
- TimerIntName dc.b "Frodo Timer Int",0
- CNOP 0,4
-
-
- **
- ** Initialisierte Daten
- **
-
- SECTION "DATA",DATA
-
- TimerInterrupt dc.l 0,0
- dc.b NT_INTERRUPT,0
- dc.l TimerIntName
- dc.l 0
- dc.l IntTimer
-
-
- **
- ** Nicht initialisierte Daten
- **
-
- SECTION "BSS",BSS
-
- ; Global
- ListenerActive ds.b 1 ;Flag: Listener angewählt, ListenerData ist gültig
- ListenerIsIEC ds.b 1 ;Flag: Aktiver Listener hängt am IEC-Kabel (impliziert ListenerActive)
- TalkerActive ds.b 1 ;Flag: Talker angewählt, TalkerData ist gültig
- TalkerIsIEC ds.b 1 ;Flag: Aktiver Talker hängt am IEC-Kabel (impliziert TalkerActive)
-
- Listening ds.b 1 ;Flag: Letzter ATN-Befehl war Listen (für SecListen/SecTalk-Unterscheidung)
- SecAddr ds.b 1 ;Aktuelle Sekundäradresse ($0x)
- ReceivedCmd ds.b 1 ;Empfangener Befehlscode ($x0)
-
- IECIsOpen ds.b 1 ;Flag: Timer und Port belegt, IEC-Kabel kann benutzt werden
- IECInited ds.b 1 ;Flag: InitIEC wurde aufgerufen
-
- WhichTimer ds.b 1 ;Welcher Timer wurde belegt? (0: Timer A, 1: Timer B)
- WhichTimerMask ds.b 1 ;Dto. als Bit-Maske für ICR
-
- CNOP 0,4
- CiaTimerReg ds.l 1 ;Zeiger auf Cia-Timer-Register
- CiaControlReg ds.l 1
-
- ListenerData ds.l 1 ;Zeiger auf Struktur des aktiven Listeners
- TalkerData ds.l 1 ;Zeiger auf Struktur des aktiven Talkers
-
- DataInBuf ds.b 1 ;Puffer für DataIn
-
- ; Datenstruktur pro Laufwerk
- CNOP 0,4
- Drv8Data ds.b drv_SIZEOF
- Drv9Data ds.b drv_SIZEOF
- Drv10Data ds.b drv_SIZEOF
- Drv11Data ds.b drv_SIZEOF
-
- ; Puffer für Dateinamen/Befehlsstrings
- NameBuf ds.b NAMEBUF_LENGTH
-
- ; Puffer für die Verzeichnisse der 4 Laufwerke
- Dir8 ds.b 256
- Dir9 ds.b 256
- Dir10 ds.b 256
- Dir11 ds.b 256
-
- ; Einstellungen
- Drv8Type ds.w 1
- Drv9Type ds.w 1
- Drv10Type ds.w 1
- Drv11Type ds.w 1
- OtherIEC ds.w 1
- XDEF _MapSlash
- _MapSlash
- MapSlash ds.w 1
- END
-