Add new attachment

Only authorized users are allowed to upload new attachments.

This page (revision-8) was last changed on 27-Dec-2010 16:19 by Carsten Strotmann  

This page was created on 27-Dec-2010 15:50 by Carsten Strotmann

Only authorized users are allowed to rename pages.

Only authorized users are allowed to delete pages.

Difference between version and

At line 267 added 557 lines
!!Teil 4
von Reinhard Wilde
!DIE EINSPRUNGADRESSEN
Nachdem wir Ihnen im letzten Monat die Speicherbelegung der SPEEDY erklärt haben, erfahren Sie jetzt etwas über die Einsprungadressen. Wichtig ist dabei, eines zu wissen: Wir haben am Ende des ROM-Bereiches ab $FF00 eine Einsprungtabelle eingerichtet. Wenn Sie nun eine Funktion innerhalb der SPEEDY ausführen wollen, brauchen Sie nur eine oder mehrere Adressen dieser Sprungtabelle anzuspringen.
Welche Versionen es in Zukunft auch von der SPEEDY geben wird, diese Sprungtabelle wird immer an der gleichen Stelle und in der gleichen Reihenfolge erhalten bleiben. Somit ist gewährleistet, daß alle Programme, die jetzt für die SPEEDY geschrieben werden, auch auf den zukünftigen Versionen laufen, wenn die internen Routinen über diese Tabelle angesprungen werden.
Hier die Beschreibung der einzelnen Jump-Vektoren:
__RESET - $FF00 - DRIVE KALTSTART__
Port A und Port B (6532) werden initialisiert, der komplette RAM-Bereich gelöscht und der Disk-Controller getestet. Sollte ein Fehler beim Testen auftreten, erfolgt ein Sprung nach "SYSER0", wo zweimal "BELL" ausgegeben wird, anschließend folgt ein Sprung nach "RESET2".
__RESET2 - $FF03 - DRIVE WARMSTART__
Die System-Variablen werden neu gesetzt, das Laufwerk in den "SINGLE-DENSITY-MODUS" gebracht, der Schreib-/Lesekopf auf Track 0 justiert und jede Controller-Tätigkeit gestoppt. Zum Rücksetzen des Laufwerkes sollte diese Routine angesprungen werden, da bei "$FF00 - RESET" alle im RAM befindlichen Daten gelöscht werden.
__BEREIT - $FF06 - BEREITSCHAFTSROUTINE__
Zuerst wird der "SLOW"-Schalter abgefragt und das Laufwerk gegebenenfalls in den "SLOW"-Modus geschaltet. Sollten sich noch zu schreibende Sektoren im RAM befinden, wird direkt danach "TSTCO" verzweigt, damit der Motor nicht ausgeschaltet wird, falls die Laufwerksklappe geöffnet wurde. Wurde nicht verzweigt, wird die Laufwerksklappe mit der letzten Stellung verglichen. Sollte die Klappe geöffnet worden sein, werden der Antriebsmotor und der Steppermotor ausgeschaltet und der Controller-Status nach "CONST" kopiert. Ist die Klappe geschlossen worden, wird die DENSITY neu festgestellt, das Laufwerk entsprechend eingestellt und die Sektor-Folge neu eingelesen. In der "TESTCO"-Routine wird die "COMMAND"-Leitung vom Computer abgefragt. Sollte diese "gesetzt" werden, erfolgt ein Sprung nach "RDINF", wo das Kommando vom Computer eingelesen wird. Ist die "COMMAND"-Leitung nicht gesetzt, wird der Motor-Timer heraufgezählt. Sollte dieser den Wert $9800 (16 Bit) erreichen, wird "TSTWR" aufgerufen, um alle Sektoren zu schreiben, die sich noch im RAM befinden.
__MOTON - $FF09 - MOTOR ZWINGEND EINSCHALTEN__
Der Antriebsmotor wird ohne Rücksicht auf die Stellung der Laufwerksklappe eingeschaltet.
__TSTMON - $FF0C - MOTOR EINSCHALTEN, WENN DIE LAUFWERKSKLAPPE GESCHLOSSEN IST__
Erst wird die Laufwerksklappe abgefragt. Ist diese geschlossen, wird der Antriebsmotor eingeschaltet und eine Zeitverzögerung durchgeführt, um den Motor auf Touren kommen zu lassen.
__MOTOFF - $FF0F - MOTOR AUSSCHALTEN__
Der Antriebsmotor wird ausgeschaltet und das entsprechende Bit in "DRSTAT" gesetzt.
__SDELAY - $FF12 - MOTOR TIMER EINSTELLEN__
Diese Routine wird nach einer Kommandoausführung abgearbeitet. Es wird die Zeit vorgegeben, wie lange der Motor nach einer Kommandoausführung noch eingeschaltet bleiben soll.
__SDRDDP - $FF15 - DRIVE DENSITY EINSTELLEN UND ANZEIGEN__
Zuerst wird nach "DENDSP" gesprungen, um die aktuelle DENSITY auf dem Display anzuzeigen. Danach wird, je nach Wert in "FORKEN", der Drive-Status, die Anzahl der Sektoren pro Track und die Anzahl der Bytes pro Sektor gesetzt.
__XWAIT - $FF18 - WARTESCHLEIFE KURZ__
Der Wert im X-Register gibt die Anzahl der Schleifendurchläufe an. 1 Schleifendurchlauf entspricht ca. 100 Taktzyklen (0,1 msek/100 mikrosek).
__X2WAIT - $FF1B - WARTESCHLEIFE LANG__
Der Wert im X-Register gibt die Anzahl der Schleifendurchläufe an. 1 Schleifendurchlauf entspricht ca. 100.000 Taktzyklen (0,1 sek/100 msek).
__TRACK0 - $FF1E - TRACK 0 POSITIONIEREN__
Der Disk-Controller wird gestoppt und der Schreib-/Lesekopf so lange zurückgezogen, bis der Track-0-Sensor anspricht. Danach wird eine Verzögerung zum Ausschwingen der Kopfmechanik durchgeführt.
__TRADJA - $FF21 - TRACK # ANZEIGEN UND SCHREIB-/LESEKOPF POSITIONIEREN__
Zuerst wird die Tracknummer angezeigt und der Controller gestoppt. Ist die Klappe geschlossen, wird der Motor eingeschaltet und die Anzahl der Doppel-Steps errechnet, die durchgeführt werden müssen, um die gewünschte Kopfposition zu erreichen. Sollte der Trackwechsel über 40 Tracks gehen, wird zweimal "BELL" ausgegeben und der Kopf auf Track 0 positioniert.
Nach erfolgreicher Schreib-/Lesekopf-Positionierung wird die Tracknummer in das Track-Register des Controllers kopiert und der Schreib-/Lesekopf-Mechanik Zeit zum Ausschwingen gegeben.
__TRADJ - $FF24 - SCHREIB-/LESEKOPF POSITIONIEREN__
Entspricht der $FF21-Routine, mit dem Unterschied, daß die Tracknummer nur dann angezeigt wird, wenn ein Trackwechsel stattgefunden hat.
__TRVR - $FF27 - 1 STEP VORWÄRTS ODER RÜCKWÄRTS AUSFÜHREN__
Im Y-Register ist die Kennung für Step vorwärts oder rückwärts (plus oder minus). Die Bitposition des Steppermotors wird entsprechend herauf- oder herabgezählt und das neue Bitmuster in Port 5 des Portbausteins geschrieben.
Anmerkung: Für 1 Trackwechsel müssen immer 2 Steps erfolgen. Das heißt aber nicht, daß ohne Bedenken 80 Tracks geschrieben oder gelesen werden können. Die beiden Steps sind verschieden lang und instabil!
__CONRES - $FF2A - DISK CONTROLLER STOPPEN__
Dem Disk-Controller wird der Befehl gegeben, alle laufenden Aktionen zu stoppen. In "WREADY" wird gewartet, bis der Controller den Befehl als "ausgeführt" meldet.
__CONRE2 - $FF2D - CONRES WIRD ZWEIMAL AUSGEFÜHRT__
Beim Einsprung in diese Routine wird die Routine $FF2A - DISK CONTROLLER STOPPEN zweimal ausgeführt.
__WREADY - $FF30 - AUF CONTROLLER "IN USE-FLAG" = 0 WARTEN__
Bei dieser Routine wird darauf gewartet, bis der Controller meldet, daß der letzte Befehl abgeschlossen wurde.
__RD128 - $FF33 - 128 BYTES VOM COMPUTER NACH "EXBUF" HOLEN__
Der Buffer wird auf "EXBUF" (Extended Buffer) und die I/O-Länge auf 128 Bytes gesetzt.
__RD256 - $FF36 - 256 BYTES VOM COMPUTER NACH "EXBUF" HOLEN__
Wie bei der vorhergehenden Routine wird der Buffer auf "EXBUF", aber die I/O-Länge auf 256 Bytes gesetzt.
__RDBTS - $FF39 - ANZAHL DER BYTES IM ACCU IN DEN BUFFER HOLEN (X/Y-REGISTER)__
Im Accu steht die Anzahl der Bytes, im X- und Y-Register die Low- und High-Adresse des Buffers, in dem die Daten vom Computer abgelegt werden sollen. Der Timer wird gesetzt, um zu verhindern, daß der Prozessor hängen bleiben kann. Es wird jeweils ein Byte über einen indirekten Jump-Vektor vom Computer geholt (außer bei HIGH-SPEED) und in dem Buffer abgelegt. Anschließend wird die Checksumme heraufgezählt und geprüft, ob alle Bytes des Datenblocks geholt wurden. Die Checksumme wird verglichen und die I/O-Länge neu gesetzt.
__RDSFOL - $FF3C - NACH VERZÖGERUNG SEKTORFOLGE VOM AKTUELLEN TRACK LESEN__
Eine Verzögerungsschleife am Anfang der Routine verhindert, daß versucht wird, die HEADER schon zu lesen, wenn die Laufwerksklappe noch nicht vollständig geschlossen ist. Danach wird die Zeit gestellt, die der Controller zur Verfügung hat, um alle HEADER zu lesen. Ist ein HEADER eingelesen, wird die Track- und Sektor-Nummer auf Gültigkeit geprüft. Befindet sich die Sektornummer des gelesenen HEADERS bereits in der Sektorliste (doppelter Sektor), wird die Sektorfolge nicht mehr weiter gelesen und das Laufwerk in den Slow-Modus geschaltet. Stimmt die Anzahl der gelesenen Sektor-HEADER nicht mit der vorgegebenen (18 oder 26 Sektoren) überein, wird das Laufwerk ebenfalls in den Slow-Modus geschaltet.
__RDTRA - $FF42 - AKTUELLEN TRACK IN DAS RAM EINLESEN__
Die Track-Slow-Kennung wird gesetzt. Über RDHDSP wird der Kopf positioniert und der nächste HEADER eingelesen. Anschließend wird die Position der Sektor-Nummer des HEADERS in der Sektorliste gesucht. Ab der nächsten Position werden die Sektoren dann in der richtigen Reihenfolge eingelesen. Die Statuswerte der Sektoren werden in die Statusliste eingetragen. Alle Statuswerte außer $08 (CRC-ERROR) und $20 (AM-ERROR) unterbrechen dabei das Einlesen der Sektoren. Nur wenn alle Sektoren des Tracks gelesen wurden, wird die Kennung für Track-Slow zurückgesetzt.
__RDTRAV - $FF45 - WIE RDTRA, JEDOCH MIT VERIFY UND 1 RETRY__
Hier wird zuerst die Track- und Sektornummer errechnet und anschließend $FF42 (RDTRA) aufgerufen. Dann wird die Statusliste auf $08 (CRC-ERROR) und $20 (AM-ERROR) getestet. Ist einer der beiden Statuswerte eingetragen, wird der entsprechende Sektor nochmal gelesen.
Fortsetzung im CSM 5'89.
Da sich viele Beschreibungen auf Zero-Page Adressen beziehen, hier eine Übersicht über die vom SPEEDY-System belegten Adressen:
{{{
DLYT1 = $03 Timer LO für Motor-Timer Routine
DLYT2 = $04 Timer HI für Motor-Timer Routine
LDSW = $05 Letzte SLOW-Schalter Position
WRKEN = $06 Anzahl der zu schreibenden Sektoren im RAM
EXSECT = $07 Sektornummer der Daten im extended Buffer
DUMKEN = $08 SLOW-Status
FORKEN = $09 Aktuelle Density $00=DD, $41=MD, $82=SD
FORKEN2 = $0A Density für Format, wenn durch COM4F gesetzt
LWRTRA = $0B Tracknummer der zu schreibenden Daten im RAM
LTRACK = $0C Tracknummer des zuletzt gelesenen Sektors
TRACK = $0D Aktuelle Tracknummer
SECTOR = $0E Aktuelle Sektornummer
CONST = $0F Controller-Status
DRSTAT = $10 Drive-Status
COMST = $11 Command-Status
RETRY = $12 Anzahl der Retries für Read/Write, normal = 2
RWLEN = $13 I/O Länge
SECLEN = $14 Anzahl der Bytes pro Sektor
USKEN = $15 Kennung für Übertragungsgeschwindigkeit
DLYTIM = $16 Enthält die Zeit, wie lange der Motor nach einem Befehl noch läuft
STPTIM = $17 Verzögerung für Steppermotor
COMPOS = $18 Position des letzten Befehls in der Kommandotabelle
IND = $19 Indirekt-Vektor für Datenbuffer
CHKSUM = $1B Checksum für Datenübertragung
RDDATK = $1C Kennung, ob Daten vom Computer geholt werden müssen
KLAPPE = $1D Letzte Klappen Position
SECANZ1 = $1E Sektoranzahl pro Track, die vorhanden sind
SECANZ = $1F Sektoranzahl pro Track, die vorhanden sein sollen
SECLST = $20 Sektorenliste
STALST = $40 Sektoren-Status-Liste
STPPOS = $60 Bit-Position für Steppermotor
DSPCTR = $61 Display/Drive-Controlbyte
BLOCKS = $62 Anzahl der Datenblocks für Datenübertragung
COUNTL = $64 16-Bit Zähler für Datenübertragung (low-Byte)
COUNTH = $65 16-Bit Zähler für Datenübertragung (high-Byte)
RDIND = $68 Indirekter Vektor für 1 Byte vom Computer empfangen
SDIND = $6A Indirekter Vektor für 1 Byte zum Computer senden
}}}
Die Zeropageadressen $90 bis $CF sind unbenutzt und frei für eigene Programme.
!! Teil 5
von Reinhard Wilde
!Fortsetzung der Sprungtabelle aus der letzten Ausgabe.
__TSTWR - $FF48 - NOCH ZU SCHREIBENDE SEKTOREN AUS DEM RAM AUF DIE DISKETTE SCHREIBEN__
In "WRKEN" steht die Anzahl der zu schreibenden Sektoren. Ist der Wert gleich 0, wird die Routine sofort verlassen. Sonst wird der Motor eingeschaltet, die Tracknummer für die zu schreibenden Sektoren aus "LWRTRA" nach "TRACK" kopiert und der Schreib-/Lesekopf positioniert. Anschließend wird der nächste HEADER eingelesen und die Sektornummer in der Sektorliste gesucht. Ist der Sektor nicht eingetragen (zum Beispiel bei geschützten Disketten, die mit "FAST-WRITE" beschrieben wurden), wird 1 Bell ausgegeben. Ansonsten wird ab der gefundenen Sektorposition die Statusliste auf negative Werte (Kennung für zu schreibende Sektoren) überprüft. Wird ein solcher Wert gefunden, wird der entsprechende Sektor geschrieben und in der Statusliste als geschrieben ($40) eingetragen. "WRKEN" wird um 1 heruntergezählt und die Position in der Sektorliste heraufgezählt. Sollte beim Schreiben eines Sektors ein Fehler auftreten, indem der "WRITE-PROTECT-Schalter" umgeschaltet war oder die Laufwerksklappe geöffnet wurde, wird die Routine "WRERR" aufgerufen, in der dem Anwender auf optischem und akustischem Wege ca. 5 Sekunden Zeit gegeben wird, um die Laufwerksklappe wieder zu schließen. Alle "WRITE-PROTECTIERTEN" Sektoren werden in der Statusliste als geschrieben ($40) eingetragen.
__TSTDAT - $FF4B - TSTWR AUFRUFEN UND STATUSLISTE MIT $40 FÜLLEN__
Diese Routine muß abgearbeitet werden, wenn das Laufwerk in den "SLOW-MODE" geschaltet wurde, damit alle Sektoren geschrieben bzw. als nicht gelesen markiert werden.
__SD128B - $FF4E - 128 BYTES VOM EXBUF ZUM COMPUTER SENDEN__
Die Übertragungslänge wird auf 128 Bytes und der Buffer auf "EXBUF" gesetzt.
__SD256B - $FF51 - 256 BYTES VOM EXBUF ZUM COMPUTER SENDEN__
Die Übertragungslänge wird auf 256 Bytes und der Buffer auf "EXBUF" gesetzt.
__SDBTS - $FF54 - ANZAHL DER BYTES IM ACCU AUS BUFFER (X/Y-REGISTER) SENDEN__
Es wird jeweils 1 Byte aus dem Buffer geladen, die Checksumme heraufgezählt und über die Jump-Tabelle der Senderoutinen gesprungen, um das gelesene Byte zum Computer zu senden. Dieser Vorgang wird in einer Schleife solange wiederholt, bis der gesamte Buffer gesendet wurde. Anschließend wird die Checksumme gesendet.
__SEND41 - $FF57 - QUITTUNG $41 ZUM COMPUTER SENDEN__
Der Accu wird mit dem Wert $41 ("A") geladen, und nach einer Verzögerung (damit die Quittung an den Computer nicht zu schnell kommt) wird über die Jump-Tabelle der Senderoutinen gesprungen, um die Quittung in der richtigen Übertragungsgeschwindigkeit zu senden. (A=Acknowledge)
__SEND43 - $FF5A - QUITTUNG $43 ZUM COMPUTER SENDEN__
Dasselbe wie bei "SEND41"-$FF57, jedoch mit dem Quittungsbyte $43 (C=Complete).
__SEND45 - $FF5D - QUITTUNG $45 ZUM COMPUTER SENDEN__
Dasselbe wie bei "SEND41"-$FF57, jedoch mit dem Quittungsbyte $45 (E=Error).
__SEND4E - $FF60 - QUITTUNG $4E ZUM COMPUTER SENDEN__
Dasselbe wie bei "SEND41"-$FF57, jedoch mit dem Quittungsbyte $4E (N=Negative Acknowledge).
__RDSECT - $FF63 - AKTUELLEN SEKTOR VON DER DISKETTE IN DEN VORBEZEICHNETEN RAMBEREICH EINLESEN.__
Sektornummer in das Sektor-Register kopieren. "READ-SEKTOR"-Befehl an den Computer geben. "TIME-OUT"-Zeit setzen. Nun werden die Daten Byte für Byte vom Controller übernommen und in den bezeichneten Buffer (indirekt "IND") abgelegt. Sind alle Daten gelesen, wird auf den Controller gewartet, bis dieser seine Arbeit eingestellt hat, und der Status des gelesenen Sektors in das Status-Register des Controllers übergeben wurde. Sollte ein "TIME-OUT" aufgetreten sein, wird noch ein Leseversuch gestartet.
__RDSEC1 - $FF66 - BEZEICHNETEN SEKTOR IN BEZEICHNETES RAM EINLESEN__
Die gleiche Routine wie RDSECT-$FF63. Nur muß die Sektornummer bereits in das Sektor-Register des Controllers geschrieben sein.
__WRSECT - $FF69 - AKTUELLEN SEKTOR VON VORBEZEICHNETER RAMADRESSE AUF DIE DISKETTE SCHREIBEN__
Sektornummer in das Sektor-Register kopieren. "WRITE-SECTOR"-Befehl an den Controller geben. "TIME-OUT"-Zeit setzen. Nun werden die Daten Byte für Byte an den Controller übergeben.
Sind alle Daten übergeben, wird auf den Controller gewartet, bis dieser seine Arbeit eingestellt hat und der Write-Status vom Controller übernommen wird. Sollte ein "TIME-OUT" aufgetreten sein, wird überprüft, ob der Controller noch arbeitet. Wenn ja, wird noch ein Schreibversuch gestartet.
__TSTWRP - $FF6F - "WRITE-PROTECT" UND LAUFWERKSKLAPPE TESTEN__
Es wird "CONRES" aufgerufen, wo der Disk-Controller seine augenblickliche Arbeit unterbricht und der Controller-Status gelesen wird. Anschließend werden Bit 6 (WRITE-PROTECT) und Bit 7 (LAUFWERKS-KLAPPE) ausmaskiert. Ist eines der beiden Bits gesetzt, können keine Daten geschrieben werden!
__VERSEC - $FF72 - AKTUELLEN SEKTOR MIT ANGEGEBENEM RAM VERGLEICHEN__
Sektornummer in das Sektor-Register kopieren. "READ-SEKTOR"-Befehl an den Controller geben. "TIME-OUT"-Zeit setzen. Nun werden die Daten Byte für Byte vom Controller übernommen und mit der bezeichneten Adresse (indirekt "IND") verglichen. Ist ein Wert ungleich, wird das Lesen unterbrochen, der Controller gestoppt, die Kennung für "DATEN UNGLEICH" (ACCU<>0) gesetzt und CARRY für "KEIN LESEFEHLER AUFGETRETEN" gelöscht. Stimmen alle Daten mit dem angegebenen Buffer überein, wird die Kennung für "DATEN GLEICH" (ACCU=0) und "KEIN LESEFEHLER" (CARRY=0) gesetzt. Tritt während des Vergleichens ein "TIME-OUT" auf, wird geprüft, ob der Controller noch arbeitet. Wenn ja, wird der Vergleich der Daten fortgesetzt. Ansonsten wird "CARRY" gesetzt (KENNUNG FÜR LESEFEHLER).
__VERSE1 - $FF75 - BEZEICHNETEN SEKTOR MIT ANGEGEBENEN RAM VERGLEICHEN__
Die gleiche Routine wie VERSEC-$FF72. Nur muß die Sektornummer in das Sektor-Register des Controllers geschrieben sein.
__STELL - $FF78 - COM-STATUS AUF ERROR UND 2 RETRIES SETZEN__
"RETRY" wird auf 2 Versuche und "COMST" vorsorglich auf "COMMAND-ERROR" gesetzt.
__QUITT - $FF7B - QUITTUNG "C" ODER "E" ZUM COMPUTER SENDEN__
Den Controller-Status übernehmen. Wenn "CONST" auf "COMMAND-ERROR" steht, wird die Kennung für "FEHLER BEI LETZTER LAUFWERKS-OPERATION" in "DRSTAT" gesetzt. Wenn Bit 7 und Bit 0 in "DSPCTR" gesetzt sind, wird der Controller-Status auf dem Display angezeigt, 1 "BELL" ausgegeben und die Quittung $45 ("E") zum Computer gesendet. Ist "COMMAND-STATUS" o.k., wird die Kennung für "LAUFWERKS-OPERATION IN ORDNUNG" gesetzt und die Quittung $43 ("C") zum Computer gesendet.
__RDHEAD - $FF7E - DIE NÄCHSTEN HEADERDATEN EINLESEN__
"TIME-OUT"-Zeit setzen. "READ-HEADER"-Befehl an den Controller geben. Nun werden die 6 Bytes des nächsten auffindbaren HEADERS in einer Schleife eingelesen und ab der Adresse $7A abgelegt. In "WREADY" wird darauf gewartet, daß der Controller seine Arbeit einstellt. CARRY als Lesefehler-Flag wird zurückgesetzt.
__RDHD1 - $FF81 - WIE RDHEAD, ABER TIMER NICHT SETZEN__
Dasselbe wie $FF7E. Nur muß "TIME-OUT" bereits gesetzt sein.
__CALCTS - $FF87 - TRACK- UND SEKTORNUMMER ERRECHNEN__
Sektornummer LOW und HIGH werden zum "IND"-Pointer kopiert (für RAM/ROM-Adressen) und auf Nummer=0 oder Nummer>$7FFF geprüft. Ist das der Fall, wird in "DUMKEN" noch der SLOW-Status getestet. Andernfalls wird die Sektornummer in IND/IND+1 solange um die Anzahl der Sektoren pro Track herabgezählt, bis sie die Nummer 0 unterschreitet. Als Ergebnis hat man die gewünschte Track- und Sektornummer. Die Tracknummer wird noch mit dem Wert 40 verglichen (Tracknummer >39). Das CARRY-Flag wird durch den Vergleich entsprechend gesetzt. Nach der Rückkehr aus dieser Routine stehen die Prozessor-Status-Flags wie folgt:
{{{
C=1 SEKTORNUMMER UNZULÄSSIG
N=1 RAM/ROM-ADRESSE
Z=1 ZERO-PAGE-ADRESSE 0
}}}
Fortsetzung in der nächsten Ausgabe.
!!Teil 6
von Reinhard Wilde
!Die Einsprungadressen, Fortsetzung
__SETBUF - $FF8A - BUFFER NACH AKTUELLEM SEKTOR SETZEN__
Je nach Sektorlänge wird die Sektornummer durch 2 geteilt (oder nicht) und zur Anfangsadresse des Datenbuffers hinzu addiert. Die Bufferadresse befindet sich dann in IND/IND+1.
__SETBU2 - $FF8D - BUFFER NACH SEKTORNUMMER IM ACCU SETZEN__
Entspricht der Routine "SETBUF"-$FF8A, jedoch muß die Sektornummer (1..26) bereits im ACCU stehen.
__SEXBUF - $FF90 - ADRESSE DES EXTENDED BUFFERS SETZEN__
Die Adresse von "EXBUF" wird nach IND/IND+1 geladen.
__SETRWL - $FF93 - ANZAHL DER BYTES FÜR DEN ZU ÜBERTRAGENDEN DATENBLOCK SETZEN__
Bei Sektornummern von 1 bis 3 wird die Übertragungslänge auf 128 Bytes, ansonsten auf den Wert von "SECLEN" gesetzt. Die Anzahl der Datenblöcke wird auf 1 gesetzt.
__COPSLT - $FF96 - SEKTORLISTE FÜR AKTUELLE DENSITY IN ZEROPAGE KOPIEREN__
In "SDRDDP" werden die Werte für die aktuelle DENSITY richtig gesetzt und die DENSITY auf dem Display angezeigt. Anschließend wird, je nach Wert in "FORKEN" (DENSITY-Kennung), die entsprechende Sektorliste für SINGLE- oder DOUBLE-DENSITY nach "SECLST" ($20) kopiert.
__BELL1 - $FF99 - 1 MAL BELL ÜBER DEN SUMMER AUSGEBEN__
Der Summer wird mittels einer Verzögerungsschleife mit einer bestimmten Frequenz angesteuert.
__CLRDSP - $FF9C - DISPLAY ABSCHALTEN__
In die Display-Speicherstellen $4000, $4001 und $4002 werden Nullen geschrieben. Die Speicherstellen sollten nur im Schreibzugriff (z.B. STA $4000) angesprochen werden, da sonst auf dem Display unkontrollierte Zeichen erscheinen.
__TRAANZ - $FF9F - AKTUELLE TRACKNUMMER ANZEIGEN__
Der ACCU wird mit dem Wert von "TRACK" geladen, und es wird, je nach Wert in "DSPCTR" zur Dezimal- oder Hexadezimal-Ausgaberoutine gesprungen.
__DEZOUT - $FFA2 - WERT IM ACCU WIRD IN DEZIMALER FORM ANGEZEIGT__
Der Wert im ACCU wird in einer Schleife um 10 heruntergezählt, bis er den Wert 0 unterschreitet. Der Schleifenzähler entspricht dann dem Wert für das 10er-Stellen-Display und die Restsumme dem Wert für das 1er-Stellen-Display. Die Werte für die richtige Segmentsteuerung werden einer Konstantentabelle (SEGTBL) entnommen.
__HEXOUT - $FFA5 - WERT IM ACCU WIRD IN HEXADEZIMALER FORM ANGEZEIGT__
Zuerst werden die unteren 4 Bits des Wertes im ACCU ausmaskiert, die dem Wert für das rechte Display entsprechen, dann die oberen 4 Bits.
__DENDSP - $FFA8 - AKTUELLE DENSITY AUF DEM DISPLAY ANZEIGEN__
Je nach Wert in "FORKEN" (DENSITY-Kennung) werden die entsprechenden Segmente des Displays angesteuert.
__SETTIM - $FFAB - TIMER MIT DEM WERT IM ACCU SETZEN__
Timer-Interrupt-Flag wird gelöscht und der Timer mit dem Wert im ACCU gestartet.
__CRLTRA - $FFAE - EINEN TRACK REFORMATIEREN__
In "FSTART" wird das "WRITE-TRACK"-Kommando gestartet und der Timer gesetzt. Nun wird der Track mit dem Wert $00 beschrieben, bis der Timer abgelaufen ist. Es wird der Track "gelöscht", auf dem sich der Schreib-/Lesekopf befindet.
__CLRDSK - $FFB1 - GANZE DISKETTE REFORMATIEREN__
Hier werden alle Tracks nacheinander, beginnend bei Track 39 (39..0) gelöscht. Der Schreib-/Lesekopf wird jeweils positioniert und "CLRTRA" aufgerufen.
__RAMTST - $FFB4 - TEST DES LAUFWERKINTERNEN RAMS__
Im ersten Teil wird die Zero-Page getestet. Der Wert der Speicherstelle, die getestet wird, wird jeweils in EXBUF+1 zwischengespeichert. Zuerst wird die Zero-Page mit dem Wert $55 getestet, das heißt, der Wert $55 wird in jede Speicherstelle geschrieben und wieder gelesen.
Ist der Wert gleich geblieben, ist die Speicherstelle in Ordnung. Anschließend wird die Zero-Page noch einmal mit dem Wert $AA getestet. Ist während des Tests kein Fehler festgestellt worden, wird der Speicherbereich von $8000 bis RAMTOP ($A000) auf die gleiche Art getestet wie die Zero-Page. Tritt bei einer Speicherstelle ein Fehler auf, wird die Adresse jener Speicherstelle in $90/$91 abgelegt und der Test wird abgebrochen.
Ist kein RAM-Fehler festgestellt worden, steht in $90/$91 die höchste RAM-Adresse. Nach Abschluß der RAM-Testroutine wird die Adresse, die in $90/$91 steht, zum Computer gesendet.
__ROMTST - $FFB7 - ROM-TEST__
Vorsorglich wird Command-Status auf ERROR gesetzt. In IND/IND+1 wird die Adresse $E000 gesetzt. Anschließend wird für eine Page die Checksumme errechnet und mit den Originalwerten in einer Tabelle verglichen. Ist die Checksumme gleich, wird die High-ROM-Adresse in $91 um 1 heraufgezählt und die nächste ROM-Page getestet. Insgesamt werden 32 ROM-Pages ($E000 bis $FFFF) getestet. Stimmen alle Checksummen mit denen der "ROMCHK"-Tabelle überein, wird der Command-Status zurückgesetzt und die Quittung ("C") zum Computer gesendet. Ist ein Fehler gefunden worden, wird der Command-Status nicht zurückgesetzt und die Quittung ("E") zum Computer gesendet.
__SPEEDT - $FFBA - MOTOR-SPEED-TEST__
Vorsorglich Command-ERROR setzen und Schreib-/Lesekopf auf Track 0 positionieren. In "FDSEC1" wird Sektor 1 zweimal direkt hintereinander gelesen und die Zeit über Taktzyklen gemessen. Dann wird in einer Schleife die gemessene Zeit von der Konstanten $C0E1E4 solange abgezählt, bis der Wert 0 unterschritten wird. Die nachfolgende Nachkomma-Stellenrundung wird mit dem Rest der vorhergehenden Rechnung vorgenommen, indem die gemessene Zeit durch 2 geteilt und vom Rest der vorhergehenden Rechnung abgezogen wird. Ist das CARRY-Flag dann gesetzt, wird die Nachkommastelle um 1 erhöht. Der aus 2 Daten bestehende Speed-Wert wird zum Computer gesendet. Der hexadezimale Wert $2875 bedeutet dabei 287,5 UPM.
!Erweiterte JMP-Tabelle ab Speedy V1.4
__TSTDEN - $FFBD - FORMAT DER DISKETTE FESTSTELLEN__
Der Schreib-/Lesekopf wird auf Track 0 positioniert und das Laufwerk im MFM-Mode gesetzt. Anschließend wird mit "RDHEAD" getestet ob sich ein Header lesen läßt. Gelingt das, wird die Routine verlassen (N-Flag=0 für Test ok.). Ansonsten wird nochmal im FM-Mode (Single-Density) versucht ein Header zu lesen. Mißlingt auch dies, wird der gesamte Vorgang noch auf den Tracks 1 bis 3 durchgeführt. Sollten auch danach noch keine Header gefunden worden sein, steht das Laufwerk in Single-Density und die Routine wird mit gesetztem N-Flag (Fehler-Flag) verlassen. Falls vorhanden, wird der Summer kurz mit einem Ton angesteuert und auf dem Display erscheint "nF" für nicht formatiert.
__FSTART - $FFC0 - "WRITE-TRACK" KOMMANDO STARTEN__
Der Schreib-/Lesekopf wird auf dem Track positioniert, der in "TRACK" festgelegt ist. Danach wird der "WRITE-TRACK"-Befehl gestartet und der Time-Out für eine Diskettenumdrehung festgelegt. Ein gesetztes Carry-Flag nach Abarbeitung dieser Routine bedeutet, daß ein Fehler aufgetreten ist.
__FORMTR - $FFC3 - AKTUELLEN TRACK FORMATIEREN__
"FSTART" wird aufgerufen und anschließend der aktuelle Track in dem Format formatiert, das in "FORKEN" festgelegt ist. ACHTUNG: der Schreib-/Lesekopf muß bereits auf dem Track positioniert sein, der formatiert werden soll. Fehlerflag ist das gesetzte Carry-Flag.
__FORDSK - $FFC6 - DISKETTE FORMATIEREN__
Die Diskette wird in dem Format formatiert, das in "FORKEN2" festgelegt ist. Die Tracks werden beginnend mit Track 39 bis herunter auf Track 0 formatiert. Fehlerflag ist das gesetzte Bit 6 in COMST (Speicherstelle $11).
__WRBOOT - $FFC9 - BOOTSEKTOREN UND VTOC-SEKTOR(EN) SCHREIBEN__
Es werden zunächst die Sektoren 1 bis 3 mit einem Bootprogramm beschrieben, in dem gemeldet wird, daß die Diskette mit der Speedy formatiert wurde. Je nach Format der Diskette wird der/die VTOC-Sektor(en) $168 ($400) beschrieben.
__DISPL - $FFCC - WERT IN X/Y-REGISTER AUF DEM DISPLAY ZEIGEN__
Die Werte, die sich bei Aufruf dieser Routine in den Registern X und Y befinden, werden auf dem Display (falls vorhanden) angezeigt.
__SENDEN - $FFCF - DATEN ZUM COMPUTER SENDEN__
Parameterübergabe: Länge des zu übertragenden Datenblocks in den Registern X und Y. In den Speicherstellen IND/IND+1 ($19/$1A) muß die Bufferadresse stehen. Die Checksumme des Datenblocks wird nicht gesendet. Dies hat den Zweck, das mehrere Datenblöcke direkt nacheinander ohne Unterbrechung gesendet werden können. Die Checksumme muß man extra senden lassen. Das Checksummenbyte steht in der Speicherstelle CHKSUM ($1B).
__INSTALL - $FFD2 - INSTALLIEREN EINES NEUEN KOMMANDOS__
Hiermit wird man in Zukunft neue Befehle in der Kommandotabelle installieren oder bereits existierende Kommandos wieder löschen können. Diese Routine entspricht der, die aufgerufen wird, wenn vom Computer der Befehl $41 gegeben wird. Nur können dann die Kommandos auch von Programmen innerhalb der Speedy ein- und ausgetragen werden.
Das war nun die vollständige Beschreibung aller Einsprungadressen. Einige Erklärungen beziehen sich auf Zeropage-Adressen, deren Bedeutung bereits in Teil 4 beschrieben wurde.
Damit wäre die Serie über das SPEEDY-System zunächst einmal abgeschlossen. Programmierbeispiele werden in einer der nächsten Ausgaben folgen.
Als Programmierhilfe ist die BIBO-Assembler Tooldisk 2 zu empfehlen. Auf dieser zweiseitigen Disk finden Sie das komplette dokumentierte Listing eines Sektorkopierers und eines Backup-Programmes für geschützte Software.
!!Teil 7
aus dem SPEEDY-Anwender-Handbuch Version 1.0 vom 17.10.1986 (c) 1986 Compy-Shop
!DIE BEFEHLE DER SPEEDY 1050
So, nachdem Sie nun mehr über die Einsprungadressen wissen, und bevor wird zum ROM-Listing kommen, hier nun nochmal alle Befehle der SPEEDY 1050 und ihre Anwendung.
KOMMANDO ist der Wert, der sich vor Aufruf der SIO - Routine ($E459) in der Speicherstelle $0302 befindet.
AUX1 und AUX2 entsprechen den Werten, die sich in den Speicherstellen $030A und $030B befinden. Bei einigen Befehlen werden AUX1 und AUX2 nicht benutzt und dürfen beliebige Werte annehmen.
Die Befehle sind im übrigen nicht nach den Hexadezimalnummern geordnet, sondern nach ihrer Funktion:
{{{
KOMMANDO: $52
FUNKTION: Sektoren lesen
AUX1: Sektornummer oder ROM-Adresse LOW BYTE
AUX2: Sektornummer oder ROM-Adresse HIGH BYTE
BESCHREIBUNG: Es werden je nach DENSITY 128 oder 256 Bytes gesendet. Sektoren 1-3 sind immer 128 Bytes lang.
KOMMANDO: $50
FUNKTION: Sektoren schreiben ohne Verify
AUX1: Sektornummer oder ROM-Adresse LOW BYTE
AUX2: Sektornummer oder ROM-Adresse HIGH BYTE
BESCHREIBUNG: Das Laufwerk erwartet je nach DENSITY 128 oder 256 Bytes. Sektoren 1-3 sind immer 128 Bytes lang.
KOMMANDO: $57
FUNKTION: Sektoren schreiben mit Verify
AUX1: Sektornummer oder ROM-Adresse LOW BYTE
AUX2: Sektornummer oder ROM-Adresse HIGH BYTE
BESCHREIBUNG: Das Laufwerk erwartet je nach DENSITY 128 oder 256 Bytes. Sektoren 1-3 sind immer 128 Bytes lang.
KOMMANDO: $53
FUNKTION: Laufwerkstatus
AUX1: nicht benutzt
AUX2: nicht benutzt
BESCHREIBUNG: Das Laufwerk sendet 4 Bytes (zur Adresse $02EA-$02ED), die den Status der letzten Diskettenoperation beinhalten.
Byte 1: Drive Status
Bit 0 - COMMAND FRAME ERROR
Bit 1 - CHECKSUM ERROR
Bit 2 - OPERATION ERROR
Bit 3 - WRITE PROTECT
Bit 4 - MOTOR ON
Bit 5 - DOUBLE DENSITY
Bit 6 - unbenutzt
Bit 7 - DUAL DENSITY
Byte 2: Controller Status
Bit 0 - BUSY
Bit 1 - DRQ
Bit 2 - LOST DATA
Bit 3 - CRC ERROR
Bit 4 - RECORD NOT FOUND
Bit 5 - RECORD TYPE
Bit 6 - WRITE PROTECT
Bit 7 - NOT READY
Byte 3: Time-Out Wert für Format Disk ($E0)
Byte 4: unbenutzt (immer 0)
KOMMANDO: $21
FUNKTION: Formatiere Diskette (SINGLE/DOUBLE DENSITY)
AUX1: nicht benutzt
AUX2: nicht benutzt
BESCHREIBUNG: Dieses Kommando wird benutzt um Disketten in SINGLE- oder DOUBLE-DENSITY (720 Sektoren) zu formatieren. Das DENSITY-Format wird durch einen vorherigen $4F-Befehl (Laufwerkskonfiguration) eingestellt. Wird das Laufwerk nach dem Einschalten nicht konfiguriert, wird automatisch in SINGLE-DENSITY formatiert. Das Laufwerk sendet nach dem Formatieren je nach DENSITY 128 oder 256 Bytes an den Computer. Die ersten zwei Bytes müssen immer $FF sein.
KOMMANDO: $22
FUNKTION: Formatiere Diskette (MEDIUM DENSITY)
AUX1: nicht benutzt
AUX2: nicht benutzt
BESCHREIBUNG: Dieses Kommando wird benutzt um Disketten in DUAL-DENSITY (MEDIUM = 1040 Sektoren) zu formatieren. Es werden immer 128 Bytes zum Computer gesendet. Die ersten beiden Bytes müssen immer $FF sein.
KOMMANDO: $20
FUNKTION: Automatisches Formatieren
AUX1: Konfigurationsbyte
AUX2: nicht benutzt
BESCHREIBUNG: Dem Laufwerk wird nur der Befehl zum Formatieren gegeben. Es wird sofort ein 'Complete' zurückgesendet. Mit diesem Befehl können alle drei Formate, abhängig vom Konfigurationsbyte ($00=SINGLE, $20=DOUBLE, $80=MEDIUM) generiert werden. Ein Write-Protect wird sofort zurückgemeldet.
Fehler beim Formatieren können dem Computer nicht gemeldet werden, da keine Daten nach Befehlsausführung zurückgesendet werden. Der Formatierungsvorgang und eventuelle Formatierungsfehler können auf dem Display verfolgt werden. Abhängig vom Drive/Display-Status Befehl wird nach dem Formatieren automatisch die VTOC (DOS 2.5 kompatibel) und 3 Bootsektoren geschrieben.
KOMMANDO: $3F
FUNKTION: SIO-Geschwindigkeitsbyte ermitteln
AUX1: nicht benutzt
AUX2: nicht benutzt
BESCHREIBUNG: Es wird ein Byte zum Computer gesendet, das die HIGH SPEED Übertragungsgeschwindigkeit beinhaltet. Dieses Byte wird für die HIGH SPEED SIO-Routine benötigt und beträgt bei der SPEEDY 1050 normalerweise $09.
KOMMANDO: $4E
FUNKTION: Laufwerkskonfiguration auslesen
AUX1: nicht benutzt
AUX2: nicht benutzt
BESCHREIBUNG: Es werden 12 Bytes der Konfigurationstabelle zum Computer gesendet. Die Bedeutung der einzelnen Bytes sind:
Byte 1 - Anzahl der Tracks (immer 40)
Byte 2 - Step Rate (immer 1)
Byte 3 - Sektoren pro Track HIGH (immer 0)
Byte 4 - Sektoren pro Track LOW (18 oder 26)
Byte 5 - Anzahl der Köpfe (immer 0)
Byte 6 - Aufzeichnungsformat (0=FM/4=MFM)
Byte 7 - Bytes pro Sektor HIGH (1=256/0=128)
Byte 8 - Bytes pro Sektor LOW (0=256/128=128)
Byte 9 - Laufwerk aktiv (immer 255)
Byte 10 - unbenutzt (immer 0)
Byte 11 - unbenutzt (immer 0)
Byte 12 - unbenutzt (immer 0)
KOMMANDO: $4F
FUNKTION: Laufwerk konfigurieren
AUX1: nicht benutzt
AUX2: nicht benutzt
BESCHREIBUNG: Dieser Befehl wird benutzt um das Laufwerk für den nächsten Formatierungsbefehl einzustellen. Das Laufwerk erwartet 12 Bytes, die genau der Reihenfolge der vorherigen Bytes ($4E) entsprechen müssen.
KOMMANDO: $51
FUNKTION: Schreibvorgang beenden
AUX1: nicht benutzt
AUX2: nicht benutzt
BESCHREIBUNG: Nach jedem Schreibbefehl wartet das Laufwerk ca. 2 Sekunden bis die Daten aus dem Trackbuffer auf die Diskette geschrieben werden. Dieses wird durch den Befehl $51 beschleunigt. Alle Daten im Trackbuffer werden unverzüglich auf die Diskette geschrieben und abhängig vom Drive/Display Befehl ($44) wird der Motor nach erfolgtem Schreibvorgang sofort gestoppt.
KOMMANDO: $44
FUNKTION: Drive/Display Einstellung
AUX1: Konfigurationsbyte
AUX2: nicht benutzt
BESCHREIBUNG: Der Wert in AUX1 setzt das Drive/Display Byte im Laufwerk. Dieses Byte kann über keinen Befehl direkt ausgelesen werden, so daß immer alle Bits richtig gesetzt werden müssen.
Die einzelnen Bits beinhalten die folgenden Funktionen:
Bit 0 - BELL bei ERROR zulassen
Bit 1 - unbenutzt
Bit 2 - unbenutzt
Bit 3 - bei Kommando $51 Motor nicht ausschalten
Bit 4 - bei Kommando $20 VTOC+Boot Sektoren nicht schreiben
Bit 5 - Formatieren ohne Verify
Bit 6 - Trackanzeige in Hexadezimal
Bit 7 - ERROR-Anzeige zulassen
KOMMANDO: $4B
FUNKTION: Slow/Fast Konfiguration
AUX1: Konfigurationsbyte
AUX2: nicht benutzt
BESCHREIBUNG: Mit dem Wert in AUX1 wird das Drive-Slow-Status Byte des Laufwerkes beeinflußt. Dieses Byte kann über keinen Befehl direkt ausgelesen werden, so daß alle Bits richtig gesetzt werden müssen.
Die einzelnen Bits haben folgenden Funktionen:
Bit 0 - Read Sektor slow
Bit 1 - Write Sektor slow
Bit 2 - Kommando $57 Verify ausschalten
Bit 3 - Laufwerk vollständig im 'Slow-Mode'
Bit 4 - unbenutzt
Bit 5 - unbenutzt
Bit 6 - 1 Track slow (nach Trackwechsel 0)
Bit 7 - 1 Diskette slow (nach Diskettenwechsel 0)
KOMMANDO: $4C
FUNKTION: Direkter Sprungbefehl ohne Rückmeldung
AUX1: Sprungadresse LOW BYTE
AUX2: Sprungadresse HIGH BYTE
BESCHREIBUNG: Der Prozessor im Laufwerk wird durch diesen Befehl veranlaßt, direkt zur Speicherstelle zu springen, die sich in AUX1 und AUX2 befindet. Das Laufwerk gibt keine Rückmeldung an den Computer zurück, so daß eine Rückmeldung von dem Programm aus gegeben werden muß, zu dem der Prozessor gesprungen ist.
KOMMANDO: $4D
FUNKTION: Direkter Sprungbefehl mit Rückmeldung
AUX1: Sprungadresse LOW BYTE
AUX2: Sprungadresse HIGH BYTE
BESCHREIBUNG: Dieser Befehl gleicht dem Vorhergehenden bis auf den kleinen Unterschied, daß das Laufwerk vor ausführen des Programms eine Rückmeldung an den Computer gibt.
KOMMANDO: $41
FUNKTION: Kommandotabelle verlängern oder verkürzen
AUX1: nicht benutzt
AUX2: nicht benutzt
BESCHREIBUNG: Das Laufwerk erwartet 3 Bytes vom Computer. Das 1. Byte ist das Kommando. Das 2. und 3. Byte ist die Sprungadresse des über das neue Kommando erreichten Programmes in LOW/HIGH-Byte Format. Falls sich der neue Befehl schon in der Kommandotabelle befindet, wird dieser mit der neuen Startadresse versehen. Ist die Startadresse $0000 wird der Befehl aus der Kommandotabelle gelöscht.
KOMMANDO: $68
FUNKTION: Länge der SIO-Routine ermitteln
AUX1: nicht benutzt
AUX2: nicht benutzt
BESCHREIBUNG: Mit diesem Befehl wird die Länge der SIO-Routine ermittelt, die mit dem Befehl $69 aus dem Laufwerk in den Computer geladen wird. Das Laufwerk sendet 2 Bytes, die die Länge (LOW/HIGH) beinhalten.
KOMMANDO: $69
FUNKTION: SIO-Routine zum Computer senden
AUX1: Relokator-Adresse LOW BYTE
AUX2: Relokator-Adresse HIGH BYTE
BESCHREIBUNG: Dieser Befehl sendet die HIGH SPEED SIO-Routine zum Computer. Diese Routine wird bereits im Laufwerk zur Startadresse hin relokiert, die sich in AUX1 und AUX2 befindet.
KOMMANDO: $60
FUNKTION: Track schreiben
AUX1: Track Anfangssektor oder Anfangsadresse LOW BYTE
AUX2: Track Anfangssektor oder Anfangsadresse HIGH BYTE
BESCHREIBUNG: Die kompletten Daten für einen Track werden mit diesem Befehl auf die Diskette oder in den Trackbuffer geschrieben. Die Anzahl der zu übertragenden Bytes errechnet sich aus der Anzahl der Sektoren mal der Bytes pro Sektor. Wegen des sehr schwierigen Timings funktioniert dieser Befehl nur in normaler Übertragungsgeschwindigkeit.
KOMMANDO: $62
FUNKTION: Track lesen
AUX1: Track Anfangssektor LOW BYTE
AUX2: Track Anfangssektor HIGH BYTE
BESCHREIBUNG: Lesen eines kompletten Tracks mit einem Befehl von der Diskette oder aus dem Trackbuffer. Die Anzahl der zu erwartenden Bytes errechnet sich aus der Anzahl der Sektoren mal der Bytes pro Sektor.
}}}
Version Date Modified Size Author Changes ... Change note
8 27-Dec-2010 16:19 68.731 kB Carsten Strotmann to previous
7 27-Dec-2010 16:18 59.163 kB Carsten Strotmann to previous | to last
6 27-Dec-2010 16:08 49.899 kB Carsten Strotmann to previous | to last
5 27-Dec-2010 16:06 49.898 kB Carsten Strotmann to previous | to last
4 27-Dec-2010 16:04 41.963 kB Carsten Strotmann to previous | to last
3 27-Dec-2010 15:59 31.017 kB Carsten Strotmann to previous | to last
2 27-Dec-2010 15:54 20.882 kB Carsten Strotmann to previous | to last
1 27-Dec-2010 15:50 12.223 kB Carsten Strotmann to last
« This page (revision-8) was last changed on 27-Dec-2010 16:19 by Carsten Strotmann