VBI finescroll + DLI rainbow (ASM)

Od piątku leżę w szpitalnym łóżku (spokojnie, to tylko kolejne badania moich szwankujących mięśni) i pomimo tego, że sobotę i niedzielę spędziłem z dzieciakami w domu (przypomina mi się seria „Wielkie ucieczki” na TVN), trochę mi się nudzi. Dzisiaj mnie biopsnęli w nogę, więc może trochę pod wpływem anestetyków postanowiłem dokończyć mój ulubiony (ad nauseam) scroll poziomy w VBI i „rainbow effect” w DLI, tym razem w assemblerze i tym razem w lewo.

hscrol = 54276
sdmctl = $022F
dlist = 560
nmien = $D40E
vvblkd = $0224
xitvbv = $E462
scount = $8000
colt = $D017
indx = $8002
wsync = $D40A
vdslist = $0200

      org $4000

init  ldy #0
      sty sdmctl                                ; wyłącz antic
      lda <ndl                                  ; ustaw adres tablicy ndl jako dliste
      sta dlist
      lda >ndl
      sta dlist+1
      lda #16
      sta scount                                ; wyzeruj liczniki
      sty chrno
      sty indx
      lda #64
      sta 88
      lda #156
      sta 89

      ; vbi+dli
      lda <scroll                               ; ustaw scroll w opóźnionym vblank interrupt
      sta vvblkd
      lda >scroll
      sta vvblkd+1
      lda <dli                                  ; ustaw adres procedury dli
      sta vdslist
      lda >dli
      sta vdslist+1
      lda #42
      sta sdmctl                                ; włącz antic
      lda #$c0                                  ; włącz przerwania dli
      sta nmien
      ; kolory i napisy
      lda #0
      sta 710
      posxy #2, #5
      putline #txt1
      lda #50
      sta 88
      lda #155
      sta 89
      posxy #0, #0
      putline #txt2

loop  jmp loop

scroll ldy scount
       dey
       sty hscrol
       beq @+
       sty scount
       jmp xitvbv
@      ldy chrno
       iny
       cpy #30
       bne chmem
       lda #25
       ldx #0
       stx chrno
       sta ndl[28],x
       lda #155
       sta ndl[29],x
       ldx #16
       stx scount
       jmp xitvbv
chmem
       clc
       sty chrno
       ldx #0
       lda ndl[28],x
       adc #2
       sta ndl[28],x
       lda ndl[29],x
       adc #0
       sta ndl[29],x
       ldy #15
       sty hscrol
       iny
       sty scount
       jmp xitvbv

dli    pha
       txa
       pha
       tya
       pha
       inc indx
       ldx #7
@      lda #1
       sta wsync
       lda indx
       cmp #30
       beq @+
       dex
       cpx #0
       beq ret
       clc
       adc vcount
       sta colt
       jmp @-
@      ldy #0
       sty indx
       jmp @-1
ret    pla
       tay
       pla
       tax
       pla
       rti

scount .by 0
chrno .by 0

.array ndl [33] .byte
 112, 112, 112, 66, 64, 156, 2, 2, 2, 2, 6, 2, 2
 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 130, 86, 30, 155
 65, 32, 156
.enda

txt1  .by 'test finescroll!' $9b
txt2  .by 'mads compiler!' $9b

.link 'putline.obx'
.link 'posxy.obx'

a2

Powyższy przykład przesuwa druga z linii w trybie Antic 6/GR. 1, ale sporo zabawy zajęło mi uzyskanie prawidłowego finescroll w Antic 2 / GR. 0. Z tego co udało mi się wyeksperymentować, w trybie GR. 0 jeden piksel potrzebuje pół cyklu koloru, skoro tych pikseli jest 8, do przesunięcia jednego znaku potrzeba 4 zmiany rejestru finescroll (1 cykl koloru = 1 finescroll). Analogicznie w trybie GR. 1 / Antic 6, jeden piksel potrzebuje jeden cykl koloru, znak ma 8 pikseli szerokości, więc mamy finescroll o 8 per znak.

Warto wspomnieć o jeszcze jednym zjawisku. W przykładach w Action! i assemblerze scroll działał prawidłowo, ale tylko w prawo i tylko o 16 punktów. Wydawało mi się to dziwne i długo nie dawało spokoju dlaczego tak się dzieje, że przy finescroll o 8 widać coś jakby szarpnięcie o jeden znak. Zjawisko brało się stąd, że zmieniałem adres pamięci w display liście i wychodziłem z procedury, a zmiana rejestru hscroll na odpowiadający nowemu położeniu znaków na ekranie, następowała dopiero przy następnym vblank interrupt (czyli hscroll był nadal 0, a ANTIC przez chwilę do następnego vbi wyświetlał znak przesunięty po zmianie adresu). Zmiana adresu pamięci i jednoczesne ustawienie hscroll przed jmp xitvbv usunęło problem i wszystko działa tak jak w książce…

Reasumując, Mads jest moim ulubionym cross-assemblerem i pewne jego cechy i funkcje bardzo mnie zachęcają do dalszych eksperymentów, jednak coraz większy widzę sens w programowaniu w Action! Przede wszystkim czytelność kodu jest o wiele większa i na pierdoły nie traci się wiele czasu (tutaj ten sam efekt w Action!). Ciekaw jestem jak sprawdzi się Action! + VBXE.

PS: putline i posxy pochodzą z LIBRARIES/stdio/lib mads. Możnaby jeszcze wyzerować pamięć obrazu, ale… X /C w SDX zrobi to za mnie ;).

Madsowy „Hello World!”

Czytam powoli „Atari Roots” i przy trybach adresowania wymyśliłem sobie „Hello World” z wykorzystaniem madsowego .sb. Pomysł jest taki: pobieramy adres pamięci tekstu z adresu 660 i 661. Jest to trzecia od dołu linijka ekranu (pewnie dlatego, żeby print w basicu był prosty i obsługiwał tryby graficzne z „okienkiem tekstowym”). Odejmujemy odpowiednią magiczną liczbę (20 linii = 800 bajtów, LSB i MSB łatwo przeliczyć).

hello

Niespodzianka polega na tym, że opis .sb mówi: „it will convert all bytes into ATASCII screen codes before storing them”. Konwersja wykonywana jest do kodów ekranowych, stąd porównanie cmp #$db już po konwersji, zamiast #$9b.

     org $600
     cld
     sec
     lda 660
     sbc #32
     sta $cb
     lda 661
     sbc #3
     sta $cc
     ldy #0
     ldx #0
loop lda txt,y
     cmp #$db
     beq nxtl
     sta ($cb),y
     iny
     jmp loop
nxtl clc
     ldy #0
     lda $cb
     adc #54
     sta $cb
     lda $cc
     adc #0
     sta $cc
     inx
     cpx #24
     bne loop
rbow lda $d20a
     sta $d018
     lda #0
     sta $2c5
     sta $d40a
     jmp rbow
txt  .sb 'Hello World!' $9b

W „promocji” namalujemy na końcu losową tęczę :). Możliwości generowania obrazu tego małego komputerka zawsze mnie fascynowały.

Tabela mapowania ATASCII na kody ekranowe tutaj. Jak zauważył xxl na forum atarionline.pl przy napisie dłuższym niż 255 bajtów rejestr y się przekręci. W „Hello World!” nam to nie grozi, niech więc póki co zostanie tak jak jest.

Następny przystanek: plot/drawto.

Action! + asm.

Moje eksperymenty z Action! trwają i ten język programowania coraz bardziej mi się podoba. Po przeczytaniu „Assembly language and Action!” z Reference Manuala zacząłem się zastanawiać w jaki sposób łączyć ze sobą programy (binarne) w Action! i istniejące procedury w assemblerze. Są dwa sposoby: dla prostych procedur kod maszynowy 6502 można umieścić bezpośrednio w pliku źródłowym Action! w nawiasach [ ]. mads potrafi wygenerować listing, z którego taki żółtodziób jak ja może sobie skopiować kolejne rozkazy procesora i wstawić w nawias. Biorąc pod uwagę, że cała biblioteka runtime Action! jest tak zrobiona zastanawiałem się jak dołączyć bardziej skomplikowane procedury bez konieczności konwertowania ich do takiej postaci (o ile to w ogóle możliwe). Jakub na forum AOL mile mnie zaskoczył: wystarczy „skleić” pliki binarne np. za pomocą polecenia cat pod Linuksem (lub Cygwinem pod Windows).

Prosty przykład pokaże fajność tego połączenia, a wspomniany rozdział manuala wyjaśnia, że do procedury w asm można przekazać aż do 16 bajtów parametrów (poprzez akumulator A, rejestry X i Y i stronę zerową $A3-$AF):

ASMPROC.ASM:

org $600

lda #0
sta 710
rts

org $607

lda #52
sta 710
rts

ASMTEST.ACT:

include "H1:RUNTIME.ACT"

proc test1=$600()
proc test2=$607()

proc main()

card i

printe("Action! jest super !")

do
 test1()
 sound(0,121,10,6)
 for i=1 to 10000 do od

 test2()
 sound(0,50,10,6)
 for i=1 to 10000 do od
od

return

Po assemblacji łączymy oba pliki: cat ASMPROC.obx ASMTEST.BIN > ASMTEST.xex i gotowe.

Powiem krótko: cieszy mnie to niezmiernie :). Po 20-latach odkrywam na nowo jak niesamowitym urządzeniem było małe Atari… Połączenie Action! z assemblerem daje pełną swobodę i ogromne możliwości. Coś jak połączenie szkieletu w pythonie i modułów wymagających wydajności w C.