Highspeed mit Pokey-Divisor 0

1, 2

Highspeed mit Pokey-Divisor 0

von Dietrich » Sa 24. Jul 2010, 22:46
Hi,

ich bastele gerade an meiner Highspeed-Routine herum (für ein QMEG-OS 4.1) und überlege, ob es sich lohnt, Übertragungen von mehr als 256 Byte auf einmal zu unterstützen und/oder Pokey-Divisor 0 zu unterstützen.

1) Gibt es eigentlich Geräte, die mehr als 256 Byte mit einem einzigen SIO-Komando übertragen? Bisher kenne ich nur das Laden der Highspeed-Routine von der Speedy, die etwas mehr als 500 Byte auf einmal überträgt.

2) Bei Pokey-Divisor 0 (mit AspeQt) funktioniert meine Highspeed-Routine mit "kurzem" VBI mit einem ATARI, aber mit einem anderen stottert es öfters, obwohl es theoretisch gehen müsste. Mein VBI dauert max. 74 Takte, hinzu kommen 7 Takte für den NMI und 31 Takte für den System-NMI-Handler, macht zusammen 112 Takte. Nach meiner Rechnung sollte es aber sogar mit 148 Takten noch einwandfrei funktionieren. Zwar kann ich die VBI-Routine problemlos um 16 Takte kürzen (xitvbv nicht benutzen, Timerlogik umstellen), womit es dann auch läuft - ich würde aber schon gerne wissen, warum 112 Takte für den VBI bei Pokey-Divisor 0 zu viel sind.

Zur Berechnung: Wenn das letzte Byte vor dem VBI ankommt, befindet sich die Leseschleife beim Pollen (9 Takte). Insgesamt ist meine Leseschleife 67 Takte lang. Für das nächste Byte nach dem VBI kommen wieder 9 Takte pollen sowie 16 Takte für das Abholen und SERIN-IRQ rücksetzen. Dann noch 4 Takte bis der ATARI wieder auf den SERIN-IRQ reagieren kann. Macht zusammen 105 Takte + VBI. 2 Bytes bei Pokey Divisor 0 zu empfangen dauert 280 Takte, also weniger als 3 leere Scanlines und damit max. 27 Takte Refresh. Also bleiben für den VBI max. 280-105-27 = 148 Takte übrig.

@hwdoc: Danke für den Hinweis und das Entfernen der Kondensatoren. Da hätte ich wohl länger gesucht, warum es nur bisher nur bis Pokey-Divisor 3 ging ...

Re: Highspeed mit Pokey-Divisor 0

von Mathy » Sa 24. Jul 2010, 23:55
Hallo Stefan

Wenn ich mich nicht irre, unterstützt die letzte Version von SpartaDOS X (und deswegen wohl auch RealDOS) 512 Byte Sektoren. Ob das nur für parallelen Datentransport oder auch für seriellen Datentransport gibt, kann ich dir leider nicht sagen. Und leider auch nicht, ob es SIO-Geräte gibt, die so was im Moment unterstützen. Ich kann mir aber vorstellen, dass man für SIO2... Geräte die Firmware ändert, damit das möglich wird. Und Erhard wollte ja auch an der Firmware des HDI arbeiten. :-)

Tschüß

Mathy

Re: Highspeed mit Pokey-Divisor 0

von HiassofT » So 25. Jul 2010, 18:19
Hallo Stefan!

Dietrich hat geschrieben:ich bastele gerade an meiner Highspeed-Routine herum (für ein QMEG-OS 4.1) und überlege, ob es sich lohnt, Übertragungen von mehr als 256 Byte auf einmal zu unterstützen und/oder Pokey-Divisor 0 zu unterstützen.

Support für mehr als 256 Bytes würde ich auf jeden Fall mit einbauen, Pokey Divisor 0 eher nicht. Bei meinem hisio patch musste ich den NMI Handler für den Divisor 0 stark kürzen, das macht aber leider Probleme mit einigen Spielen (zB Last Starfighter).

1) Gibt es eigentlich Geräte, die mehr als 256 Byte mit einem einzigen SIO-Komando übertragen? Bisher kenne ich nur das Laden der Highspeed-Routine von der Speedy, die etwas mehr als 500 Byte auf einmal überträgt.

Hat nicht das 850er Interface ein ähnliches Kommando zum Laden des R: Handlers?

2) Bei Pokey-Divisor 0 (mit AspeQt) funktioniert meine Highspeed-Routine mit "kurzem" VBI mit einem ATARI, aber mit einem anderen stottert es öfters, obwohl es theoretisch gehen müsste. Mein VBI dauert max. 74 Takte, hinzu kommen 7 Takte für den NMI und 31 Takte für den System-NMI-Handler, macht zusammen 112 Takte.

7+31 Takte für den System-NMI-Handler kommen mir etwas wenig vor, beim original XL OS sind es 61 (bzw. 64 wenn man XITVBV verwendet). Kommt aber natürlich drauf an, welche Code-Teile Du zum NMI und welche zum VBI gezählt hast. Hier der Code vom XL-OS, inkl. Zyklen:
Code: Alles auswählen
System NMI handler
... NMI overhead             ; 7
C018  2C 0F D4  BIT $D40F    ; 4
C01B  10 03     BPL $C020    ; 3
C01D  6C 00 02  JMP ($0200)  ; 0
C020  D8        CLD          ; 2
C021  48        PHA          ; 3
C022  8A        TXA          ; 2
C023  48        PHA          ; 3
C024  98        TYA          ; 2
C025  48        PHA          ; 3
C026  8D 0F D4  STA $D40F    ; 4
C029  6C 22 02  JMP ($0222)  ; 6
                             ; sum = 39

end of NMI (VBLKD):
C28A  68        PLA          ; 4
C28B  A8        TAY          ; 2
C28C  68        PLA          ; 4
C28D  AA        TAX          ; 2
C28E  68        PLA          ; 4
C28F  40        RTI          ; 6
                             ; sum = 22


Nach meiner Rechnung sollte es aber sogar mit 148 Takten noch einwandfrei funktionieren. Zwar kann ich die VBI-Routine problemlos um 16 Takte kürzen (xitvbv nicht benutzen, Timerlogik umstellen), womit es dann auch läuft - ich würde aber schon gerne wissen, warum 112 Takte für den VBI bei Pokey-Divisor 0 zu viel sind.

Zur Berechnung: Wenn das letzte Byte vor dem VBI ankommt, befindet sich die Leseschleife beim Pollen (9 Takte). Insgesamt ist meine Leseschleife 67 Takte lang. Für das nächste Byte nach dem VBI kommen wieder 9 Takte pollen sowie 16 Takte für das Abholen und SERIN-IRQ rücksetzen. Dann noch 4 Takte bis der ATARI wieder auf den SERIN-IRQ reagieren kann. Macht zusammen 105 Takte + VBI. 2 Bytes bei Pokey Divisor 0 zu empfangen dauert 280 Takte, also weniger als 3 leere Scanlines und damit max. 27 Takte Refresh. Also bleiben für den VBI max. 280-105-27 = 148 Takte übrig.

Ich kenne Deinen Code nicht, aber evtl. hast Du die kritischen Pfade noch nicht richtig identifiziert. Hier mal ein Beispiel an einem älteren Code von mir, der Probleme machte:

Code: Alles auswählen
?GETBYTE LDA #IMRECV
?GETBY1 BIT IRQST
        BPL ?ERRBRK     ; break key pressed?
        BNE ?GETBY1

        LDA #RMRECV     ; reset data-receive IRQ bit
        STA IRQEN
        LDA #MSKRECV    ; enable data-receive IRQ
        STA IRQEN
        LDA SKSTAT
        STA SKREST
        BPL ?ERRFRM     ; framing error
        AND #$20
        BEQ ?ERROVR     ; data input overrun
        LDA SERIN

Im Worst Case trifft das Byte direkt nach dem "BIT IRQST" ein und die Schleife muss ein zweites Mal durchlaufen werden. Macht also 13 Zyklen bevor der eigentliche Code loslegen kann.

Der folgende Code bis zum Lesen des Bytes (LDA SERIN) braucht insgesamt 30 Zyklen. Das sind in Summe also 43 Zyklen. Gibt's in diesen 43 Zyklen einen VBI, so würden zB 112+43=155 Zyklen vom IRQ bis zum LDA SERIN vergehen (inkl. Refresh dann 164 Zyklen), ein Byte dauert 141 Zyklen, also liefert das "LDA SERIN" das nächste Byte, es kommt zu einem Checksum Error.

Lösung: Ich habe das "LDA SERIN" ganz an den Beginn verschoben (direkt nach den IRQST Checks), ein LDX SERIN draus gemacht und am Ende ein TXA. Braucht zwar 2 Takte mehr, funktioniert dafür aber :-)

Ich habe für meinen Code mal versucht diverse Worst-Case Szenarien durchzugehen, inkl. exakter Analyse der Zyklen, wann wo ein Refresh oder ANTIC-DMA Auftritt etc., mit dem Ergebnis, daß der Code garnicht funktionieren kann :-) Da dürfte ich wohl irgendeinen Fehler gemacht haben, hab' die Analysen dann nicht mehr wiederholt, das Zyklen-Zählen hat durchaus Kopfschmerzen bereitet.

so long,

Hias

Re: Highspeed mit Pokey-Divisor 0

von Dietrich » Mo 26. Jul 2010, 01:02
Hias hat geschrieben:... das macht aber leider Probleme mit einigen Spielen (zB Last Starfighter).

Was gibt es denn da für Probleme mit Last Starfighter? Wenn man den VBI nach jedem I/O-Zugriff wieder zurücksetzt, sollte es doch gehen? Oder installiert das Spiel beim Laden einen eigenen VBI, und ist beleidigt, wenn der nicht zum Zuge kommt?

Wenn es tatsächlich so ist, baue ich Pokey Divisor 0 wohl besser nicht ein - zumal das auch noch 100 Bytes wegen der zusätzlichen VBI-Routine kostet. Ohne Extra-VBI geht es ja immerhin bis Pokey Divisor 1 :-)

Hias hat geschrieben:Hat nicht das 850er Interface ein ähnliches Kommando zum Laden des R: Handlers?

Ja richtig, aber dafür "lohnt" sich die Unterstützung nicht, weil es nur einmal beim Booten passiert - das kann man dann ja auch automatisch in Normalspeed ausführen lassen (if length>$100 then normal_sio).

Hmm, da kommt mir eine Idee: Ich könnte das Normal-SIO einfach aus dem QMEG-OS rauswerfen, wenn ich mehr als 256 Byte in Highspeed unterstütze, das gäbe jede Menge Platz ...

Hias hat geschrieben:7+31 Takte für den System-NMI-Handler kommen mir etwas wenig vor, beim original XL OS sind es 61 (bzw. 64 wenn man XITVBV verwendet).

Ich zähle dazu nur den unvermeidbaren Teil: den NMI=7 Takte, und den Handler im OS bis JMP ($222). Hat ein indirekter JMP tatsächlich 6 Takte? Meine Doku sagt 5 Takte.

Mein VBI-Code sah bisher so aus:
Code: Alles auswählen
5 ?hivbi1  inc 20            ; interne Uhr hochzählen
2          bne ?i1       
5          inc 19
2          bne ?i1
5          inc 18
4 ?i1      lda cdtmv1
2          bne ?i2
4          lda cdtmv1+1
2          beq ?iexit        ; Timer1 ist 0, also bereits abgelaufen
6          dec cdtmv1+1
6 ?i2      dec cdtmv1        ; Timer1 runterzählen
3          bne ?iexit
           lda cdtmv1+1
           bne ?iexit        ; noch nicht null
           jmp (cdtma1)      ; von 1 auf 0 gewechselt -> cdtma1 aufrufen
                             ; kein RTS, da Sprung aus ?timout nach sioret
3 ?iexit   jmp xitvbv

xitvbv macht noch einen weiteren JMP (3) und dann kommt das PLA-Geraffel (22 Takte). Insgesamt macht das max. 74 Takte. Das kann ich um 16 Takte kürzen, indem ich die Timerlogik radikal vereinfache (dec cdtmv1: bne ?1 dec cdtmv1+1: bne ?1: jmp (cdtma1)) und jmp xitvbv direkt durch das PLA-Zeugs ersetze.

Hias hat geschrieben:Der folgende Code bis zum Lesen des Bytes (LDA SERIN) braucht insgesamt 30 Zyklen. Das sind in Summe also 43 Zyklen. Gibt's in diesen 43 Zyklen einen VBI, so würden zB 112+43=155 Zyklen vom IRQ bis zum LDA SERIN vergehen (inkl. Refresh dann 164 Zyklen), ein Byte dauert 141 Zyklen, also liefert das "LDA SERIN" das nächste Byte, es kommt zu einem Checksum Error.

Danke für den Hinweis. Ich glaube, ich habe meinen Denkfehler gefunden. Hier die ausführliche Erklärung anhand eines Zeitdiagramm (jedes Zeichen sind 5 Takte):
Code: Alles auswählen
|---------------------------|---------------------------|
|P-|---------VBI-------|-G|IR|

Oben bedeuten die |, dass der Pokey ein Byte anliefert (alle 140 Takte). Unten steht das Zeitverhalten der Leseschleife: Wenn der Pokey das letzte Byte vor dem VBI anliefert, befindet sich die Leseschleife sicher in der Pollschleife bit irqst: bpl : bne loop (denn die letzten Scanlines waren alles Leerzeilen, wo die CPU genug Zeit hatte, Rückstände aufzuholen). Als erstes kommen u.U. fast zwei Runden in der Pollschleife bit irqst: bpl break: bne loop (P, 13 Takte). Dann haut der VBI mit normalerweise max. 101 Takten dazwischen (ich gehe davon aus, dass inc 19/18 nicht durchlaufen wird, wenn cdtmv1=0 ist). Nun muss aber noch das Byte abgeholt und der IRQ zurückgesetzt werden (G, 16 Takte): ldx serin: lda #:sta irqen: lda #: sta irqen. Nun vergehen noch 4 Takte bis der IRQ tatsächlich wieder scharf ist (I, siehe Altirra HW manual, S.49) und der Pokey das nächste Byte anliefern darf.

Macht zusammen für die CPU 13+101+16+4 = 134 Takte. Wegen des Refresh (R) stehen der CPU aber nur 140*0.92=129 Takte zur Verfügung, bis der Pokey das nächste Byte liefert, das sind 5 Takte zuviel. Wenn ich das jmp xitvbv durch das PLA-Zeugs ersetze, sind es 6 Takte weniger, was gerade so eben reicht. Anders ausgedrückt: Das Maximum für den VBI sind 96 Takte, mehr führt zum Overrun.

Mein Denkfehler war, dass ich nur den Fall betrachtet habe, wenn der VBI nach Abholen des letzten Bytes vor dem VBI kommt. Dann sieht das Timing-Diagramm nämlich so aus:
Code: Alles auswählen
|---------------------------|---------------------------|
|P|-----Rloop---|---------VBI---------|P|-G|I|

Wie man sieht, genug Zeit für die CPU, das nächste Byte abzuholen.

Gruß Dietrich (der keine ungeklärten Sachen mag)

Re: Highspeed mit Pokey-Divisor 0

von HiassofT » Mo 26. Jul 2010, 02:10
Dietrich hat geschrieben:
Hias hat geschrieben:... das macht aber leider Probleme mit einigen Spielen (zB Last Starfighter).

Was gibt es denn da für Probleme mit Last Starfighter? Wenn man den VBI nach jedem I/O-Zugriff wieder zurücksetzt, sollte es doch gehen? Oder installiert das Spiel beim Laden einen eigenen VBI, und ist beleidigt, wenn der nicht zum Zuge kommt?

Ich habe da den NMI Handler ziemlich böse gepatcht, wenn CRITIC gesetzt ist wird ein verkürzter NMI Code durchlaufen. Das macht dann die Probleme. In der "FastVBI" Version gibt's keine Probleme, da wird der Immediate VBI ja nur während der I/O gesetzt. Hier der FastNMI Code:

Code: Alles auswählen
FASTNMI BIT $D40F
        BPL ?NODLI

        JMP ($200)

?NODLI  STA $D40F

        PHA
        LDA CRITIC
        BEQ ?NOCRIT

        INC 20
        BNE ?NOC1
        INC 19
        BNE ?NOC1
        INC 18

?NOC1   LDA CDTMV1      ; check lo byte. if its != 0 timer is running and it must be decremented.
        BNE ?TIDEC      ; go decrement, hi byte unchanged because lo != 0
        LDA CDTMV1+1    ; this branch: lo = 0
        BEQ ?TIEXIT     ; timer is zero (disabled, expired), exit from here
        DEC CDTMV1+1
?TIDEC  DEC CDTMV1
        BEQ ?TICHK      ; lo reached 0, check if we hi also reached 0
?TIEXIT PLA             ; timer still running or expired
        RTI
?TICHK  LDA CDTMV1+1
        BEQ ?RUNT1      ; hi is also 0, execute timer vector
        PLA             ; timer still running
        RTI

?RUNT1  CLD
        TXA
        PHA
        TYA
        PHA
        JSR ?RUNT11
        PLA
        TAY
        PLA
        TAX
?IGNDLI PLA
        RTI

?NOCRIT CLD
        TXA
        PHA
        TYA
        PHA
        JMP ($222)

?RUNT11 JMP (CDTMA1)

Wenn ich nur den Immediate VBI ($222) umlenke gibt es bei Divisor 0 sporadische Fehler (beim Überlauf von 20/19). Meistens klappt es (die Variante nehme ich zB bei meiner Entwicklerversion vom MyPicoDos), aber für den produktiv-Betrieb ist das nix.

Wenn es tatsächlich so ist, baue ich Pokey Divisor 0 wohl besser nicht ein - zumal das auch noch 100 Bytes wegen der zusätzlichen VBI-Routine kostet. Ohne Extra-VBI geht es ja immerhin bis Pokey Divisor 1 :-)

Hmmm. Interessant. Ohne VBI hatte ich glaube ich auch bei Divisor 1 sporadische Fehler. Muss ich bei Gelegenheit nochmal testen.

Hmm, da kommt mir eine Idee: Ich könnte das Normal-SIO einfach aus dem QMEG-OS rauswerfen, wenn ich mehr als 256 Byte in Highspeed unterstütze, das gäbe jede Menge Platz ...

Ich hatte eigentlich angenommen, daß das Dein Plan war :-)

Andererseits: ich fürchte, das könnte Probleme mit Software geben, die sich in die VSER* Vektoren einklinkt. IIRC macht der 850er R: Handler sowas (hab' selber keine 850er, aber vor einiger Zeit mal die Firmware und den Treiber disassembliert).

Hat ein indirekter JMP tatsächlich 6 Takte? Meine Doku sagt 5 Takte.

Danke für den Hinweis, Du hast recht. Da war in der schönen Tabelle im WDC 65c02 Datenblatt tatsächlich ein Fehler. Die andere Tabelle hat 5 drin, ebenso das Rockwell Datenblatt.

Mein VBI-Code sah bisher so aus:

OK, der ist ziemlich ähnlich wie mein fast-nmi Code.

Das kann ich um 16 Takte kürzen, indem ich die Timerlogik radikal vereinfache (dec cdtmv1: bne ?1 dec cdtmv1+1: bne ?1: jmp (cdtma1)) und jmp xitvbv direkt durch das PLA-Zeugs ersetze.

Wie soll der Code dann genau aussehen? Ich hab' da auch mal versucht was zu optimieren und bin kräftig auf die Nase gefallen. Die ganzen blöden Checks sind notwendig, weil der Timer ja nicht laufen soll wenn er 0 ist, und nur wenn er von 1 auf 0 wechselt soll der cdtma1 Code ausgeführt werden.

Wenn Du da eine bessere Lösung hast, wäre ich sehr daran interessiert!

Wenn ich das jmp xitvbv durch das PLA-Zeugs ersetze, sind es 6 Takte weniger, was gerade so eben reicht. Anders ausgedrückt: Das Maximum für den VBI sind 96 Takte, mehr führt zum Overrun.

Das ist eine gute Idee. In meinem Code wollte ich das nicht machen, weil er ja mit verschiedenen OSsen funktionieren soll.

Ich könnte natürlich beim Highspeed SIO Patch einen eigenen VBI-Handler nehmen, der direkt auf's OS zugeschnitten ist, und beim separaten Highspeed Code (zB MyPicoDos oder $68/$69 Kommandos bei AtariSIO) den bisherigen Code. Werd' mal ein wenig überlegen und testen.

so long,

Hias

Re: Highspeed mit Pokey-Divisor 0

von Dietrich » Mo 26. Jul 2010, 23:40
Hi,

Hias hat geschrieben:Ich habe da den NMI Handler ziemlich böse gepatcht, wenn CRITIC gesetzt ist wird ein verkürzter NMI Code durchlaufen.

Aha, sowas würde ich natürlich nie machen. Die System-Interrupt-Routinen sind heilig. ;-)

Hias hat geschrieben:Andererseits: ich fürchte, das könnte Probleme mit Software geben, die sich in die VSER* Vektoren einklinkt. IIRC macht der 850er R: Handler sowas (hab' selber keine 850er, aber vor einiger Zeit mal die Firmware und den Treiber disassembliert).

Ja, deshalb habe ich bisher das Original-SIO immer mit im QMEG-OS gelassen. Aber es ist schon blöd, den Platz könnte ich echt gut brauchen. Mein neuer Highspeed-Code ist wegen der Optimierungen deutlich länger als der alte, ich bin nun bei etwa 750 Byte (inkl. kurzem VBI).
Wozu macht denn der R-Handler das? (Im alten 400/800-OS war ein Bug im VERSIN-IRQ, der dazu führte, dass das das SIO bei einer Bufferendadresse von $XX00 endlos loopt. Deswegen hatte DOS 2.0 einen eigenen VSERIN-IRQ-Handler, vielleicht trifft das auch auf die 850 zu? Dann wäre das egal.)
Eigentlich ist es nur sinnvoll, eigene VSER-Routinen zu haben, wenn das SIO dabei gar nicht aufgerufen wird, weil die VSER-Routinen des SIO sehr eng miteinander und dem SIO verknüpft sind (vgl. die vielen Flags) und das SIO ohnehin nix anderes macht, als auf das Ende der Interrupts zu warten. (Das ist schon ein Widerspruch: Das SIO baut eine komplizierte raffinierte interruptgetriebene Übertragung auf und loopt dann einfach nur herum.) Bei völliger Loslösung vom SIO wäre es möglich, einen echten interruptgetriebenen I/O zu machen, während im Hauptprogramm andere Sachen gemacht werden, z.B. könnt man tippen oder Sound abspielen, ersters könnte ich mir bei der 850 gut vorstellen. Wahrscheinlich machen die Lucasfilm-Spiele auch sowas. Das wäre dann kein Problem für ein QMEG-OS ohne Original-SIO, da ich den System-IRQ-Handler natürlich unverändert belasse.

Hias hat geschrieben:Wie soll der Code dann genau aussehen? Ich hab' da auch mal versucht was zu optimieren und bin kräftig auf die Nase gefallen. Die ganzen blöden Checks sind notwendig, weil der Timer ja nicht laufen soll wenn er 0 ist, und nur wenn er von 1 auf 0 wechselt soll der cdtma1 Code ausgeführt werden.

Der Check, ob der Timer schon auf 0 steht, ist gar nicht erfoderlich. Wenn ich nicht will, dass der Timer ablaufen kann, schreibe ich einfach z.B. $FF in cdtmv1+1. Das mache ich vor Aktivieren des kurzen VBI, vor dem Senden und nach einem Fehler. Bis der Timer dann auf 0 läuft, braucht er über 1000 Sekunden. Bis dahin ist die SIO-Routine längst durch (oder loopt in der Leseschleife, aber da ist der Timer ohnehin richtig gesetzt). Und am Ende der SIO-Routine setze ich nach dem Deaktivieren des kurzen VBI cdtmv1 wieder zurück auf 0 und alles ist gut.

Und wer sagt, dass der Timer brav einen 16Bit-Integerwert herunterzählen muss, etwa $0102, $0101, $0100, $00FF, $00FE, $00FD, ..., $0001, $0000? Hauptsache, ?timout wird zur richtigen Zeit angesprungen. Ich erhöhe also die Werte beider Timer-Bytes um 1. Dann kann ich die einfach mit 2x DEC+BNE runterzählen, das sieht dann so aus: $0203, $0202, $0201, $0100, $01FF, $01FE, ..., $0102, $0101, $0000. Es wird zwar 1 VBI mehr ausgeführt, bis es zum Timeout kommt, aber bei den riesigen Timeouts von über 7 Sekunden spielt das keine Rolle. (Letztendlich erhöhe ich deswegen auch nicht das Low-Byte um 1.) Eine Alternative ist, den Timer einfach hoch- statt runterzuzählen, dann muss man das Komplement in cdtmv1 schreiben. Da das aber mehr Platz kostet, habe ich das nicht gemacht. So sieht mein kurzer VBI-Code jetzt aus:
Code: Alles auswählen
; Kurze VBI-Routine mit Uhr- und Timer1-Behandlung
; dauert nur 39-58 Takte + 7 für NMI + 31 für NMI-Handler = max. 96 Takte
?hivbi1  inc 20            ; interne Uhr hochzählen
         bne ?i1
         inc 19
         bne ?i1
         inc 18
?i1      dec cdtmv1        ; um Takte einzusparen, benutzen wir einfach 2*dec
         bne ?iexit        ; dazu sind die Bytes cdtmv1, cdtmv1+1 um 1 erhöht
         dec cdtmv1+1      ; Außerdem wird auf die Null-Abfrage verzichtet
         bne ?iexit
         jmp (cdtma1)      ; von 1 auf 0 gewechselt -> cdtma1 aufrufen
                           ; kein RTS, da Sprung aus ?timout nach sioret
?iexit   pla
         tay               ; jmp xitvbv kostet 6 Takte mehr
         pla
         tax
         pla
         rti

Macht max. 96 Takte, das ist exakt die rechnerische Grenze, bei der Pokey Divisor 0 noch einwandfrei funktioniert :-) Und die Wahrscheinlichkeit, dass der VBI tatsächlich 96 Takte braucht, ist sehr sehr gering, nämlich 1/256/256/256=0,000006%, also alle 100 Stunden 1mal. Du kannst ja mal meine neue Software testen, die ich Dir geschickt habe. Da ist dieser Code schon drin.

Hias hat geschrieben:Danke für den Hinweis, Du hast recht. Da war in der schönen Tabelle im WDC 65c02 Datenblatt tatsächlich ein Fehler. Die andere Tabelle hat 5 drin, ebenso das Rockwell Datenblatt.

Ups, habe gerade eine Info gefunden, dass der 65C02 6 Takte beim JMP () verbrät - und der 6502 5 Takte - und zwar wegen eines Bugs im JMP ()-Befehl des 6502 (!!!): Wenn die indirekte Adresse auf $FF endet ($xxFF), greift der 6502 gewaltig daneben: das Lowbyte holt er aus $xxFF und das Highbyte aus $xx00 (!!!). Ich programmiere schon über 25 Jahre 6502, aber das wusste ich noch nicht. Unglaublich!

Dietrich hat geschrieben:Wenn ich das jmp xitvbv durch das PLA-Zeugs ersetze, ...

Hias hat geschrieben:Das ist eine gute Idee. In meinem Code wollte ich das nicht machen, weil er ja mit verschiedenen OSsen funktionieren soll.

Was für Probleme kann es denn geben? Alle OSse, die ich kenne, springen bei jmp xitvbv zu einer Routine, die stets PLA, TAY, PLA, TAX, PLA, RTI macht. Wäre aus Kompatibilitätsgründen zum Original-OS auch gar nicht anders möglich.

Hias hat geschrieben:Hmmm. Interessant. Ohne VBI hatte ich glaube ich auch bei Divisor 1 sporadische Fehler. Muss ich bei Gelegenheit nochmal testen.

Nunja, ich habe meine Leseschleife auch auf 62 Takte herunteroptimiert (ohne Unterstützung von mehr als 256 Byte, mit sind es 67 Takte). Außerdem setze ich CRITIC, dann ist nämlich der System-VBI 10 Takte kürzer - vgl. das OS-Listing :-)

Gruß Dietrich (der das alles sehr interessant findet)

Re: Highspeed mit Pokey-Divisor 0

von HiassofT » So 15. Aug 2010, 01:54
Hallo Stefan!

Nach einer etwas längeren Pause geht's nun weiter :-)

Dietrich hat geschrieben:Wozu macht denn der R-Handler das? (Im alten 400/800-OS war ein Bug im VERSIN-IRQ, der dazu führte, dass das das SIO bei einer Bufferendadresse von $XX00 endlos loopt. Deswegen hatte DOS 2.0 einen eigenen VSERIN-IRQ-Handler, vielleicht trifft das auch auf die 850 zu? Dann wäre das egal.)
Eigentlich ist es nur sinnvoll, eigene VSER-Routinen zu haben, wenn das SIO dabei gar nicht aufgerufen wird

Ich bin mir da nicht 100% sicher, aber es kann durchaus sein, daß der 850er R: Handler wirklich nur einen eigenen VERSIN Handler installiert (und nicht auf den OS VSERIN Code angewiesen ist).

Der Check, ob der Timer schon auf 0 steht, ist gar nicht erfoderlich. Wenn ich nicht will, dass der Timer ablaufen kann, schreibe ich einfach z.B. $FF in cdtmv1+1. Das mache ich vor Aktivieren des kurzen VBI, vor dem Senden und nach einem Fehler. Bis der Timer dann auf 0 läuft, braucht er über 1000 Sekunden. Bis dahin ist die SIO-Routine längst durch (oder loopt in der Leseschleife, aber da ist der Timer ohnehin richtig gesetzt). Und am Ende der SIO-Routine setze ich nach dem Deaktivieren des kurzen VBI cdtmv1 wieder zurück auf 0 und alles ist gut.

Ah, jetzt versteh' ich Dich, für den eigenen Code muss man ja nicht den OS-Code nachbauen sondern einfach nur irgendeinen Timer implementieren. Gute Idee, hab' ich gleich in meinen Code übernommen :-)

Macht max. 96 Takte, das ist exakt die rechnerische Grenze, bei der Pokey Divisor 0 noch einwandfrei funktioniert :-) Und die Wahrscheinlichkeit, dass der VBI tatsächlich 96 Takte braucht, ist sehr sehr gering, nämlich 1/256/256/256=0,000006%, also alle 100 Stunden 1mal. Du kannst ja mal meine neue Software testen, die ich Dir geschickt habe. Da ist dieser Code schon drin.

BTW: Danke, Deine Software gefällt mir sehr gut (nicht nur der SIO Code da drin :-)

Ich habe heute meinen Code umgebaut und mal einiges getestet (unsere beiden Codes sind nun fast gleich, ich verwende aber statt CDTMV 2 Zero-Page Adressen die ich freigeschaufelt habe). Das interessante dabei ist, daß ich ab einer NMI Länge von 95 Takten Fehler bekomme. Mit Takten 94 funktioniert alles einwandfrei. Zuerst mal mein VBI Code:
Code: Alles auswählen
Fast VBI handler (worst case):

CF68  E6 14     INC $14      ; 5
CF6A  D0 06     BNE $CF72    ; 2
CF6C  E6 13     INC $13      ; 5
CF6E  D0 02     BNE $CF72    ; 2
CF70  E6 12     INC $12      ; 5
CF72  C6 3B     DEC $3B      ; 5
CF74  D0 06     BNE $CF7C    ; 2
CF76  C6 3C     DEC $3C      ; 5
CF78  D0 02     BNE $CF7D    ; 3
CF7D  68        PLA          ; 4
CF7E  A8        TAY          ; 2
CF7F  68        PLA          ; 4
CF80  AA        TAX          ; 2
CF81  68        PLA          ; 4
CF82  40        RTI          ; 6
                             ; sum = 56

BTW: einen Zyklus kann man leicht einsparen indem man das letzte BNE durch ein BEQ ersetzt.

Hier nun der Read-Code:
Code: Alles auswählen
worst case read timing
CEA3  18        CLC          ; 2
CEA4  A9 20     LDA #$20     ; 2
CEA6  2C 0E D2  BIT $D20E    ; 4
                             ; sum = 8
-> irq occurs here
CEA9  10 DC     BPL $CE87    ; 2
CEAB  D0 F9     BNE $CEA6    ; 3
CEA6  2C 0E D2  BIT $D20E    ; 4
CEA9  10 DC     BPL $CE87    ; 2
CEAB  D0 F9     BNE $CEA6    ; 2
CEAD  AE 0D D2  LDX $D20D    ; 4
CEB0  A9 DF     LDA #$DF     ; 2
CEB2  8D 0E D2  STA $D20E    ; 4
CEB5  A9 A0     LDA #$A0     ; 2
CEB7  8D 0E D2  STA $D20E    ; 4
                             ; sum = 29

CEBA  A9 20     LDA #$20     ; 2
CEBC  2C 0F D2  BIT $D20F    ; 4
CEBF  10 B0     BPL $CE71    ; 2
CEC1  F0 B1     BEQ $CE74    ; 2
CEC3  8A        TXA          ; 2
CEC4  B0 25     BCS $CEEB    ; 2
CEC6  91 32     STA ($32),Y  ; 6
CEC8  18        CLC          ; 2
CEC9  65 31     ADC $31      ; 3
CECB  69 00     ADC #$00     ; 2
CECD  85 31     STA $31      ; 3
CECF  C8        INY          ; 2
CED0  D0 04     BNE $CED6    ; 3
CED6  C4 34     CPY $34      ; 3
CED8  D0 C9     BNE $CEA3    ; 3
                             ; sum = 41

Kritisch ist nicht nur der VBI sondern auch der Code bis zum zweiten "STA IRQEN" ($D20E). Wenn ich dazwischen ein NOP einfüge (+2 Zyklen) oder auch nur das "LDA #$A0" durch "LDA ZP-Adresse" ersetze (+1) gibt's im Worst Case Fehler (Timeout). Danach machen ein (oder auch ein paar mehrere) NOPs nichts aus.

Rein von den Zyklen her kann ich mir das nicht erklären, da müsste eigentlich noch etwas Luft sein. Das Problem dürfte evtl. beim Pokey liegen, möglicherweise muss IRQEN eine gewisse Zeit vor dem Ende des empfangenen Bytes gesetzt sein. Ich schliess' da beim Pokey schon garnichts mehr aus :-)

BTW: Ich habe meinen Test-Code so ausgelegt, daß immer der Worst Case (Timer auf $FFFFFF und Timeout-Zähler auf $0201 initialisiert) vor jedem SIO-Aufruf gesetzt wird.
Dietrich hat geschrieben:Wenn ich das jmp xitvbv durch das PLA-Zeugs ersetze, ...

Hias hat geschrieben:Das ist eine gute Idee. In meinem Code wollte ich das nicht machen, weil er ja mit verschiedenen OSsen funktionieren soll.

Was für Probleme kann es denn geben? Alle OSse, die ich kenne, springen bei jmp xitvbv zu einer Routine, die stets PLA, TAY, PLA, TAX, PLA, RTI macht. Wäre aus Kompatibilitätsgründen zum Original-OS auch gar nicht anders möglich.

Ich war mir da nicht so 100% sicher und hätte eigentlich gerne XITVBV verwendet. Das geht sich aber von der Zeit doch nicht aus, also mach' ich jetzt auch PLA...RTI (der gepatchte NMI Handler ist mittlerweile komplett rausgeflogen). Letzte Woche hatte ich mit einem kleinen Programm alle OSse die ich auf der Platte hatte gecheckt, XITVBV ist tatsächlich bei allen gleich.

Nunja, ich habe meine Leseschleife auch auf 62 Takte herunteroptimiert (ohne Unterstützung von mehr als 256 Byte, mit sind es 67 Takte). Außerdem setze ich CRITIC, dann ist nämlich der System-VBI 10 Takte kürzer - vgl. das OS-Listing :-)

CRITIC sollte da keinen Unterschied machen, den OS VBI Code wo das abgefragt wird überspringen wir ja :-)

so long,

Hias

Re: Highspeed mit Pokey-Divisor 0

von HiassofT » Mo 16. Aug 2010, 02:07
So, nochmal ein Update:

Habe heute einiges getestet und habe festgestellt, daß der NMI maximal 93 Zyklen dauern darf. Bei 94 Zyklen gibt's Fehler. Eine 100% Erklärung was da genau abläuft habe ich noch nicht, aber immerhin ein paar Hinweise.

Der kritische Zeitpunkt am Code ist das "STA IRQEN", das den SERIN IRQ wieder einschaltet. Laut Altirra Hardware Reference Manual muss das 4 Zyklen vor Eintreten des Ereignisses erfolgen, sonst geht's schief. Bleiben also 141-4 = 137 Zyklen Zeit.

Nun zum kritischen Pfad:

In Zyklus 7 der Scanline in der der VBI auftritt wird der "BIT IRQST" Befehl ausgeführt (also IRQST von der CPU gelesen). Zu diesem Zeitpunkt sei noch kein IRQ da. In Zyklus 8 passiert nun folgendes:

- Der Pokey beendet den Empfang, das IRQST Bit wird auf 0 gesetzt
- ANTIC startet den VBI und zieht NMI auf low
- Da gerade kein Befehl abgearbeitet wird beginnt die CPU sofort mit dem NMI

Nun läuft für 93 Zyklen der NMI ab, dazu kommen 9 Refresh-Zyklen. Macht insgesamt 102 Zyklen.

Der SIO Code läuft nun ab Zyklus 110 der Scanline weiter:
Code: Alles auswählen
CEC0  10 DC     BPL $CE9E    ; 2
CEC2  D0 F9     BNE $CEBD    ; 3
CEBD  2C 0E D2  BIT $D20E    ; 4
CEC0  10 DC     BPL $CE9E    ; 2
CEC2  D0 F9     BNE $CEBD    ; 2
CEC4  AE 0D D2  LDX $D20D    ; 4
CEC7  A9 DF     LDA #$DF     ; 2
CEC9  8D 0E D2  STA $D20E    ; 4
CECC  A9 A0     LDA #$A0     ; 2 
CECE  8D 0E D2  STA $D20E    ; 4
                             ; sum = 29

Bis zum Ausführen des "STA $D20E" vergehen 28 Zyklen, in Summe ist das also 110+28=138. Das "STA $D20E" geschieht also in Zyklus 24 der nächsten Scanline.

Braucht der NMI Code 94 Zyklen passiert folgendes: das "STA $D20E" würde im Zyklus 25 der nächsten Scanline landen, dieser Zyklus ist aber für den ANTIC Refresh bestimmt, also wird der Befehl erst bei Zyklus 26 ausgeführt. Insgesamt braucht der Code also 2 (statt 1) Zyklus länger.

Soweit ist alles noch recht klar. Die Frage ist aber nun, wieso es mit 131 Zyklen klappt, nicht aber mit 133 - eigentlich sollte ja bis 137 Zeit sein.

Hier beschreibt ijor, daß der Pokey 4.8uS (also ca. 8.5 Zyklen) nachdem er das Stop-Bit übernommen hat den IRQ Pin auf low zieht. Im Altirra Manual steht weiters, daß mindestens 3 Zyklen vom Signalisieren des Ereignisses in IRQST vergehen bevor die CPU mit der IRQ Abarbeitung beginnt (Gründe, wieso das so ist werden aber nicht genannt - in der Pokeydoc wurde diskutiert daß IRQST und IRQ zur selben Zeit schalten sollten).

Möglicherweise ist das nun eine blöde Milchmädchenrechnung, aber angenommen der IRQ kommt wirklich 3 Zyklen nach IRQST: Wenn ich nun von den 8.5 Zyklen die 3 Zyklen abziehe, komme ich auf eine Differenz von 5.5 Zyklen. Das wäre dann die Verzögerung zwischen Sampling des Stop-Bits und Signalisierung in IRQST.

Mit 131 + 5.5 = 136.5 würde es also passen (< 137), mit 133+5.5=138.5 wären wir über den 137 Zyklen.

Diese Rechnung ist natürlich mit sehr vielen Fragezeichen zu versehen, vieles ist nicht 100% klar, aber vielleicht kann sie uns ja als Arbeitshypothese dienen.

Achja: Ich hab's geschafft meinen Fast VBI Code auf 48 (statt vorher 55) Zyklen im worst Case zu drücken, damit läuft die Highspeed Routine nun auch einwandfrei mit dem 400/800er OS!

Der Trick dabei ist recht einfach: im VBI erhöhe ich nur RTCLOK+2 und RTCLOK+1, das spart ein BNE und ein DEC (also 7 Zyklen im worst case), am Ende des SIO Codes checke ich dann ob RTCLOK+1 übergelaufen ist und erhöhe ggf. RTCLOK um 1.

so long,

Hias

Re: Highspeed mit Pokey-Divisor 0

von Dietrich » Di 17. Aug 2010, 20:57
Hias hat geschrieben:BTW: Danke, Deine Software gefällt mir sehr gut (nicht nur der SIO Code da drin :-)

Danke, danke. Deine Software ist aber auch nicht ohne. Und so schnell fertig geworden, da hab ich doch etwas gebraucht, bis das alles konzipiert und ausprogrammiert war - das Löschen einzelner Images wollte ich unbedingt haben :-)

Hias hat geschrieben:Bleiben also 141-4 = 137 Zyklen Zeit.

Wieso 141? Es müssten doch bei Pokey Divisor 0 140 Takte sein, oder?

Hias hat geschrieben:In Zyklus 8 passiert nun folgendes:
- ANTIC startet den VBI und zieht NMI auf low

Interessant, wo steht das? Ich habe durch Experimentieren herausgefunden, dass der VBI genau 16 Takte, nachdem VCOUNT von 123 auf 124 gewechselt ist, aktiv wird. Nach dem Altirra-HW-Manual wechselt VCOUNT bei Takt 104 einer Rasterzeile. Folglich müsste der VBI eigentlich bei Takt 6 ausgelöst werden ?!?

Hias hat geschrieben:Diese Rechnung ist natürlich mit sehr vielen Fragezeichen zu versehen, vieles ist nicht 100% klar, aber vielleicht kann sie uns ja als Arbeitshypothese dienen.

Bis auf ein paar Takte stimmt's ja, möglich ist vieles. Ich bin damit recht zufrieden.

Hias hat geschrieben:Der Trick dabei ist recht einfach: im VBI erhöhe ich nur RTCLOK+2 und RTCLOK+1, das spart ein BNE und ein DEC (also 7 Zyklen im worst case), am Ende des SIO Codes checke ich dann ob RTCLOK+1 übergelaufen ist und erhöhe ggf. RTCLOK um 1.

Nette Idee! D.h. Du merkst Dir RTCLOK+1 zu Anfang und prüfst am Ende der SIO-Routine, ob nun RTCLOK+1 < als das alte RTCLOK+1 ist?

Wie man sieht, kann man mit Überlegung immer noch was rausholen :-)

Noch etwas: Ich habe festgestellt, dass ein Overrun in SKSTAT nur dann gemeldet wird, wenn das IRQ-SERIN-Bit noch auf 0 steht. Das bedeutet, dass die korrekte Reihenfolge in der Leseschleife eigentlich so aussieht:
1) Pollschleife
2) SERIN lesen
3) SKSTAT auf Overrun(+Frame) testen
4) IRQ-SERIN-Bit zurücksetzen

In Deiner (und meiner) Schleife sind 3 und 4 vertauscht, was zur Folge hat, dass Overruns, die zwischen Rücksetzen des IRQ-SERIN-Bits und Prüfen von SKSTAT auftreten, nicht bemerkt werden, so dass dann ein Byte fehlt und der User den elendlich langen 7 Sekunden-Timeout abwarten muss (wenn er nicht auf die Idee kommt, Break zu drücken). Allerdings gibt es damit nun Probleme mit auftretenden VBIs, weil nun das Rücksetzen des IRQ-Bits wegen des dazwischengeschobenen SKSTAT-Tests 8 Takte länger dauert ...

Gruß Dietrich

Re: Highspeed mit Pokey-Divisor 0

von HiassofT » Mi 18. Aug 2010, 17:07
Dietrich hat geschrieben:
Hias hat geschrieben:Bleiben also 141-4 = 137 Zyklen Zeit.

Wieso 141? Es müssten doch bei Pokey Divisor 0 140 Takte sein, oder?

Theoretisch ja, in der Praxis schafft es der Pokey aber nicht in 140 Zyklen. Hatte da letztes Jahr einen recht aufwändigen Test gestartet: Siehe: http://www.atariage.com/forums/topic/13 ... p__1696180 sowie mein Posting davor: http://www.atariage.com/forums/topic/13 ... p__1695399

Deshalb funktionieren auch Divisor 0 und 1 nicht mit der original SDrive und SIO2SD Firmware. Die SDrive Firmware hatte ich ja schon gepatcht, die SIO2SD kommt demnächst dran.

Hias hat geschrieben:In Zyklus 8 passiert nun folgendes:
- ANTIC startet den VBI und zieht NMI auf low

Interessant, wo steht das? Ich habe durch Experimentieren herausgefunden, dass der VBI genau 16 Takte, nachdem VCOUNT von 123 auf 124 gewechselt ist, aktiv wird. Nach dem Altirra-HW-Manual wechselt VCOUNT bei Takt 104 einer Rasterzeile. Folglich müsste der VBI eigentlich bei Takt 6 ausgelöst werden ?!?

In meinem Manual (vom 25.4.2010) steht, daß VCOUNT bei Takt 111 wechselt, und im DLI Kapitel davor, daß NMIs immer bei Takt 8 ausgelöst werden.

Hab' aber gerade noch entdeckt, daß der 6502 anscheinend 2 Takte braucht (plus evtl. weitere Zyklen wenn noch ein Befehl ausgeführt wird), bis er mit dem 7-Zyklus NMI Start beginnt. Da muss ich wohl noch mal von vorne mit dem Rechnen beginnen. Naja, Cycle Counting ist nicht so meine Stärke :-)

Hias hat geschrieben:Diese Rechnung ist natürlich mit sehr vielen Fragezeichen zu versehen, vieles ist nicht 100% klar, aber vielleicht kann sie uns ja als Arbeitshypothese dienen.

Bis auf ein paar Takte stimmt's ja, möglich ist vieles. Ich bin damit recht zufrieden.

Mich würd's ja noch interessieren, wie gross der Delay im Pokey ist, vom Sampling des Stopbits bis IRQST gesetzt wird. Den Zeitpunkt wann der POKEY sampelt weiss ich, jetzt müsste ich nur noch einen Versuchsaufbau machen um IRQST mit einer Genauigkeit von 1 Zyklus abzufragen. Hätte da schon eine Idee (CPLD steuert Pokey direkt an, geclockt vom Atari mit den 1.79 MHz), ist aber etwas aufwändig und wird noch ein wenig dauern bis ich dazu komme.

Hias hat geschrieben:Der Trick dabei ist recht einfach: im VBI erhöhe ich nur RTCLOK+2 und RTCLOK+1, das spart ein BNE und ein DEC (also 7 Zyklen im worst case), am Ende des SIO Codes checke ich dann ob RTCLOK+1 übergelaufen ist und erhöhe ggf. RTCLOK um 1.

Nette Idee! D.h. Du merkst Dir RTCLOK+1 zu Anfang und prüfst am Ende der SIO-Routine, ob nun RTCLOK+1 < als das alte RTCLOK+1 ist?

Ja, genau. Die Idee kam mir Sonntag Nacht nachdem ich den PC schon abgeschaltet hatte. Am Montag hab' ich's dann getestet :-)

Noch etwas: Ich habe festgestellt, dass ein Overrun in SKSTAT nur dann gemeldet wird, wenn das IRQ-SERIN-Bit noch auf 0 steht. Das bedeutet, dass die korrekte Reihenfolge in der Leseschleife eigentlich so aussieht:
1) Pollschleife
2) SERIN lesen
3) SKSTAT auf Overrun(+Frame) testen
4) IRQ-SERIN-Bit zurücksetzen

In Deiner (und meiner) Schleife sind 3 und 4 vertauscht, was zur Folge hat, dass Overruns, die zwischen Rücksetzen des IRQ-SERIN-Bits und Prüfen von SKSTAT auftreten, nicht bemerkt werden, so dass dann ein Byte fehlt und der User den elendlich langen 7 Sekunden-Timeout abwarten muss (wenn er nicht auf die Idee kommt, Break zu drücken). Allerdings gibt es damit nun Probleme mit auftretenden VBIs, weil nun das Rücksetzen des IRQ-Bits wegen des dazwischengeschobenen SKSTAT-Tests 8 Takte länger dauert ...

Hmmm... Ich glaub' hier tritt noch irgendein anderes Problem auf. Overrun wird ja dann gesetzt, wenn SERIN=0 ist und ein neues Byte empfangen wird. Das Overrun Bit in SKSTAT bleibt aber gesetzt bis man SKREST beschreibt.

Hab' hier mal getestet: Ein DLI mit einem "STA WSYNC" führt meist zu einem Overrun Error, gelegentlich zu einem Timeout. Ein DLI mit 2 mal STA WSYNC gibt immer einen Overrun Error.

Die kritische Phase, in der Bytes verloren gehen können, ist eigentlich nur die nach dem ersten "STA IRQEN" (mit der das SERIN bit zurückgesetzt wird) bis zum zweiten "STA IRQEN" (der SERIN IRQs wieder einschält) plus weitere 4 Zyklen (Pokey Delay). Wenn in der Zeit ein Byte ankommt, wird es nicht in SERIN gemeldet (durch VBIs, aber ich vermute vor allem durch ANTIC DMA) kann das kritische Fenster deutlich länger als 2+4+4=10 Zyklen sein.

Dieses kritische Fenster gibt's immer, egal ob man den Code vor oder nach dem SKSTAT Check hat. Da SKSTAT aber eh gelatcht wird, und es besser ist den IRQEN Code möglichst bald auszuführen (damit der Pokey möglichst bald wieder ein Byte empfangen kann) bin ich dafür den Code so zu belassen wie er ist.

so long,

Hias

Re: Highspeed mit Pokey-Divisor 0

von Dietrich » Do 19. Aug 2010, 22:45
Hias hat geschrieben:In meinem Manual (vom 25.4.2010) steht, daß VCOUNT bei Takt 111 wechselt, und im DLI Kapitel davor, daß NMIs immer bei Takt 8 ausgelöst werden.

Stimmt, habe das mit STA WSYNC verwechselt! Allerdings habe ich definitiv 16 Takte zwischen dem VCOUNT-Wechsel auf 124 und dem Beginn des VBI, das lässt sich leicht testen. Das HW-Manual scheint hier also nicht richtig zu sein ... (sind aber auch an anderer Stelle Fehler drin)

Code: Alles auswählen
lda #124
?1 cmp vcount
beq ?1               warten bis vcount <>124 ist
?2 cmp vcount
bne ?2
ldx 0               nun ist vcount von 123 auf 124 gewechselt
?3 cmp vcount
beq ?1            noch kein VBI aufgetreten
rts

Dieses Programm läuft in einer Endlosschleife, obwohl zwischen den vcount-Abfragen in ?2 und ?3 10-16 Takte liegen. Ergo kann der VBI nicht weniger als 16 Takte nach dem VCOUNT-Wechsel auf 124 auftreten. Wenn man ldx 0 durch ldx $100 ersetzt, endet das Programm, also müssen es genau 16 Takte sein.

Re: Highspeed mit Pokey-Divisor 0

von HiassofT » Fr 20. Aug 2010, 02:32
HiassofT hat geschrieben:Mich würd's ja noch interessieren, wie gross der Delay im Pokey ist, vom Sampling des Stopbits bis IRQST gesetzt wird. Den Zeitpunkt wann der POKEY sampelt weiss ich, jetzt müsste ich nur noch einen Versuchsaufbau machen um IRQST mit einer Genauigkeit von 1 Zyklus abzufragen. Hätte da schon eine Idee (CPLD steuert Pokey direkt an, geclockt vom Atari mit den 1.79 MHz), ist aber etwas aufwändig und wird noch ein wenig dauern bis ich dazu komme.

CPLD ist doch zu aufwändig, ein Stückchen Draht (in alter McGyver Manier) und etwas Hirnschmals genügen auch :-)

Vorweg gleich mal das Ergebnis: Es vergehen 5 Takte nach dem Sampling des Stopbits bis der Pokey das "serial input ready" Bit in IRQST setzt. Im 6. Takt ist IRQST richtig.

Der Versuchsaufbau war denkbar einfach: Pin 7 (/COMMAND) mit Pin 3 (Data In) an der SIO Buchse verbunden, dann per Software ein Startbit erzeugt und nach verschiedenen, genau definierten Zyklen, IRQST abgefragt.

Die Software macht nun folgendes: In Zyklus 69 einer Scanline wird der STA PBCTL Befehl ausgeführt, der COMMAND Low zieht. Im Zyklus 70 wechselt dann also COMMAND von high auf low und das Startbit beginnt. 14 Zyklen später wird dann Command wieder auf High gesetzt, jetzt kommen die Datenbits und das Stopbit, COMMAND lasse ich aber auf High, dH es wird ein $FF Byte gesendet.

Ein ganzes Byte dauert bei Divisor 0 10*14 = 140 Zyklen, d.h. im Zyklus 95 (inklusive) der nächsten Scanline endet das Stop-Bit.

Beim Pokey erfolgt das Sampling nicht genau in der Bit-Mitte sondern 5 Zyklen nach hinten verschoben. Bei Divisor 0 sampelt er im 12. Zyklus von 14. Das Sampling des Stopbits erfolgt also im 93. Zyklus der Scanline.

Nun habe ich den Code so ausgelegt, daß er einmal im 93. Zyklus IRQST liest (also noch bevor der Pokey sampelt), einmal im 94. usw. bis zum 102. Zyklus, mit folgendem Ergebnis:

In den Zyklen 93-98 war das Bit 5 High (=kein Byte da), in Zyklus 99-107 war es Low (=Byte da). Differenz zum 93. Zyklus in dem das Sampling passiert also 6 Zyklen.

Nun zurück zum früheren, etwas vermurksten, NMI Cycle Counting:

Die CPU beginnt mit der 7-Zyklen NMI Aktivierung erst bei Zyklus 10, nicht bei Zyklus 8. Also verschiebt sich alles um 2 Zyklen. Für die ganze Rechnung macht das nur einen kleinen, aber wichtigen Unterschied: Auch bei 93 Zyklen für den NMI Handler fängt sich der Code bis zum 2. "STA IRQEN" einen weiteren Refresh Zyklus ein. Insgesamt dauert der Code dann im worst case 132 Zyklen (nicht 131), also nur um 1 (nicht 2) Zyklen kürzer als bei 94 NMI Zyklen.

Nun macht das ganze Sinn: 5 Zyklen Delay + 132 Zyklen für den Code + 4 Zyklen Setup Time = 141 Zyklen. Auch die mit den erwähnten ~5.5 Zyklen (~8.5 Zyklen insgesamter IRQ Delay minus 3 Zyklen IRQST-IRQ Delay) deckt sich das Ergebnis.

Ich hoffe mal, ich hab' mich bei dem ganzen Kram nicht verrechnet, Cycle Counting ist nicht so mein Ding und kann einen wirklich in den Wahnsinn treiben :-)

Wer das ganze selber Testen möchte: ich hab' den Source-Code inkl. fertig assembliertem ATR angehängt.

so long,

Hias

PS: @Dietrich: Das VCOUNT dingens muss ich mir später mal ansehen, wenn ich auch nur einen einzigen Atari-Zyklus zusätzlich zähle kann ich mich umgehend in die Klapse einliefern lassen :-)))

Re: Highspeed mit Pokey-Divisor 0

von HiassofT » Mi 25. Aug 2010, 23:49
Ich hab' die letzten Tage einiges weiter getestet und meinen Test-Code erweitert. Zwar sind mit jetzt einige Sachen klarer (im Bezug auf den Pokey), andererseits scheinen meine bisherigen Annahmen zum Timing nun doch falsch zu sein. Aber fangen wir mal vorne an:

Wenn ein Byte von Zyklus 0 bis 139 (10*14 Zyklen) übertragen wird, sampelt der Pokey SERIN jeweils zum Ende des 11. Zyklus (also am Ende von Zyklus 11, 25, 39, ... 123, 137). Das Stopbit wird also am Ende von Zyklus 137 verarbeitet. Soweit nichts neues, das wusste ich vorher auch schon (wollte es aber nochmal überprüfen).

In Zyklus 143 wird der Empfang des Bytes in IRQST signalisiert, exakt am Ende dieses Zykluses zieht Pokey IRQ auf Low. Zwischen Sampling des Stop-Bits und erstmaliger Signalisierung des Empfangs per IRQST vergehen also 5 Zyklen (oder je nach Betrachtungsweise 6 Zyklen wenn man vom Ende des Zyklus 137 bis zum Ende des Zyklus 143 rechnet). Soweit immer noch nichts neues, das hatte ich vorher ja auch schon rausgefunden.

Nun das spannendere, ich wollte rausfinden wann spätestens der SERIN IRQ per IRQEN freigeschaltet werden muss. Ergebnis: in Zyklus 142, also im Zyklus unmittelbar bevor der Pokey per IRQST den Empfang signalisiert.

Mit anderen Worten: für den SIO-Code stehen insgesamt 141 Zyklen bereit. Der Delay in der Signalisierung ist egal (Byte endet in Zyklus 139 inklusive, Signalisierung in Zyklus 143), dadurch verschiebt sich nur das Timing, aber es wird nicht verkürzt. Wichtig ist nur, daß 140 Zyklen nachdem der Empfang signalisiert wurde IRQEN gesetzt wird.

Möglicherweise spielen die Signalflanken auch noch eine Rolle, die Tests hatte ich auf einem 600XL und 800XL ohne Kondensatoren durchgeführt, bei einem 800XL und einem 130XE mit Kondensatoren waren alle Werte einfach um 1 nach hinten verschoben (144 statt 143 etc.). Eine wirkliche Verkürzung gab es dadurch aber auch nicht...

Hmpf. Jetzt bin ich ziemlich planlos. Evtl. habe ich irgendwo etwas wichtiges übersehen (Zyklen zählen ist ja nicht so mein Ding, hab' ich glaubich schonmal erwähnt :-). Wenn irgendwer von Euch eine gute Idee hat wäre ich sehr dankbar.

Achja: Hier der Link zur Test-Software: http://www.horus.com/~hias/tmp/pokeytest-1.0.zip

Auf AtariAge hab' ich das auch gepostet (inkl. ein paar Screenshots des Timings), vielleicht meldet sich dort ja auch noch wer:
http://www.atariage.com/forums/topic/16 ... g-details/

so long,

Hias

Re: Highspeed mit Pokey-Divisor 0

von tfhh » Do 26. Aug 2010, 08:58
Moin Hias,
HiassofT hat geschrieben:Möglicherweise spielen die Signalflanken auch noch eine Rolle, die Tests hatte ich auf einem 600XL und 800XL ohne Kondensatoren durchgeführt, bei einem 800XL und einem 130XE mit Kondensatoren waren alle Werte einfach um 1 nach hinten verschoben (144 statt 143 etc.). Eine wirkliche Verkürzung gab es dadurch aber auch nicht...

Hmpf. Jetzt bin ich ziemlich planlos. Evtl. habe ich irgendwo etwas wichtiges übersehen (Zyklen zählen ist ja nicht so mein Ding, hab' ich glaubich schonmal erwähnt :-). Wenn irgendwer von Euch eine gute Idee hat wäre ich sehr dankbar.

Achja: Hier der Link zur Test-Software: http://www.horus.com/~hias/tmp/pokeytest-1.0.zip

Vielleicht liege ich ja vollkommen daneben, aber ich vermute, daß es auch definitiv Design-Unterschiede zwischen den einzelnen Pokey-Herstellern gibt. Und es gibt deutlich mehr Pokey-Hersteller als z.B. Hersteller von Antic und GTIA, von daher könnten Streuungen durchaus zu solchen Effekten führen.

Als Du seinerzeit die S-Drive Firmware angepasst hast, hatte ich schon festgestellt, daß nicht alle meine Pokeys mit Divisor 0 laufen. Bisher hatte ich keine Zeit/Lust, da mal genauer nachzuforschen, kann das aber gern machen.

Wenn Du mir mailst, wie die Software von Dir anzuwenden ist, kann ich mal mein Pokey-Arsenal (min. 7 verschiedene Typen habe ich, sicher noch mehr wenn ich noch ein paar Rechner aufmache) nacheinander im selben XL-Referenzboard durchprüfen. Da ich nun auch einen miniLA besitze (muß nur noch die Meßstrippen fertigbasteln), kann ich hier auch mit logik-analysieren :D

Gruß, Jürgen

Re: Highspeed mit Pokey-Divisor 0

von HiassofT » Do 26. Aug 2010, 11:08
tfhh hat geschrieben:Vielleicht liege ich ja vollkommen daneben, aber ich vermute, daß es auch definitiv Design-Unterschiede zwischen den einzelnen Pokey-Herstellern gibt. Und es gibt deutlich mehr Pokey-Hersteller als z.B. Hersteller von Antic und GTIA, von daher könnten Streuungen durchaus zu solchen Effekten führen.

Hmmm. Ausschliessen kann man natürlich nichts, ich würde aber eher vermuten, daß in allen Pokeys die gleiche Logik steckt (also die gleiche Maske verwendet wurde) und sich die Unterschiede auf Details wie zB Flankensteilheit, Spannungspegel etc. beschränken - die normalen Streuungen in den Fertigungsprozessen halt.

Wenn Du mir mailst, wie die Software von Dir anzuwenden ist, kann ich mal mein Pokey-Arsenal (min. 7 verschiedene Typen habe ich, sicher noch mehr wenn ich noch ein paar Rechner aufmache) nacheinander im selben XL-Referenzboard durchprüfen. Da ich nun auch einen miniLA besitze (muß nur noch die Meßstrippen fertigbasteln), kann ich hier auch mit logik-analysieren :D

Wäre super wenn Du testen könntest, kann ja auch gut sein, daß ich da noch irgendwo einen Bug drin hab oder so.

Einfach das ATR booten, dann SIO Pin 3 und 7 verbinden und eine Taste drücken. Dann wird das Ergebnis angezeigt. Durch einen weiteren Tastendruck kannst Du die Tests wiederholen.

Wichtig ist natürlich wie man die Ausgabe interpretieren soll. Hier der Screenshot von meinem 800XL (ohne Kondensatoren):
800xl.jpg
800xl.jpg (64.2 KiB) 9873-mal betrachtet

In der ersten Zeile siehst Du jeweils die Zyklus-Nummer, in Hex, beginnend bei 0 (0 ist der Zyklus in dem das Start-Bit beginnt). Danach folgen die Werte von IRQST, SKSTAT und SERIN.

Im "Bit 7" Tests geht's um die Werte von SERIN. Es soll ein $81 Byte übertragen werden und ich setze COMMAND/DataIn zu verschiedenen Zeitpunkten während Bit 7 auf High. War es früh genug, wird $81 angezeigt, ansonsten $01.

Der "StopBit" Test ist ähnlich, hier wird erst während des Stop-Bits DataIn auf High gesetzt. SERIN ist also immer $01, aber der Wert von SKSTAT ändert sich. Wenn alles OK ist, sollte er $FF sein, wurde DataIn zu spät gesetzt meldet Pokey einen Framing Error und setzt SKSTAT auf $7F.

Im "IRQST" Tests geht's um den Wert von IRQST. Da checke ich den Wert von IRQST zu verschiedenen Zeitpunkten. Ist noch kein Byte eingetroffen steht da $F7, ist das Byte schon eingetroffen ist Bit 5 von IRQST Low, also $D7.

Im "IRQEN" Test geht's ebenfalls um den Wert von IRQST. Hier setze ich Bit 5 von IRQEN zu verschiedenen Zeitpunkten (von vorher Low auf High) und checke danach ob der Pokey den Empfang des $81 Bytes meldet. $D7 ist OK, $F7 heisst ich war zu spät und Pokey hat den Interrupt ignoriert.

Den MiniLA brauchst Du (vorerst) mal noch nicht, den hab' ich hauptsächlich deshalb drangehängt um zu sehen ob mein Testprogramm korrekt läuft. Zyklen-Zählen verursacht Kopfschmerzen und ich hab' da öfters einen blöden Fehler eingebaut....

so long,

Hias

Re: Highspeed mit Pokey-Divisor 0

von tfhh » Do 26. Aug 2010, 21:11
Moin,
Wenn Du mir mailst, wie die Software von Dir anzuwenden ist, kann ich mal mein Pokey-Arsenal (min. 7 verschiedene Typen habe ich, sicher noch mehr wenn ich noch ein paar Rechner aufmache) nacheinander im selben XL-Referenzboard durchprüfen. Da ich nun auch einen miniLA besitze (muß nur noch die Meßstrippen fertigbasteln), kann ich hier auch mit logik-analysieren :D

Wäre super wenn Du testen könntest, kann ja auch gut sein, daß ich da noch irgendwo einen Bug drin hab oder so.

Ich habe mal 6 verschiedene Pokeys gefunden - ich habe noch weitere Modelle, aber dazu müßte ich erst im Keller wühlen, das ist ein Job fürs Wochenende, wenn es denn überhaupt noch Not tut. Sowie ich das gesehen habe, sind meine Ergebnisse jeweils identisch mit Deinem. Im Anhang findest Du die Screenshots der 6 Tests mit den verschiedenen Pokeys, hier die im Test genutzten Pokeys als "Gruppenfoto" :D

Pokeys.jpg
Pokeys.jpg (198.39 KiB) 9858-mal betrachtet

Download der Bilder hier klicken

Hoffe, das hilft Dir irgendwie :roll:

Gruß, Jürgen

Re: Highspeed mit Pokey-Divisor 0

von HiassofT » Fr 27. Aug 2010, 00:16
Hallo Jürgen!

tfhh hat geschrieben:Ich habe mal 6 verschiedene Pokeys gefunden - ich habe noch weitere Modelle, aber dazu müßte ich erst im Keller wühlen, das ist ein Job fürs Wochenende, wenn es denn überhaupt noch Not tut. Sowie ich das gesehen habe, sind meine Ergebnisse jeweils identisch mit Deinem. Im Anhang findest Du die Screenshots der 6 Tests mit den verschiedenen Pokeys, hier die im Test genutzten Pokeys als "Gruppenfoto" :D

Vielen Dank für's Testen!

Hab' mir die Screenshots angesehen, sind tatsächlich alle identisch. Ich glaube weitere Tests kannst Du Dir sparen, das reicht erstmal (und ich erwarte mir auch keine Abweichungen).

Interessanter wären evtl. noch Tests mit verschiedenen Ataris, werde mal meinen NTSC 800XL ausgraben, aber auch da glaub' ich nicht, daß es irgendwelche Unterschiede gibt.

so long,

Hias

Re: Highspeed mit Pokey-Divisor 0

von tfhh » Fr 27. Aug 2010, 07:43
Moin Hias,
HiassofT hat geschrieben:Hab' mir die Screenshots angesehen, sind tatsächlich alle identisch. Ich glaube weitere Tests kannst Du Dir sparen, das reicht erstmal (und ich erwarte mir auch keine Abweichungen).

Interessanter wären evtl. noch Tests mit verschiedenen Ataris, werde mal meinen NTSC 800XL ausgraben, aber auch da glaub' ich nicht, daß es irgendwelche Unterschiede gibt.

Ich kann den Test sonst noch auf einem 800 XLF (also mit Freddie) durchführen, da habe ich auch ein sauberes Referenzboard von. Das Timing bei Systemen mit Freddie ist ja doch etwas unterschiedlich - ich nehme dann die 6 Pokeys von gestern einfach nochmal zum Prüfen. Achja, SIO-Caps waren natürlich auch entfernt 8)

Gruß, Jürgen

Re: Highspeed mit Pokey-Divisor 0

von HiassofT » Fr 27. Aug 2010, 12:22
Hi Jürgen!

tfhh hat geschrieben:Ich kann den Test sonst noch auf einem 800 XLF (also mit Freddie) durchführen, da habe ich auch ein sauberes Referenzboard von. Das Timing bei Systemen mit Freddie ist ja doch etwas unterschiedlich - ich nehme dann die 6 Pokeys von gestern einfach nochmal zum Prüfen. Achja, SIO-Caps waren natürlich auch entfernt 8)

Um so genaues Timing geht's bei diesem Test garnicht, wichtig ist nur die Anzahl der CPU-Zyklen.

Ich hab' nun einen weiteren Test mit meinem NTSC 800XL gemacht, wie erwartet mit dem gleichen Ergebnis wie bei den PAL Ataris.

Gestern hatte ich mir auch noch das IRQ Timing der CPU angesehen, wie zB im Altirra HW Manual beschrieben beginnt die CPU frühestens 3 Zyklen nach der Signalisierung in IRQST mit der 7-Zyklen IRQ-Sequenz. Am Ende von Zyklus 143 geht IRQ auf low, dann führt die CPU in den Zyklen 144 und 145 weiterhin normal den Code aus und startet in Zyklus 146 mit der IRQ-Sequenz (bzw. etwas später, wenn die CPU in Zyklus 146 mitten in einem Befehl steckt).

Das IRQ-Verhalten der CPU ist so nirgends explizit in den Datenblättern beschrieben. Im Mos Hardware Manual findet sich in der Beschreibung des NMI Pins, daß er mindestens 2 Zyklen lang auf low sein muss damit die CPU einen NMI erkennt. Die Beschreibung des IRQs verweist zwar auf den NMI, aber es ist nicht 100% klar ob diese 2 Zyklen auch für den IRQ Pin gelten. Offensichtlich gelten diese 2 Zyklen auch für den IRQ Pin.

Nun ist klar: 1 Zyklus geht auf das Konto des Pokey und 2 auf das Konto der CPU.

BTW: Im AtariAge Thread hab' ich auch Screenshots vom IRQ Timing Test gepostet.

so long,

Hias

Re: Highspeed mit Pokey-Divisor 0

von HiassofT » Fr 27. Aug 2010, 17:39
Hi Jürgen!

Jetzt hab' ich doch noch einen Timing-kritischen Test für all Deine Pokeys :-)

Lade Dir das neue Test-Programm runter und starte das irqtest.atr
http://www.horus.com/~hias/tmp/pokeytest-1.1.zip

Pokey setzt den IRQ sehr knapp vor Ende von PHI2, und je nach dem wie knapp es war beginnt die CPU schon früher mit der IRQ-Sequenz. Der 1 Zyklus Verzögerung durch den Pokey fällt dann weg, es bleiben die 2 Zyklen von der CPU.

Das Testprogramm startet eine Sequenz von 2/3/4/5/6 Zyklen langen Befehlen zu verschiedenen Zeitpunkten (erste Zeile: start-Zyklus in Hex) und misst/berechnet dann, bei welchem Zyklus die IRQ-Sequenz angefangen hat (2. Zeile, ebenfalls hex).

Mein PAL 800XL und mein NTSC 800XL schaffen's meist mit Zyklus $91 = 145, bei wiederholten Testläufen mit dem 800XL hatte ich aber auch schon mindesten $92. Mein 600XL kommt normalerweise auf mindestens $92, ausser wenn der Pokey kalt ist, dann schafft der auch $91.

Hier der Screenshot vom 800XL:
irq-800xl.jpg
irq-800xl.jpg (71.26 KiB) 9820-mal betrachtet


Und hier vom 600XL:
irq-600xl.jpg
irq-600xl.jpg (79.39 KiB) 9820-mal betrachtet

so long,

Hias
1, 2