Drodzy magnetofoniarze, pamiętacie te pełne napięcia chwile z dzieciństwa, gdy chodziliście po domu na palcach, błagaliście domowników aby mówili szeptem, wszystko po to aby nie zakłócić spokojnego przebiegu ładowania Ulubionej Gry? Ile razy wasze starania spełzły na niczym, gdy w 15. minucie komputer niemiłym buczeniem oznajmiał "nic z tego"? Nadeszła chwila oczyszczenia! Za Wasze zszargane nerwy odpowiada nie szczekający pies, nie głośna muzyka z Pokoju Starszego Brata, lecz błąd w OS-ie.

Podczas pracy nad A8CAS notorycznie przydarzał mi się dziwny problem: podczas odczytu w emulatorze obrazu CAS kasety, raz na kilkanaście-kilkadziesiąt prób występował błąd odczytu. Poszukiwania spełzły na niczym, dopiero kol. FUJI przeanalizował sprawę dogłębnie i wywnioskował, że podczas odczytu w pewnej szczególnej sytuacji błędnie wykrywane jest baudrate rekordu. Rzut oka na źródła OS-u potwierdził obawy.

Główna procedura obliczania baudrate, SBR ($ED3D) oczekuje aż sygnał na DATA IN zmieni się z 1 na 0, czyli na 1. bit rekordu. W tym momencie aktualne wartości VCOUNT i RTCLOK+2 są zapisywane pod TIMER1 i TIMER1+1. Potem procedura odczekuje 10 zmian sygnału DATA IN i znowu zapisuje aktualne VCOUNT i RTCLOK+2, tym razem w akumulatorze i rejestrze Y.

SBR     =       $ED3D               ;entry

SBR1    LDA     BRKKEY
        BNE     SBR2            ;if BREAK key not pressed

        JMP     PBK             ;process BREAK key, return

SBR2    SEI
        LDA     TIMFLG          ;timeout flag
        BNE     SBR3            ;if no timeout

        BEQ     SBR5            ;process timeout

; Czekaj na bit startu (0)
SBR3    LDA     SKSTAT          ;???
        AND     #$10            ;extract start bit???
        BNE     SBR1            ;if start bit

        STA     SAVIO           ;save serial data in
; Zapisz aktualne VCOUNT i RTCLOK+2 w TIMER1, TIMER1+1
        LDX     VCOUNT          ;vertical line counter
        LDY     RTCLOK+2        ;low byte of VBLANK clock
        STX     TIMER1
        STY     TIMER1+1        ;save initial timer value
        LDX     #1
        STX     TEMP3           ;set mode flag???
        LDY     #10             ;10 bits

; Odczekaj 10 zmian sygnału
SBR4    LDA     BRKKEY          ;???
        BEQ     PBK             ;if BREAK key pressed, process, return

        LDA     TIMFLG          ;timeout flag
        BNE     SBR6            ;if no timeout

SBR5    CLI
        JMP     ITO             ;indicate timeout, return

SBR6    LDA     SKSTAT          ;???
        AND     #$10            ;extract ???
        CMP     SAVIO           ;previous serial data in
        BEQ     SBR4            ;if data in not changed

        STA     SAVIO           ;save serial data in
        DEY                     ;decrement bit counter
        BNE     SBR4            ;if not done

        DEC     TEMP3           ;decrement mode???
        BMI     SBR7            ;if done with both modes

; Po 10 zmianach sygnału, zapamiętaj aktualne VCOUNT i RTCLOK+2
        LDA     VCOUNT          ;???
        LDY     RTCLOK+2        ;???
; Oblicz baudrate
        JSR     CBR             ;compute baud rate
        LDY     #9              ;9 bits
; Zignoruj następne 9 zmian sygnału (rekord zaczyna się od 20 naprzemiennych 
; bitów 0 i 1 (2 bajty $55), zczego tylko 10 pierwszych jest używanych do
; obliczania baudrate)
        BNE     SBR4            ;set bit counter
; Dalej nieistotne - zapis wyniku do AUDF3/4

Potem jest skok do CBR ($ECC8), gdzie obliczana jest ilość skanlinii które minęły pomiędzy ww. dwoma momentami (dokładniej, ilość skanlinii/2, w końcu to VCOUNT).

CONS1X  DB    131        ;liczba skanlinii/2 w NTSC
        DB    156        ;liczba skanlinii/2 w PAL

CBR     =       $ECC8           ;entry
; w A i Y znajdują się wartości odpowiednio VCOUNT i RTCLOK+2 po 10. zmianie sygnału
        STA     TIMER2          ;save final timer value
        STY     TIMER2+1
        JSR     AVV             ;adjust VCOUNT value
        STA     TIMER2          ;save adjusted timer 2 value
        LDA     TIMER1
        JSR     AVV             ;adjust VCOUNT value
        STA     TIMER1          ;save adjusted timer 1 value
        LDA     TIMER2
        SEC
        SBC     TIMER1
        STA     TEMP1           ;save difference
        LDA     TIMER2+1
        SEC
        SBC     TIMER1+1
        TAY                     ;difference
        LDX     PALNTS          ; 0 = NTSC, 1 = PAL
        LDA     #0
        SEC
        SBC     CONS1X,X        ;???

CBR1    CLC
        ADC     CONS1X,X        ;accumulate product
        DEY
        BPL     CBR1            ;if not done

; W tym momencie A zawiera ilość skanlinii/2, które minęły podczas 10. zmian sygnału DATA IN.
; Dalej nieistotne - robiona jest interpolacja i ustalane są wartości dla AUDF3/4 na postawie tablicy

CBR, w uproszczeniu, odejmuje pary liczb TIMER2, TIMER2+1 od TIMER1, TIMER1+1 aby uzyskać odpowiednią wartość. Przedtem jednak każda z par liczb jest lekko modyfikowana (skok do AVV ($ED2E)), żeby odejmowanie miało sens:

CONS2X  DB    7        ;liczba skanlinii/2 od skanlinii 248. do 0. w NTSC
        DB    32        ;liczba skanlinii/2 od skanlinii 248. do 0. w PAL

AVV     =       $ED2D   ;entry
; W linii 248 (= $7C * 2) zachodzi przerwanie VBL, w którym RTCLOK+2 jest zwiększane o 1.
        CMP     #$7C
        BMI     AVV1    ;if A < $7C

        SEC
        SBC     #$7C
        RTS             ;return

AVV1    CLC
        LDX     PALNTS
        ADC     CONS2X,X
        RTS             ;return

AVV bierze pod uwagę, że w 248 linii ekranu następuje zwiększenie RTCLOK+2 o 1.

Ogólnie wszystko działa dobrze, przy następującym założeniu: w VCOUNT wartość $7C pojawia się po wystąpieniu przerwania VBL (a tym samym po zwiększeniu RTCLOK+2). Niestety założenie to nie jest prawdą. VCOUNT jest zwiększane zawsze w 111 cyklu poprzedniej skanlinii (czyli VCOUNT przeskakuje na $7C w 111 cyklu skanlinii 247), natomiast CPU zaczyna obsługiwać VBL najwcześniej w 9. cyklu linii 248 (12 cykli później). Linia 248 jest daleko poniżej końca Display Listy, standardowo jest też wyłączone DMA dla PMG, więc całe 12 cykli jest tu dostępne dla CPU. Na każdą ramkę przypada zatem 12-cyklowy okres, podczas którego jest problem. Jeśli w okolicy tych dwunastu cykli zmieni się sygnał DATA IN, wykryte baudrate może być nieprawidłowe.

FUJI wykonał odpowiednie testy na prawdziwym sprzęcie (spreparowany programik i nagranie składające się z 10000 dwubajtowych rekordów $5555, mam nadzieję że napisze tu coś od siebie), i wyszło że prawdopodobieństwo błędu jest ok. 1/2000.

Czy ktoś już wcześniej natknął się na ten błąd i analizował sprawę? Nie znalazłem na necie nic w tym temacie.

A8CAS - narzędzie do 100% archiwizacji kaset Atari

2

Wydaje mi się, że ktoś pisał tu na forum o tym, że procedura obliczania baudrate ma błędy i jej poprawienie polepsza stabilność transmisji. Ale nie umiem znaleźć tego posta.

KMK
? HEX$(6670358)

3

Krótki napisał/a:

prawdopodobieństwo błędu jest ok. 1/2000.

Rozumiem, że ta procedura jest wykonywana dla każdego bloku? A że bloków jest zwykle rzędu 100, to przez ten błąd 1 z 20 odczytów pliku się nie udaje?

https://www.youtube.com/watch?v=jofNR_WkoCE

4

Tak.

A8CAS - narzędzie do 100% archiwizacji kaset Atari

5

Nooooo.... z tym prawdopodobieństwem to tak pi x oko. Tak naprawdę to chyba wszystko zależy od poziomu szczęścia osobistego ;). Jak ktoś się chce zmierzyć z własnym szczęściem, to proponuję zagrać w nową grę p.t. "Klątwa magnetofonu". Gra wykorzystuje opisaną powyżej właściwość 8-bitowych komputerów Atari (na marginesie - trudno mi uwierzyć, że ta przypadłość nie była wcześniej wykryta, ale też nigdy o niej nie słyszałem, zawsze narzekało się na jakość magnetofonów).

Gra jest trudna, ale wciągająca, ma 10000 poziomów, a ponieważ za każdym razem przebieg rozgrywki jest inny, to grywalność też oceniam wysoko ;). Wytrwali otrzymują dodatkowy bonus w postaci niezwykłych, kolorowych efektów graficznych pojawiających się około poziomu 4100. Zadaniem gracza jest przejście wszystkich poziomów przy utracie jak najmnejszej liczby żyć. Celem ostatecznym jest jej zakończenie bez utraty żadnego życia. Obsługa jest bardzo prosta i nie wymaga dodatkowego komentarza.

Gra jest przeznaczona do uruchamiania wyłącznie z magnetofonu, całość mieści się na jednej stronie 60-minutowej kasety. Można grać na emulatorze, ale preferowane jest używanie prawdziwego sprzętu ze względu na możliwość wykorzystania pomocniczych elementów w rodzaju szczekającego psa czy brata słuchającego głośnej muzyki, klaskania i krzyków, na które to emulator jest całkowicie nieczuły ;).

Instrukcja ładowania i uruchamiania: uruchomić komputer (emulator) z włączonym interpreterem Basica (należy wyłączyć SIO-patch). Umieścić taśmę w magnetofonie (lub załadować plik cas), wcisnąć "Play", wczytać grę poleceniem "CLOAD" i uruchomić poleceniem "RUN". Przycisk "Play" magnetofonu w trakcie gry musi pozostać cały czas wciśnięty (kwestia sprawdzania zabezpieczeń przed kopiowaniem).

Oto przykładowy zrzut ekranu przedstawiający przebieg gry:
curseoft screenshot

Aby ściągnąć grę, kliknij tutaj: The Curse of a Tape Player

Życzę wielu godzin mile spędzonych podczas zabawy.

Notatka techniczna:
podstawową cześcią programu jest fragment procedury systemowej umieszczony w pierwszym listingu przytoczonym przez Krótkiego. Dokonałem tylko drobnych zmian, żeby inne zdarzenia w systemie nie powodowały skoków w nieprzewidziane miejsca oraz żeby podprogram można było wywoływać z Basica i odczytać wynik obliczonej prędkości transmisji. Prędkość nagrania jest ustawiona na 600 bodów. Prawidłowo obliczone wartości to 1470, 1459 lub 1481 (ta ostania bardzo rzadko), które pozwalają prawidłowo ustawić generatory Pokeya. Liczby spoza zakresu 1400-1500 oznaczają ujawnienie się błędu procedury obliczającej prędkość (pojawia się tam 8258 lub 24680). Jak ktoś nie chce nagrywać testu na taśmę, można z powodzeniem wykorzystać np. AspeQt, tyle że traci się dodatkową losowość wprowadzaną przez magnetofon. A całość oczywiście ma na celu weryfikację, że bug w OS powoduje losowe błędy odczytu.

6 Ostatnio edytowany przez uicr0Bee (2011-08-28 17:59:22)

Nie to żebym był fanem taśmowych nośników zapisu danych o dostępie sekwencyjnym ;) ale z czystej ciekawości fajnie byłoby przekonać się na ile poprawiona procedura zmniejszyłaby w praktyce liczbę błędów. Czy da się zrobić patcha i podmienić ROM z OSem w gołej atarce albo takiej z rozszerzeniem typu 4OS?

<-- Kontakt przez "E-mail" gdyż albowiem moja skrzynka "PW" jest pełna i zaprawdę nie mam czego usunąć.

--== Kup Pan/i dyskietkę http://www.atari.org.pl/forum/viewtopic.php?id=18887 ==--

7

A ten bug w OS można poprawić?

8 Ostatnio edytowany przez FUJI (2011-08-28 19:28:42)

Problem jest przede wszystkim tu:

; Zapisz aktualne VCOUNT i RTCLOK+2 w TIMER1, TIMER1+1
        LDX     VCOUNT          ;vertical line counter
        LDY     RTCLOK+2        ;low byte of VBLANK clock

Gdyby pomiędzy tymi dwoma instrukcjami były inne, których wykonanie zajmie minimum 12 cykli maszynowych, błąd powinien zniknąć. Sądzę, że poprzesuwanie instrukcji tak:

; Zapisz aktualne VCOUNT i RTCLOK+2 w TIMER1, TIMER1+1
        LDX     VCOUNT          ;vertical line counter
        STX     TIMER1
        STA     SAVIO           ;save serial data in
        LDX     #1
        STX     TEMP3           ;set mode flag???
        LDY     RTCLOK+2        ;low byte of VBLANK clock
        STY     TIMER1+1        ;save initial timer value
        LDY     #10             ;10 bits

mogło by pomóc. Pomiędzy "LDX VCOUNT" i "LDY RTCLOK+2" było by 4+4+2+4=14 cykli, a raczej niczego się nie popsuje.

W sumie nie problem sprawdzić....

Edit:
Efekt jest jakby połowiczny, zamiast dwóch różnych błędnych wartości dostaję teraz tylko jedną (8258), więc jak można było podejrzewać, chyba trzeba by też coś zrobić z tym:

; Po 10 zmianach sygnału, zapamiętaj aktualne VCOUNT i RTCLOK+2
        LDA     VCOUNT          ;???
        LDY     RTCLOK+2        ;???

Ale to już nie dzisiaj.

9 Ostatnio edytowany przez Krótki (2011-11-29 11:14:08)

uicr0Bee napisał/a:

ale z czystej ciekawości fajnie byłoby przekonać się na ile poprawiona procedura zmniejszyłaby w praktyce liczbę błędów

Niewiele by to zmieniło. Błąd występuje raz na parę tysięcy rekordów, i objawia się tym, że dobrej jakości taśma, która prawie zawsze wgrywa się dobrze, z prawdopodobieństwem jak jeden do kilkunastu "wysypuje się" w losowym miejscu. Jedynym efektem poprawki byłoby ukojenie nerwów :-) Natomiast jak masz nagranie kiepskiej jakości, które nie wgrywa się nigdy lub prawie nigdy, to i poprawka nie pomoże.

EDIT:

FUJI napisał/a:

Gdyby pomiędzy tymi dwoma instrukcjami były inne, których wykonanie zajmie minimum 12 cykli maszynowych, błąd powinien zniknąć. Sądzę, że poprzesuwanie instrukcji tak (...) mogło by pomóc. Pomiędzy "LDX VCOUNT" i "LDY RTCLOK+2" było by 4+4+2+4=14 cykli, a raczej niczego się nie popsuje.

Pomiędzy odczytem VCOUNT (ostatni cykl LDX VCOUNT) a pierwszym cyklem instrukcji LDY RTCLOK+2 jest 14 cykli, czyli może dojść do, niezwykle rzadkiej, przeciwnej sytuacji: odczyt z VCOUNT wartości $7B oraz odczyt RTCLOK+2 już po obsłużeniu VBL:

247,106        LDX     VCOUNT          ;w 4. cyklu mamy cykl 109, więc odczytane jest $7B
247,110        STX     TIMER1
248,  0        STA     SAVIO
248,  4        LDX     #1
248,  6        STX     TEMP3
248, 10        ; VBL
???,???      LDY     RTCLOK+2        ;wykona się dopiero po VBL

Pomiędzy LDX VCOUNT a LDY RTCLOK+2 powinno być dokładnie 12 cykli odstępu:

; Sytuacja: odczyt VCOUNT w cyklu 109 lub wcześniej
247,106        LDX     VCOUNT          ;$7B
247,110        ; 12 cykli mija
248,  8      LDY     RTCLOK+2        ;przed VBL. Odstęp większy niż 12 spowoduje wykonanie po VBL (źle).

; Sytuacja: odczyt VCOUNT w cyklu 110 lub później
247,107        LDX     VCOUNT          ;$7C
247,111        ; 12 cykli mija
248,  9        ; VBL
???,???      LDY     RTCLOK+2        ;po VBL. Odstęp mniejszy niż 12 spowoduje wykonanie przed VBL (źle).

Oczywiście pod warunkiem, że rzeczywiście ANTIC nie kradnie żadnego z tych cykli (fizycznie nie sprawdzałem).
EDIT: VCOUNT jest zwiększany w 110 cyklu, nie w 111.

A8CAS - narzędzie do 100% archiwizacji kaset Atari

10

Masz całkowitą rację. Chyba nie tędy droga. przydało by się wcisnąć kilka dodatkowych instrukcji, tylko najpierw miejsce trzeba by na nie znaleźć...

Krótki napisał/a:

Niewiele by to zmieniło.

Oj, pod emulatorem by wiele zmieniło :P.

11

gdybym wczesniej wiedzial... myslalem ze to zle oko kolegi komodziarza a to zwykly bug w atari os.

brawo Krótki i FUJI !!!

http://atari.pl/hsc/ad.php?i=1.

12

A czy to przypadkiem nie jest poprawka tego? (Nie sprawdzałem, za słaby jestem.)
http://wiki.strotmann.de/wiki/Wiki.jsp? … %20Handler

13 Ostatnio edytowany przez Krótki (2011-09-07 01:58:51)

Nie. Ten program robi coś innego - poprawia 2 niedogodności procedury OPEN urządzenia C:
1. Przed rozpoczęciem zapisu opróżnia rejestr SEROUT, aby uniknąć ewentualnych śmieci na początku zapisu sygnału pilotującego.
2. W przypadku zapisu z długimi przerwami, po powrocie z OPEN silnik magnetofonu jest zatrzymywany. (Normalnie nie jest.)

A8CAS - narzędzie do 100% archiwizacji kaset Atari

14

A czy to można upchnąć w rom - spaczować go, czy się nie da?

15

Co sie nie da, wszystko sie da.

Tylko pewnie trzebaby zoptymalizować kilka innych procedurek, żeby zwolnić trochę miejsca.

A8CAS - narzędzie do 100% archiwizacji kaset Atari

16 Ostatnio edytowany przez Krótki (2011-11-29 11:15:05)

POPRAWKA: Phaeron przyznał się, że w Altirra HW Reference Manual jest błąd i VCOUNT jest zwiększane w 110. cyklu skanlinii, a nie w 111. Przeedytowałem poprzedniego posta zgodnie z powyższym.

A8CAS - narzędzie do 100% archiwizacji kaset Atari

17

Ale jazda. Czyli ja robiąc gry dla Mirage "w długim bloku" nieświadomie ominąłem (zminimalizowałem) ten bug.

A jeszcze jedno. Jak już przetestowaliście, to czy jest brane pod uwagę pojawienie się w VCOUNT wartości 156 na króciutko? (za Altirra Hardware Reference Manual)