Artykuły

    Kurs Assemblera cz. 5

    Doszły mnie słuchy ze poprzednia cześć kursu była dla Was niezbyt zrozumiała, i od kogo musze sie o tym dowiadywać? Przecież jak macie jakiekolwiek pytania są od tego komentarze na samym dole tego arta. O, o tam na samym dole.

    Przypomnijmy co było do zapamiętania w 4 rozdziale naszej historii o programowaniu 6502. Był nim ANTIC, układ odpowiedzialny za wyświetlanie grafiki. Macie zapamiętać trzy rejestry: $d400(DMACTL), $d402, $d403(DLPTR) i to wszystko.

    DMACTL-$d400, jego cień to bajt 559 w pamięci atarka. Po co nam DMACTL ? Po to, aby `powiedzieć` ANTIC`owi że chcemy obraz o szerokości normalnej, wąskiej i fullscreen(szeroki), że wogóle nie chcemy obrazu dzięki czemu mamy całą moc procka na nasze dziwne programiki np. player MOD, itp. Po to nam właśnie rejestr DMACTL. Przykład:

                  bit 5, DMA dla programu ANTIC-a (1 = włączony)
                   |    
           lda #%00100010
           sta 559     ^^
                       bit 1 i 0 określają szerokość ekranu, lub jego brak
                           -----
                           0   0 = brak obrazu
                           0   1 = obraz wąski (192 punkty)
                           1   0 = obraz normalny (320 punkty)
                           1   1 = obraz szeroki (384 punkty)
    
    

    bity 6 i 7 nie są w ogóle wykorzystane przez cokolwiek, są zbędne i w ogóle po co nam :) bity 2, 3, 4 dotyczą spritów i im podobnych, zostaną opisane w dalszej części tego kursu.

    Dlaczego napisałem `sta 559`, a nie `sta $d400`, ponieważ standardowe przerwanie VBL (co 1/50 sekundy) przepisuje wartości z cieni do odpowiadających im rejestrów. VBL już zatroszczy się aby wartość z 559 wprowadzic do $d400. Przykład:

              lda 559
              sta $d400
    

    OK, DMACTL mamy już w jednym paluszku, teraz DLPTR. Przez DLPTR rozumiemy rejestr 2-u bajtowy, jak już wyżej wspominałem: $d402 i $d403, cieniem są komórki 560 i 561. W tych 2-óch bajtach zapiszemy adres programu dla ANTIC-a. ANTIC jest przecież osobnym układem zajmującym się tworzeniem obrazu na podstawie specjalnego programu, programu którego autorami możemy być my. Przedtem jednak musimy znać jego składnie, a składnie tą poznaliśmy w części 4-ej kursu. Przykład:

    -*-
    obraz equ $bc40
    
              lda <program_dla_antica
              sta 560
              lda >program_dla_antica
              sta 561
              rts
    
    program_dla_antica dta b($70,$70,$70)                ;3x po 8-m pustych linii
                       dta b($42),a(obraz)               ;zawsze musi być przynajmniej jeden rozkaz LMS, 
    ;czyli załaduj licznik ;pamięci obrazu wartością 2-u bajtową, w naszym ;przykładzie będzie to ;a(obraz) i zawsze jest to wartość 2-bajtowa!! dta b($f,$f,$f,$f,$f,$f,$f,$f) ;tutaj kod konkretnego trybu graficzngo, ;każdy taki bajt odpowiada ;jednej linii obrazu, w naszym przykładzie $f ;czyli tryb 8 Basica dta b($41),a(program_dla_antica) ;na końcu każdego Anticowego programu musi być ;jeden z dwóch możliwych ;rozkazów: JVB = $41 lub JMP = $01 ;w naszym przykładzie jest to $41 i jest to ;w większości używany rozkaz ;powoduje on skok pod adres zapisany w 2-óch ;następnych bajtach czyli ;a(program_dla_antica) wtedy gdy wystąpi pełna ;synchronizacja VBLK czyli ;wiązka elektronów tworzących obraz dotrze do ;prawej dolnej krawędzi kineskopu -*-

    Teraz podam jaki kod ANTIC-a odpowiada trybowi graficznemu Basica(OS), bo tego zabrakło w części 4-ej.

    Tryby graficzne:

               Kod trybu ANTIC-a    Tryb Basica (OS)
                     $08                  $03
                     $09                  $04
                     $0A                  $05
                     $0B                  $06
                     $0C                  $0E
                     $0D                  $07   - to ten tryb od Crumbles Crisis :)
                     $0E                  $0F   - ten musicie znać
                     $0F                  $08   - czyli Hi-Res
    
    

    Z trybem ANTICA $0F związany jest pewien bajer w postaci rejestru GTIACTL ($d01b, cień = 623). Bity 7 i 6 GTIACTL odpowiadają właśnie za te bajery:

              bit 7     bit6
              -----     -----
                0         0      - bez zmian, tryb 8 Basic-a (OS)
                0         1      - tryb 9 Basic-a (OS), czyli 16 odcieni szarości
                1         0      - tryb 10 Basic-a (OS), czyli 9 różnych kolorów (704-712)
                1         1      - tryb 11 Basic-a (OS), czyli 16 kolorów 
                                   o stopniu jasności wg. wartości bajtu 712
    Przykład:
                lda #%01000000
                sta 623           ;tryb 9 Basic-a (OS)
    
    Tryby znakowe:
    
              Kod trybu ANTIC-a    Tryb Basica (OS)
                   $02                  $00   - czyli ten najbardziej standardowy :)
                   $03                  brak  - znak ma wysokość 10 linii
                   $04                  $0C   - wykorzystywany w grach np. Misja, Fred
                   $05                  $0D
                   $06                  $01
                   $07                  $02
    
    

    To była powtórka z ANTIC-a :). Zapoznaliśmy się już z ważniejszymi elementami programowania Atari XE/XL, została nam jeszcze muzyka, sprity, operacje ze stacją dysków oraz przerwania. Te ostatnie są najważniejsze.

    P R Z E R W A N I A

    Skoro są najważniejsze to od nich zaczniemy. Mamy przerwania maskowalne NMI i niemaskowalne IRQ. Maskowalne oznacza, że mogą zostać wyłączne jeśli zajdzie taka potrzeba. IRQ natomiast są tak ważne, że ich zatrzymanie grozi katastrofą.

    Tak na prawdę to IRQ mają najwyższy piorytet i jak ruszają wszyscy muszą czekać aż sie skończą. Wszelkie operacje In-Out ze stacją dysków czy magnetofonem zaprzęgają do działania właśnie IRQ oraz ... Pokey. Swojego czasu w magazynie Energy, panowie z TQA zamieścili własną obsługę przerwań IRQ, dzięki czemu można podczas odczytu ze stacji odgrywać czasochłonne msx na samplach i wyświetlać inne fx-y.

    Najczęściej wykorzystywać będziemy przerwanie VBL i DLI, ich wektory czyli 2-bajtowe adresy mieszczą się na 2-iej stronie pamięci (strona to już chyba wiadomo że = $100 bajtom). Jest tak gdy OS jest włączony !

    	Wektor DLI - ($200) - adres składany jest z zazwartości $200 i $201
    	Wektor VBL - ($224) - identycznie jak w/w
    

    Taki OS pragnie sobie np. zrealizować przerwanie DLI, bo jakiś użytkownik wstawił rozkaz DLI do programu ANTIC-a (ustawiony bit 7 w rozkazie, np. dta b($f+$80)) i pozwolił na przerwania NMI wpisując wartość $c0 do NMIEN($d40e), normalnie jest tam wartość $40. Podsumowując:

    -*-
    obraz equ $bc40
    
        lda <ant                ;młodszy bajt adresu programu ANTIC-a
        sta 560                 ;do młodszego bajtu cienia DLPTR(560), czyli znajdzie sie to potem w $d402
        lda >ant                ;starszy bajt adresu programu ANTIC-a
        sta 561                 ;do starszego bajtu cienia DLPTR(561), czyli znajdzie sie to potem w $d403
    
        lda #$c0                ;wartość $c0
        sta $d40e               ;do NMIEN
        rts
    
    ant dta b($70,$70)          ;2 x 8 pustych linii
        dta b($70+$80)          ;8 pustych linii z przerwaniem DLI, bo `+$80`
        dta b($42),a(obraz)
        dta b(2,2,2,2,2,2,2,2,2,2,2,2)
        dta b($41),a(ant)
    
    -*-
    

    I co ? I nic ! Bo gdzie jest nasze przerwanie DLI ? Tam gdzie wskazuje na nie wektor :) A wektor wskazuje na RTI domyślnie, czyli skończ przerwanie. Musimy więc sami napisać nową obsługę DLI i zapisać adres tej procedurki obsługi do wektora. Przed modyfikacją jakiegokolwiek przerwania musimy poczekać na synchronizację VBLK, czyli:

       lda 20    lub    lda $d40b
       cmp 20           bne *-3
       beq *-2
    

    Nasza nowa procedurka obsługi DLI może wyglądać tak:

    dli1 pha        ;A (akumulator) na stos
        tya         ;rej.Y do A 
        pha         ;A na stos
    
        ldy #100
    l0  tya
        sta $d40a   ;WSYNC znacznik synchronzacji poziomej, CPU czeka aż ANTIC skończy rysować linie obrazu
        sta $d01a
        dey
        bne l0
    
        pla         ;zdejm ze stosu do A
        tay         ;z A do Y
        pla         ;zdejm ze stosu do A
        rti         ;skoncz przerwanie, to taki odpowiednik RTS
    

    Dlaczego ładujemy na stos A i Y, ponieważ gdy następuje dowolne przerwanie, aktualnie wykonywany program zostaje wstrzymany a sterowanie jest przekazywane do procedury obslugujacej przerwanie. Gdy przerwanie sie kończy nasz wstrzymany program jest kontynuowany, a więc wszystkie rejestry muszą być niezmienione, muszą zawierać te same wartości co przed przerwaniem inaczej nastąpiłby kogel-model ;). Możemy też tak:

    dli2 sta a+1
        sty y+1
    
        ldy #100
    l0  tya
        sta $d40a
        sta $d01a
        dey
        bne l0
    
    a   lda #0
    y   ldy #0
        rti
    

    Wynik będzie ten sam co w dli1, inaczej tylko zapamiętujemy A i Y. Zbierając wszystko do kupy, otrzymujemy:

    -*-
    obraz equ $bc40
    
        opt h+
        org $8000    
     
        lda <ant    ;adres programu ANTICA
        sta 560
        lda >ant
        sta 561
    
        lda 20      ;czekamy na synchro :)
        cmp 20
        beq *-2
    
        lda <dli    ;mlodszy bajt naszego nowego DLI
        sta $200
        lda >dli    ;starszy bajt naszego nowego DLI
        sta $201
        lda #$c0    ;pozwalamy na przerwania DLI
        sta $d40e
        rts
    
    dli pha         ;A (akumulator) na stos
        tya         ;rej.Y do A 
        pha         ;A na stos
    
        ldy #100
    l0  tya
        sta $d40a
        sta $d01a
        dey
        bne l0
    
        pla         ;zdejm ze stosu do A
        tay         ;z A do Y
        pla         ;zdejm ze stosu do A
        rti         ;skoncz przerwanie
    
    ant dta b($70,$70)                  ;2 x 8 pustych linii
        dta b($70+$80)                  ;8 pustych linii z przerwaniem DLI, bo `+$80`
        dta b($42),a(obraz)             ;tutaj już wszyscy wiedzą co i jak itd
        dta b(2,2,2,2,2,2,2,2,2,2,2,2)
        dta b($41),a(ant)
    -*-
    

    To był przykład własnej obsługi DLI przy włączonym OS. Teraz koniec z tym, jeśli chcecie napisać demo zapomnijcie o OS. Sami sobie napiszemy wszystko :D

    PRZERWANIA BEZ OS

    Poprzedni paragraf potraktujcie jako ciekawostkę, osobiście nie pamiętam ile lat temu skorzystałem z OS w celu modyfikacji przerwań. Po prostu pisząc własną obsługę przerwań masz pełną kontrolę nad kompem i pamięcią. Nie zajmujemy się tu szkoleniem koderów użytków tylko koderów `wypaśnych dem` :). W progach użytkowych OS się przydaje, przedewszystkim do odczytu zapisu danych ze stacji. Możecie jednak posłużyć sie DOS-em jak to jest w przypadku DELTA Trackera.

    Demo, demo, demo nie obejdzie sie bez własnej procedury obsługi przerwań. System zostaje wyłączony, dzięki czemu zyskujemy pamięć $c000-$cfff, $d800-$fff0. "OS z wozu, CPU lżej" :)

    Powiedzmy sobie prawde o przerwaniach. Gdzieś w pamięci musi być stały adres procedur obsługi przerwań: IRQ, NMI, RESET. Dlaczego ? Czy zastanawialiście się kiedyś gdy włączacie Atari skąd CPU6502 wie gdzie znajdują się programy przerwań. Jest bowiem w pamięci takie miejsce, które zna 6502, wpisano mu je na stałe do jego krzemowej struktury. Oto one:

             ($FFFA) - NMIVEC
             ($FFFC) - RESETVEC
             ($FFFE) - IRQVEC
    

    My zajmiemy sie tylko NMI bo są fajne, ładne, sprawne i wogóle reszta nam sie nie przyda. Po prostu wyłączymy IRQ i po sprawie.

    Z DLI możemy zmienić obraz w konkretnych liniach, np. kolor, pozycja spritów. Nie zmieścimy tyle co na VBL, ale wystarczy aby na ekranie znalazło się 256 kolorów, zaczął działać TIP itp. Natomiast w trakcie VBL możemy wykonać nawet do 20000 cykli zegara. Swojego czasu ludziska prześcigali się co też można zmieścic w 1 ramce, czyli w czasie wykonywania VBL-a. !!! Przykład, który jest poniżej należy traktować jako wzorcowe rozwiązanie, wszyscy mają wykuć to na `blache`. !!!

    -*-
     opt h+
     org $2000  ;adres uruchomienia naszego extra programu, może być wg Waszego widzi-misie
    
     lda 20     ;czekamy ramke zanim zaczniemy szaleć
     cmp 20
     beq *-2
    
     sei        ;wyłączamy nieodwołalnie IRQ
     lda #0        
     sta $d40e  ;wyłączamy NMI ($d40e = $00), tak na chwilę, na czas zmiany wektorów przerwań
     lda #$fe   
     sta $d301  ;wyłączamy OS ($d301 = $fe), możemy dzięki temu korzystać z pamięci $c000-$cfff, $d800-$fff0
    
                ;i w tym momencie niejako działa już sam CPU, wszystko inne zamarło :)
    
     ldx <nmi   ;nasz nowy adres programu NMI
     ldy >nmi
     stx $fffa
     sty $fffa+1
    
     ...        ;tutaj nasze jakieś inne wartości do incjacji
     ...
     ...
    
     lda #$40
     sta $d40e  ;włączamy NMI ($d40e = $40, tylko VBL), ($d40e = $c0, VBL oraz DLI)
     
     ...        ;tutaj nasz dalszy program, może jakieś wektorki kto wie :)
     ...
     ...
    
    
    *-------------
    * Obsługa NMI
    *-------------
    nmi	bit $d40f ;NMIST - rejestr statusu przerwań NMI
    	    bpl _vbl
    dliv	jmp dli   ;skok do obsługi DLI
    
    _vbl	pha       ;tutaj nasze VBL, zapamietujemy rejestry A,Y,X na stosie
            tya
            pha
    	    txa
    	    pha
    
    	    inc 20    ;licznik zwiekszany co ramke
    
    	    lda 756   ;adres zestawu znaków
    	    sta $d409
    	    lda 560   ;< adres programu ANTIC-a
    	    sta $d402
    	    lda 561   ;> adres programu ANTIC-a
    	    sta $d403
    	    lda 559   ;DMACTLS
    	    sta $d400
    	    lda 623   ;GTICTLS
    	    sta $d01b
    	
            ldx #8
    col	    lda 704,x    ;przepisujemy kolory z cieni do ich rejestrow właściwych
    	    sta $d012,x
    	    dex
    	    bpl col
    	
    	    pla        ;zdejmujemy ze stosu wartości rejestrów X,Y,A
    	    tax        ;zdejmujemy je w odwrotnej kolejności jak je tam kładliśmy
    	    pla
            tay
            pla
    	    rti
    
    dli	rti           ;tutaj nasze DLI, pamiętajcie żeby zostawiać rejestry niezmienione 
                      ;po zakończeniu przerwania
    -*-
    

    Oczywiście możecie zmienić standardowe komórki cieni na swoje własne, jeśli czujecie się na siłach. Może będziecie potrzebowali akurat strony 2 pamięci. Przykład zastosowania własnej obsługi przerwań i wyłączenia OS. Szybkie tworzenie grafiki (np. rysowanie linii) może potrzebować aby pamięć obrazu zaczynała się od $0000. Wtedy organizujemy program ANTIC-a w ten sposób, że każda linia obrazu zaczyna się od nowej strony pamięci. Przykład:

    ant dta b($70,$70,$70)            ;odpowiednikiem tego jest d`ppp`
        dta b($4f),a($0000)           ;0 - page
        dta b($4f),a($0100)           ;1 - page
        dta b($4f),a($0200)           ;itd
        dta b($4f),a($0300)
        dta b($4f),a($0400)
        dta b($4f),a($0500)
        dta b($4f),a($0600)
        dta b($4f),a($0700)
        dta b($4f),a($0800)
        ...                           ;itd
        ...
        dta b($41),a(ant)
    

    Zaledwie 40 bajtów będzie wykorzystane z każdej strony pamięci, resztę możecie przeznaczyc na texture czy inną grafikę. Nie obawiajcie się, że coś stanie się stosowi (strona 1 = $100), on zapisuje dane od $1ff w dół do $100, a my od $100 do $127 w tym konkretnym przypadku. Jeśli zorganizujecie inaczej obraz, będziecie musieli wyliczyć adres każdej linii obrazu, żeby móc postawić tam pixel. A w/w przykładzie nie trzeba:

    scr  equ $80
    
         jsr init          ;przygotowanie tablicy `pozycjaX`
         ldx #37           ;pozycja X
         ldy #59           ;pozycja Y
         jsr plot          ;wywołanie podprocedurki PLOT
    lop  jmp lop           ;pętl się w nieskończoność
    
    plot sty scr+1         ;3 cykle
         ldy pozycjaX,x    ;4 cykle ???
         lda (scr),y       ;5 cykli
         ora kolor,x       ;4 cykle
         sta (scr),y       ;5 cykli
         rts               ;6 cykli = razem 27 cykli
    
    init ldy #0
    in_  tya
         lsr @             ;dzielimy przez 8
         lsr @             ;
         lsr @             ;
         sta pozycjaX,y
         iny
         bne in_
         rts
    
         org $a400
    kolor     :32 dta b(%00000001,%00000010,%00000100,%00001000,%00010000,%00100000,%01000000,%10000000)
    pozycjaX  org *+256
    

    Tablice `pozycjaX` oraz `kolor` mają wielkość 256bajtów i muszą znajdować sie na początku strony, tzn. młodszy bajt = $00. Całość zobaczycie w załączniku z przykładami (PLOT.ASM), tak jak i inne źródłowki pokazane tutaj. Ten programik potrafi w 1 ramce wyświetlić do 606 pixli dla wąskiego obrazu i 596 dla normalnego. Inne rekordy typu 1024pixli itp polegają już na kopiowaniu. Nasz program można też przyspieszyć, umieszczając główną pętlę i zmienne na stronie $00. Da nam to 631 pixli w ramce (PLOT2.ASM) dla wąskiego ekranu a 621 dla normalnego. 1 cykl zaoszczędziliśmy m.in. w ten sposób (PLOT2.ASM):

                           
         org GDZIES_NA_0_PAGE   
    
         ldx #47           ;pozycja X
         lda #55           ;pozycja Y
         sta scr+2
      
    plot ldy pozycjaX,x    ;4 cykle ???
    scr  lda $ff00,y       ;4 cykli - tu jest nasz 1-cyklowy zysk
         ora kolor,x       ;4 cykle
         sta (scr+1),y     ;5 cykli
    

    P O K E Y

    A teraz Pokey (Potentiometr and Keyboard chip) i jego przewyższające wszystkie 8-bitowe układy, możliwosci dźwiękowe. Jeśli Pokey nie gra tak jak Sid, to tylko dlatego że nie napisano jeszcze odpowiedniego programu ;).

    Co nam daje Pokey? Daje nam 4 niezależne generatory dźwięku, sterowane przez dziewięc rejestrów (tylko do zapisu). Oprócz tego generatory służą jako sprzętowe liczniki i mogą wywoływać przerwania IRQ.

    Ponieważ Pokey wykorzystywany jest do obsługi klawiatury i łącza szeregowego przed użyciem jego dźwiękowych możliwości należy go zaincjować. Jeślibyśmy go nie zaincjowali zawierał by jakieś śmieci z transmisji in-out. Jak incjujemy ? Wpisujemy do rejstru AUDCTL ($d208 - Audio Control) wartość 0, natomiast do SKCTL ($d20f) wartość 3.

    	lda #0
    	sta $d208
    	lda #3
    	sta $d20f
    

    Teraz możemy grać :). Do tego celu służą po dwa rejestry na kanał. Pierwszy AUDF to rejestr częstotliwości. Drugi AUDC odpowiada za głośność i zniekształcenia. Oczywiście dla kanału nr 1 mamy odpowiednio AUDF1, AUDC1, dla kanału nr 2 mamy AUDF2, AUDC2 itd. Jak to działa, że wogóle działa. Rejestr częstotliwości AUDF jest wykorzystywany jako dzielnik impulsów. POKEY zlicza impulsy sygnału wejściowego doprowadzonego do generatora i przesyła impuls do wyjścia, gdy stan licznika jest zgodny z zawartością rejestru AUDF zwiększoną o jeden. Przy wartości 0 w AUDF przepuszczany jest każdy impuls wejściowy, a przy wartości np. 3 - co czwarty. Dzielnik ma więc zakres od 1 do 256. Ponieważ sygnał wyjściowy składa się z pojedyńczych impulsów, to na końcu jest dzielony jeszcze przez 2 przy pomocy przerzutnika. Otrzymuje się wtedy sygnał o wypełnieniu 1:1 (stosunek czasu trwania impulsu do czasu trwania przerwy między impulsami). Ta ostatnia operacja jest konieczna dla uzyskania właściwej barwy dźwięku.

    Nieco bardziej skomplikowane jest działanie rejestrów sterujących generatorami - AUDC. Poszczególne bity tych rejestrów mają różne funkcje. Bity 0-3 określają natężenie dźwięku. Skala siły głosu jest więc 16stopniowa, 0-15. Bit 4 wyłącza dzielnik częstotliwości. Powoduje to pojawienie się na wyjściu stałego napięcia o wartości określonej przez bity 0-3, dzięki czemu mamy zajebistej jakości 4bitowe sample :). Można wtedy stworzyć dowolny przebieg fali dźwiękowej. Normalny dźwięk wytwarzany przez komputer ma przebieg prostokątny, jeśli jednak zaczniemy wpisywać do AUDC przy włączonym 4-tym bicie wartości od 0-15 i od 15-0 uzyskamy przebieg trojkątny, taki jaki tworzą instrumenty dęte blaszane.

            lda value0..15   ;jakaś wartość z zakresu 0..15
            ora #%00010000   ;ustaw bit 4
            sta audc1..4     ;zapisz do jednego z AUDC, od 1 do 4
    
    lub
            lda #%00010101   ;bezpośrednio mamy już przygotowaną wartość z ustawionym bitem 4, 
                             ;jak w Inertii lub ProTracker-ze
            sta audc1..4
    

    Pozostałe bity AUDC kontrolują zniekształcenia dźwięku. Układ POKEY zawiera jeszcze rejestry przesuwające pracujące z częstotliwością zegara systemu (1.79MHz w systemie NTSC i 2.217MHz w systemie PAL - "ciekawe, no ale skoro pisze tak Wojtek Zientara, to trzeba się z nim zgodzić :)") W/w rejestry przesuwające mają długość 4, 5 i 17 bitów, przy czym rejestr 17bitowy można przełączyć na 9bitowy. Impulsy z generatora, po przejściu przez dzielnik częstotliwości, lecz przed podziałem przez 2, są doprowadzane na wejście wybranego rejestru. Pojawiają się na wyjściu z rejestru w tej samej kolejności (rejestr przesuwający działa jak kolejka w sklepie). Nie byłoby w tym nic nadzwyczajnego, gdyby nie dodatkowa operacja. Bity pobierane są nie tylko z wyjścia, lecz także ze środka rejestru przesuwającego. Bity te poddawane są operacji logicznej NOR i ponownie przesyłane do wyjścia rejestru. Powoduje to uzyskanie zakłóceń pseudolosowych, których powtarzalność zależy od długości rejestru.

    Po tym wyjaśnieniu będzie łatwiej zrozumieć działanie trzech najstarszych bitów (5-7) rejestru AUDC. Służą one do wyboru rejestru przesuwającego, który będzie użyty do zniekształcenia dźwięku. Kolejne kombinacje tych bitów mają następujące znaczenie:

    		bity 000 - rejestr 5bitowy i 17bitowy
    		bity 001 - rejestr 5bitowy
    		bity 010 - rejestr 5bitowy i 4bitowy
    		bity 011 - rejestr 5bitowy
    		bity 100 - rejestr 17bitowy
    		bity 101 - bez rejestru przesuwającego
    		bity 110 - rejestr 4bitowy
    		bity 111 - bez rejestru przesuwającego
    

    Pomimo użycia 3bitów kombinacji jest tylko 6, gdyż pary 001 i 011 oraz 101 i 111 są identyczne. Ostatni rejestr POKEY-a, który opiszemy to AUDCTL ($d208) - steruje on jednocześnie wszystkimi generatorami. Jego użycie znacznie zwiększa możliwości dźwiękowe Atari. Poszczególne bity tego rejestru mają następujące znaczenie:

    Bit 0 służy do wyboru zegara bazowego, czyli źródła impulsów dla wszystkich generatorów. Normalnie zegar bazowy ma
          częstotliwość 64khz, a po ustawieniu bitu 0 jest przełączany na 15khz. Jeśli pozostałe parametry pozostaną
          niezmienione, to spowoduje to czterokrotne zmniejszenie częstotliwości wszystkich dźwięków.
    Bit 1 jego ustawienie włącza filtr górnoprzepustowy w generatorze 2. Filtr ten jest sterowany generatorem 4
           i powoduje,że generator 2 emituje tylko dźwięki o częstotliwościach wyższych od częstotliwości generatora 4.
    Bit 2 włącza analogiczny filtr górnoprzepustowy dla generatora 1 sterowany generatorem 3.
    Bit 3 gdy jest ustawiony, łączy dzielniki generatorów 3 i 4 w jeden dzielnik 16bitowy, który umożliwia bardziej 
          precyzyjną regulację częstotliwości. Poszerza to również zakres uzyskiwanych częstotliwości ze 125Hz-32kHz
           do 0.5Hz-32kHz, a po zmianie zegara bazowego przy pomocu bitu 5 na 16Hz-1MHz.
    Bit 4 łączy dzielniki 1 i 2 w jednen dzielnik 16bitowy analogocznie jak w/w bit3.
    Bit 5 gdy jest ustawiony przełącza zegar bazowy dla generatora 3 na częstotliwość 2.217MHz (wszystkie źródła 
          podają tuczęstotliwość 1.79MHz - jest to częstotliwość kwarcowego zegara systemu, ale w NTSC! - komputery 
          w wersji PAL mają zegar 2.217MHz). Przełączenie to powoduje zwiększenie częstotliwości ponad 30 razy.  
          Tak wysokiedźwięki nie nadają się do słuchania - wykorzystuje się tą możliwość prawie zawsze jednocześnie 
          z ustawieniem bitu3.
    Bit 6 przelącza zegar bazowy dla generatora 1 na częstotliwość 2.217MHz, podobnie jak w/w bit5
          (wszystkie podane tam uwagi odnoszą się także do tego bitu).
    Bit 7 przełącza 17bitowy rejestr przesuwający na rejestr 9bitowy. Pozwala to na uzyskanie dwóch dodatkowych 
          sposobówzniekształcenia dźwięku (dla bitów 5-7 w AUDC równych 000 lub 100).
    

    Ubocznym efektem działania generatorów dźwięku jest liczba pseudolosowa znajdująca się w rejestrze RANDOM ($d20a). Umieszczane jest tam osiem najstarszych bitów z 17bitowego rejestru przesuwającego.

    Przykładem wykorzystania możliwości POKEY-a są wszelkie trackery, jak pierwszy Chaos Music Composer (CMC), później DMC, który grał 2x na ramke, i najpopularniejszy Music Pro Tracker (MPT). Wywoływanie playera więcej niż 1raz na ramke powoduje że uzyskujemy inne brzmienia, inną barwę dźwięku. Theta Music Composer (TMC) właśnie oferuje taką możliwość wywołania playera więcej niż 1raz. Pozostałych programów jest tak wiele że ich nie wymienie, bo te w/w najczęsciej wykorzystuje demo-scena :).

    Delta COMPILER.ASM kompilujemy najpierw, potem DLTPLAY.ASM i możemy uruchomić DLTPLAY.OBX (wszystkie pliki w załączniku).

    S P R I T Y

    Sprity czyli po naszemu duszki to sprzętowo sterowana grafika przez układ GTIA i ANTIC, którą możemy nakładać na inne sprity, na grafikę oraz tło. Jeśli braknie nam spritów sprzętowych, a jest ich tylko 4 lub 5 sztuk musimy posiłkować się spritami programowymi. A że Atari to wypaśnie szybki sprzęcior nie ma z takimi spritami problemów ;).

    Jak już wspomniałem mamy 4 lub 5 sprity, 4 rzeczywiście od razu, a ten 5-y powstaje ze złożenia 4 pocisków. Pociski są 4-y razy węższe od sprita, czyli jaką szerokość ma sprite? Sprite ma szerokość 8pixli grafiki trybu 15Basica. Pocisk zaś szerokość 2pixli. Wystarczy nam to na postać bohatera, postać przeciwnika i ... zabrakło ;)

    Taki sprite ma 2 kolory, czyli opiszemy go za pomocą 0 i 1. Tam gdzie jest 0 mamy dziure, tam gdzie 1 nasz kolor. Jeśli ma dziure to przez tą dziure zobaczymy kolor tła, ponieważ sprite jest nad tłem. Przeważnie jest nad tłem, bo za tłem nie byłoby go widać :). Ale wszyscy chcą więcej kolorów, więc GTIAa da nam więcej kolorów, jeśli tylko ustawimy X bit w DMACTL. Po takiej operacji gdy nałożymy na siebie 2 sprity, tzn oba sprity maja tą samą pozycje poziomą i pionową uzyskamy 4 kolorowe sprity (to tak jak kładziesz sie na dziewczynie, razem macie więcej kolorów :>).

    Wiemy już co oferują nam sprity, podsumowując, (5spritow 2kolorowych) lub (4sprity 2kolorowe i 4pociski 2kolorowe) lub (2sprity 4kolorowe i 4 pociski). Z tym 5-tym jest zawsze więcej roboty. Szerokość to 8pixli dla sprita i 2pixle dla pocisku. Szerokość może być: pojedyńcza, podwójna lub potrójna (realizowana sprzętowo). Wysokość 256 linii w spritach jednoliniowych i 128 linii w spritach dwuliniowych. Za jedno i dwu liniowość odpowiada rejestr sprzętowy. Dostępem ANTIC-a do do pamięci ze spritami regulują bity 3-5 rejestru DMACTL:

    Bit 3 kontroluje dostęp ANTIC-a do obszaru pamięci dla pocisków. Gdy jest ustawiony, 
          to dane te są przepisywane z pamięci do rejestru GRAFM (Graphics For Missile).
    Bit 4 kontroluje dostęp ANTIC-a do obszaru pamięci dla graczy. Gdy jest ustawiony, to dane te są przepisywane
          z pamięci do rejestrów GRAFP0-3 (Graphics For Player 0-3).
    Bit 5 ustala rozdzielczość grafiki P/MG. Gdy jest skasowany, to dane P/MG są pobierane do pamięci podczas tworzenia
          co drugiej linii ekranu. Każdy pixel obiektu ma więc wysokość dwóch linii ekranu. Po ustawieniu bitu 5 dane są
          odczytywane przy tworzeniu każdej linii, więc pixel ma wysokość jednej linii ekranu. 
          To jest właśnie rozdzielczość dwuliniowa lub jednoliniowa.
    

    Bazowy adres pamięci graczy i pocisków jest umieszczany w rejestrze PMBASE (Player/Missile BASE - $d407). PMBASE musi koniecznie wskazywać początek bloku 1kb przy rozdzielczości dwuliniowej i 2kb przy rozdzielczości jednoliniowej. Dane poszczególnych obiektów muszą być umieszczone w pamięci następująco:

                      rozdz. dwuliniowa
            pociski   PMBASE+$0180 - PMBASE+$01ff
            gracz 0   PMBASE+$0200 - PMBASE+$027f
            gracz 1   PMBASE+$0280 - PMBASE+$02ff
            gracz 2   PMBASE+$0300 - PMBASE+$037f
            gracz 3   PMBASE+$0380 - PMBASE+$03ff
    
                      rozdz. jednoliniowa
            pociski   PMBASE+$0300 - PMBASE+$03ff
            gracz 0   PMBASE+$0400 - PMBASE+$04ff
            gracz 1   PMBASE+$0500 - PMBASE+$05ff
            gracz 2   PMBASE+$0600 - PMBASE+$06ff
            gracz 3   PMBASE+$0700 - PMBASE+$07ff
    

    Obiekty mogą być też tworzone na ekranie bez pośrednictwa ANTIC-a i bez korzystania z opisanego wyżej obszaru pamięci. Trzeba w tym celu wpisać bajt wzoru bezpośrednio do rejestru grafiki GRAFM (pociski) lub GRAFP (gracze). Każdy rejestr GRAFP odpowiada bajtowi danych gracza, zaś w rejestrze GRAFM każdemu pociskowi odpowiadają dwa bity. Umieszczone w ten sposób dane będą wyświetlane na całej wysokości ekranu, otrzymamy więc pionowy pas. Zmienić zawartośc rejestrów grafiki tak aby uzyskać widoczny efekt na ekranie możemy tylko podczas tworzenia obrazu, czyli przy pomocy przerwania DLI.

    Niezależnie od sposobu zapisywania danych w rejestrach grafiki (bezpośrednio lub przez ANTIC) należy jeszcze zasygnalizować układowi GTIA, że dane z tych rejestrów mają być przeniesione na ekran. Do tego celu służą dwa najmłodsze bity rejestru PMCTL (Player/Missile Control - $d01d). Bit 0 steruje pociskami, a bit 1 graczami. Ustawienia tych bitów powoduje dodawanie danych gracza lub pocisku do danych tworzonej linii.

    Szerokość graczy to 8bitów, pociskow 2bity. Każdy bit reprezentuje 1 pixel obiektu. Pixel ten jest niezależny od aktualnego trybu obrazu.

    Wysokość obiektów PM/G jest wyznaczana przez wybraną rozdzielczość i jest jednakowa dla nich wszystkich. Szerokość jest ustalana przez zawartość rejestru SIZEM lub SIZEP. W rejestrach SIZEP0-3 (Size Player 0-3, $d008-$d00b) szerokość określają dwa najmłodsze bity (pozostałe są niewykorzystane). W rejestrze SIZEM (Size Missiles, $d00c) każda para bitów określa szerokość pixeli odpowiedniego pocisku, czyli w jednym bajcie zapisane są szerokości 4pocisków:

              bity 0 i 1 - pocisk 0
              bity 2 i 3 - pocisk 1
              bity 4 i 5 - pocisk 2
              bity 6 i 7 - pocisk 3
    
    Szerokość pixeli jest wyznaczana wg schematu:
              00 - pixel o szerokości 1 cyklu koloru
              01 - pixel o szerokości 2 cyklu koloru
              10 - pixel o szerokości 1 cyklu koloru
              11 - pixel o szerokości 4 cyklu koloru
    

    Kolory obiektów określają rejestry COLPM0-3 (Color of Player/Missile 0-3, $d012-$d015). Kolory te są identyczne parami, tzn gracz 0 i pocisk 0 mają kolor z rejestru COLPM0, gracz 1 i pocisk 1 z rejestru COLPM1. Gdy obiekt znajduje sie na tle obrazu, nie ma żadnych kłopotów. Problem pojawia sie dopiero wtedy, gdy obraz zawiera jakąś treść. Chodzi o to, czy obiekt będzie zasłaniał zawartość obrazu, czy odwrotnie. Nazywamy to piorytetem - kolor o wyższym piorytecie będzie zasłaniał kolory o niższym piorytecie. Do określenia kolejności kolorów służy rejestr GTIACTL (GTIA Control - $d01b). Jego bity 0-3 ustalają następujące piorytety kolorów:

    bit0    bit1    bit2    bit3
    COLPM0  COLPM0  COLPF0  COLPF0
    COLPM1  COLPM1  COLPF1  COLPF1
    COLPM2  COLPF0  COLPF2  COLPM0
    COLPM3  COLPF1  COLPF3  COLPM1
    COLPF0  COLPF2  COLPM0  COLPM2
    COLPF1  COLPF3  COLPM1  COLPM3
    COLPF2  COLPM2  COLPM2  COLPF2
    COLPF3  COLPM3  COLPM3  COLPF3
    COLBAK  COLBAK  COLBAK  COLBAK
    

    Ustawienie jednego z tych bitów ustala określone przez niego piorytety. Ustawienie więcej niż jednego bitu powoduje niejednoznaczne określenie piorytetów. W takim przypadku, gdy obszary o jednakowym piorytecie będą się pokrywały, to uzyskają one kolor czarny. Przy ustalaniu piorytetów trzeba pamiętać, że w niektórych trybach ANTIC-a (2, 3, F) z rejestru COLPF1 jest pobierana tylko jasność pixela. W tych trybach wszystkie pixele obrazu mają taki jak COLPF2, niezależnie od aktualnego piorytetu COLPF1.

    Przy tworzeniu P/MG wykorzystywane są jeszcze 2bity rejestru GTIACTL (4 i 5). Ustawienie bitu 4 powoduje nadanie wszystkim pociskom koloru określonego rejestrm COLPF3. Można w ten sposób uzyskać 5-ego gracza. Każda część takiego gracza jest jednak niezależna - może być poruszana oddzielnie i mieć różną szerokość.

    Bit 5 wywołuje po ustawieniu zmianę piorytetów par graczy 0-1 i 2-3. Każdy gracz z takiej pary ma kolorów określony odpowiednim rejestrem. Gdy pixele graczy pokrywają się, to kolor wynikowy jest otrzymywany poprzez operację OR wykonaną na bitach kolorów (np. dla graczy 0 i 1 - COLPM0 ORA COLPM1). Także w tym przypadku pozostałe parametry gracze są ustalane odrębnie.

    Za pozycje poziomą graczy odpowiedzialne są rejestry HPOSP0-3 (Horizontal Position of Player 0-3, $d000-$d003), pocisków HPOSM0-3 (Horizontal Position of Missile 0-3, $d004-$d007). Każdy z nich zawiera numer cyklu koloru, w którym rozpoczyna się przenoszenie na ekran danych odpowiedniego obiektu.

    Przykładem na sprity sprzętowe i ich większą ilośc są gry: Technus, Smuś, Włóczykij. Jak to możliwe ? Możliwe jeśli w jednej poziomym obszarze będą znajdowały sie max 2-a 4kolorowe sprity, np. powiedzmy 32 linii ekranu. W następnych liniach dzieki przerwaniu DLI umieścimy następne 2 przeszkadzajki (na spritach przeważnie są nasi wrogowie), itd. Albo tak jak w w/w grach 2sprity na gracza i 2sprity na przeszkadzajki co 32 linie ekranu.

    Duszki programowe najlepiej zobaczyć w Mario Bros, rewelacyjnie zrobionej, dynamicznej i wciągającej gierce, nie to co te pomyje z C-64 ;P. W Blinky Scary School nasz bohater jest z duszków sprzętowych, a przeszkadzajki z programowych. Pozatym wszystkie gry w Hi-res muszą mieć sprity programowe, C-64 posiada duchy w Hi-res, my mamy to programowo, bo stać nas na to :). Teraz mały przykład prostego wyświetlenia duszka na ekranie, czyli które rejestry wypełniamy:

    pm	equ $a000	;od adresu `PM` bedzie nasz obszar na duchy i pociski
    py	equ 56		;pozycja Y naszego duszka (duszek nie porusza się w pionie)
    
    	opt h+
    	org $8000
    	
    	ldx #0
    petla	lda shape,x		;przepisujemy 25 bajtow z tablicy `SHAPE` pod adres `pm+$400+py`
    	sta pm+$400+py,x	;w tej tablicy znajduja sie dane opisujace ksztalt duszka
    	inx
    	cpx #$19
    	bne petla
    
    	lda >pm
    	sta $d407	;PMBASE - starszy adres obszaru z duchami
    	ldy #2
    	sty $d01d	;PMCTL - czy wyswietlic duchy lub pociski, czy oba razem
    	dey
    	sty 623		;GTICTLS - piorytet kolorów
    	dey
    	sty $d008	;SIZEP0 - szerokość
    	lda #$e
    	sta 704		;cien rejestru koloru gracza0
    	lda #%00111010
    	sta 559		;DMACTLS - dostep do pamieci dla duchow i pociskow wg odpowiednich bitow
    	
    animka	lda 20		;pozycja pozioma bedzie wartosc z zegara systemowego
    	sta $d000	;HPOSP0 - pozycja pozioma duszka nr 0
    	jmp animka
    	
    shape	dta b(0,$c,$18,$38,$7c,$54,$7c,$28,$38,$38,$3c)
    	dta b($7e,$fb,$b9,$38,$38,$3c,$1c,$1c,$e,6,3,0)
    

    Zmiana pozycji poziomej. Za pozycje poziomą akurat odpowiadają rejestry komputerka, więc jest to proste jak w w/w przykładzie. Zmiana pozycji pionowej. Obszar na naszego sprita jest 256 lub 128 bajtowy, każdy bajt odpowiada za jedną linię sprita. Żeby sprawić aby poruszał sie on w pionie, nalezy przemieścić dane opisujące kształt w tym 256 lub 128 bajtowym obszarze.

            ldy #0     ;pozycja Y obiektu
            jsr poz_Y  
            rts
    
    poz_Y   ldx #0
    petla   lda shape,x		;przepisujemy 25 bajtow z tablicy `SHAPE` pod adres `pm+$400+py`
    	    sta pm+$400+py,y	;w tej tablicy znajduja sie dane opisujace ksztalt duszka
            iny
    	    inx
    	    cpx #$19
    	    bne petla
            rts
    

    Jeśli zmieniamy pozycje pionową o znaczną wartość musimy wówczas wymazać całego sprita, inaczej pozostaną fragmenty po poprzedniej pozycji (np. kursor myszki). Jeśli jednak zwiększamy go o 1 wystarczy że umieścimy wartość $00 na początku i końcu tablicy opisującej kształt sprita (tak jak w w/w `shape`).

    cls    ldx #0
           txa
    cls_   sta pm+$400,x	;cały obszar 256 lub 128 kasujemy, wpisując $00
    	     inx
    *      cpx #128
    	     bne petla
           rts
    

    I N - O U T

    Zabawy ze stacją dysków. Ze stacją dysków ponieważ nikt już nie powinien używac magnetofonu, nie wolno ;). Zatem powinniśmy dowiedzieć się jak otworzyć plik, jak go odczytać, zapisać, skasować oraz jak wyswietlić katalog dyskietki. Nie będziemy zajmowali sie dyskowym systemem Sparta ani MyDos, tylko tym najpopularniejszym DosII+ :). DOSII+ oraz jak mu mu podobne charakteryzuje sie obsługą max 64 plików w katalogu dyskietki, brakiem podkatalogów, ślicznym CommandProcesorem. Ten CommandProcesor oznacza że wpisujemy 3literowy taki prawie mnemonik, po nim parametry, naciskamy Return i mamy `bum`. Jeśli nasz program zabawia się ze stacją dysków, a my nie uruchomiliśmy go spod DOSa, to coś z nami jest nie tak :). DOS musi być, chyba że chcecie napisać własny `Disk Operating System`.

    A dlaczego gry i inne programy wczytują się same, bez Dos-u ?

    Nic nie wczytuje się samo, nasz `Operating System` ma w sobie programiki, które potrafią odczytać wskazany sektor z dysku. W czasie bootowania `OPTION+RESET` system odczytuje pierwsze 3sektory i uruchamia w nich zawarty programik. Programik ten przejmuje dalsze działania i ładuje do pamięci cały program. Właśnie tam umieszczone są procedury zabezpieczające przed kopiowaniem. Np. pewien sektor na dysku jest uszkodzony, procedurka sprawdza czy rzeczywiście ten konkretny sektor nie daje sie odczytać jeśli tak tzn. że to jest niby oryginał. Tyle że pewne stacje potrafiły kopiować te zabezpieczenia zapisując właśnie `pseudo bad sectory`. Do dyspozycji mamy gęstości zapisy Single-90kb(128b sector), Enhanced-128kb (128b sector), Double Density-180kb (256b sector). Dwie pierwsze już nie stosujemy bo po co. Używamy najczęściej DD. W przypadku stacji Toms720, Karin itp. możemy zapisywać dyski z gęstością 360kb, 720kb itp w zależności od stacji. Po tym wstępie, przykłady odczytu sektora z pomocą OS i operacje z udziałem DOS-u. Bez udziału DOS-u, pełny przykład w załączniku, plik `LOADER.ASM`:

        ldx <$169   ;nr sektora, w naszym przykladzie jest to pierwszy sektor z katalogiem dysku
        ldy >$169
        stx $30a
        sty $30b
    
        lda #$52    ;kod operacji, $52 = READ
        ldx <128    ;dlugosc sektora
        ldy >128
        sta cod+1   ;modyfikujemy odpowiednie komorki pamieci
        stx lng+1
        sty lng+6
    
        ldx <bufor  ;bufor pod ktory wczytane zostana dane
        ldy >bufor
    
    sio stx $304    ;< adres bufora
        sty $305    ;> adres bufora
    cod lda #0      ;kod operacji
        sta $302
        lda #$40    ;$40 odczyt
        sta $303
    lng lda #0      ;< dlugosc bufora
        sta $308
        lda #0      ;> dlugosc bufora
        sta $309
        jsr $e459   ;wywolanie procedury
        rts
    

    W celu poznania operacji wejścia/wyjścia (in-out) musimy zaznajomić się z podprogramem CIO, który może sterować 8-oma urządzeniami. Zawiera on 8 jednakowych bloków IOCB (o długości 16 bajtów) umieszczonych w pamięci Atari od adresu $340:

              IOCB0 $0340
              IOCB1 $0350
              IOCB2 $0360
              IOCB3 $0370
              IOCB4 $0380
              IOCB5 $0390
              IOCB6 $03A0
              IOCB7 $03B0
    
    Dla wszystkich IOCB struktura jest jednakowa:
    
    0 ICHID  HANDLER ID
    1 ICDNO  NUMER URZĽDZENIA
    2 ICCMD  COMMAND
    3 ICSTA  STATUS
    4 ICBAL  BUFFERADRL (bajt młodszy)
    5 ICBAH  BUFFERADRH (bajt starszy)
    6 ICPTL  PUTADR L (bajt młodszy)
    7 ICPTH  PUTADR H (bajt starszy)
    8 ICBLL  BUFFERLEN L (bajt młodszy)
    9 ICBLH  BUFFERLEN H (bajt starszy)
    A ICAX1  AUX1
    B ICAX2  AUX2
    C ICAX3
    D ICAX4
    E ICAX5
    F ICAX6
    
    - HANDLER ID wartość określana przez podprogram CIO (związana z tablicą HATABS)
    - COMMAND    zawiera numer rozkazu, który ma wykonywać CIO
    - STATUS     zawiera rezultat operacji, tzn czy się udała czy nie
    - BUFFERADR  zawiera adres bufora danych
    - PUTADR     używany wewnętrznie przez podprogram CIO
    - BUFFERLEN  zawiera liczbę bajtów, które będą przekazywane przez wejście/wyjście
    - AUX1       określana przez użytkownika: $04 - dla operacji czytania, $08 dla operacji zapisu
    - AUX2       określana przez użytkownika, np. $80 dla operacji z magnetofonem (długość rekordów)
    
    Aby uruchomić procedury CIO należy:
                                         - wypełnić odpowiednie pozycje IOCB
                                         - do rejestru X wprowadzić numer wybranego IOCB pomnożony przez 16
                                         - wywołać procedurę CIO (jsr $e456)
                                         - sprawdzić status operacji
                                         - zamknąć kanał komunikacji (IOCB)
    

    Po tej dawce teorii czas na przykłady:

    iocb equ $340
    ciov equ $e456
    
    *--------
    *- OPEN
    *--------
    open equ *
    
     ldx #1*16          ;nr kanału * 16
     lda #$03           ;komenda $03 = OPEN, otwiera kanał komunikacji
     sta iocb+2,x 
    
     lda #$04           ;kod operacji, $04 = READ, otwarty kanał bedzie służył do czytania danych
     sta iocb+10,x
    
     lda <nam           ;adres, pod którym umieszczona jest pierwsza litera urzadzenia, lub zbioru
     sta iocb+4,x       ;np. nam dta c`D:PLIK.OBX`,b($9b)
     lda >nam           ;zakończona EOL-em = $9b
     sta iocb+5,x
    
     jsr ciov           ;wywołanie podprocedury systemowej CIOV
     bmi error          ;bit 7 ustawiony czyli coś niedobrego stało się z transmisją
     rts
    
    nam dta c`D:PLIK.OBX`,b($9b)
    
    *---------
    *- CLOSE
    *---------
    close equ *
    
     ldx #1*16          ;nr kanału * 16
     lda #$0c           ;kod operacji $0C = CLOSE, zamyka kanał transmisji
     sta iocb+2,x
    
     jsr ciov           ;i już standardowo, wywołanie CIOV
     bmi error          ;reakcja na błąd
     rts                ;koniec
    
    
    *--------
    *- READ
    *--------
    read equ *
    
     ldx #1*16          ;nr kanału * 16
     lda #$07           ;kod operacji $07 = GET BYTES, pobiera bajty
     sta iocb+2,x 
    
     lda <bufor         ;adres początku bufora danych, pod ten adres będą one wczytywane
     sta iocb+4,x
     lda >bufor
     sta iocb+5,x
     
     lda <length        ;liczba bajtów do pobrania
     sta iocb+8,x
     lda >length
     sta iocb+9,x 
    
     jsr ciov           
     bmi error
     rts
    
    
    *---------
    *- WRITE
    *---------
    read equ *
    
     ldx #1*16          ;nr kanału * 16
     lda #$0b           ;kod operacji $0B = PUT BYTES, zapisuje bajty
     sta iocb+2,x 
    
     lda <bufor         ;adres początku bufora danych, spod tego adresu będą one zapisywane
     sta iocb+4,x
     lda >bufor
     sta iocb+5,x
     
     lda <length        ;liczba bajtów do zapisania (przesłania do urządzenia)
     sta iocb+8,x
     lda >length
     sta iocb+9,x 
    
     jsr ciov           
     bmi error
     rts
    

    Kod $06 to DIRECTORY, czyli odczyt katalog dyskietki. Pozostałe 2 kody, są chyba najrzadziej używane. To GET RECORD = $05 i PUT RECORD = $09. Powodują one wczytanie lub zapisanie bajtów aż do momentu wystąpienia znaku końca zbioru (EOL=$9b). Ich wywołanie wygląda analogicznie jak w/w READ i WRITE.

    Komentarze gości atari.area

    Momencik, uaktualniam...  

    Nie jesteś zalogowany. Tylko zarejestrowani i zalogowani użytkownicy mog± dodawać komentarze.

Lotharek.pl
Retronics
Grawitacja 2024
Lost Party 2024
Silly Venture 2024 SE

Szukaj

Wyszukiwarka przeszukuje zasoby atari.area, atariki oraz forum.

Twoliner

Momencik, uaktualniam...  .

Pamiętaj, żeby linki do Twolinera dodawać wyłącznie po skróceniu za pomocą serwisu tiny.pl. Jeśli coś Ciebie ominęło - skorzystaj z archiwum.

Network

konto

Nie jesteś zalogowany. Zaloguj się lub załóż konto

forum

Artykuły

Wywiady

Allegro

Jako, że Allegro.pl jest bardzo często odwiedzanym serwisem przez Atarowców, umiejscowiłem poniżej wyszukiwarkę produktów związanych z naszym kochanym Atari. Chcesz coś kupić - wystarczy wpisać w okienko poniżej.


Wystarczy wpisac czego szukamy i po chwili znajdujemy sie juz na Allegro.pl.