Effectus na starych linuksach.

Zdarza mi się ostatnio testować i kompilować (na prośbę przesympatycznego autora) Effectusa, czyli cross compiler Atari Action! na PC dla Linuksa.

Zastanawiałem się jak wypada kompatybilność statycznych binarek, które kompiluje na Archu. No i wg moich ustaleń na wszystkim co ma glibc w wersji 2 powinno działać.
Testy przeprowadziłem na dystrybucji którą znam i której kiedyś używałem: Slackware w wersjach 1.0.1, 2.2.1 i 7.0.

Wybór był nieprzypadkowy. Na początku myślałem, że wystarczy w kernelu obsługa formatu binarnego ELF. Slackware 1.0.1 z kernelem 0.99.12 jeszcze tego formatu nie obsługiwał. Kolejny, czyli Slackware 2.2.1 miał już kernel 1.2.1 czyli ELF na 100% obsługiwany. Segfaulty sugerowały, że to jednak libc się gryzie. Kiedyś dawno zrobiłem taki eksperyment na potrzeby dyskusji o ABI kernela i moje programiki działały z kernelem 0.1, ale one nie używały libc, tylko wprost funkcje os-u.

Pierwszym Slackiem z glibc2 była wersja 7, od ktorej zaczęła się moja poważniejsza przygoda z Linuksem. Rok 1999, full-wypas kernel 2.2. No i jak się spodziewałem, binarki effectusa i madsa zadziałały bez problemu.

A tak swoją drogą instalacja Linuksa z 1993 w 2014 to ciekawe doświadczenie. Qemu nie jest w stanie zaemulować kontrolera scsi, czy też obsługiwanego 20 lat temu CD romu, ale to nie problem. Można stworzyć obraz dysku w pliku (dd) i w nim utworzyć system plików, np msdos. W ten sposób stworzyłem dysk zawierający wszystkie serie pakietow (można taki obraz zamontować z -o loop=/dev/loop0), który potem montowałem w trakcie instalacji do /root/dos, a instalator pozwala na instalację pakietów ze wskazanego, wcześniej zamontowanego nośnika. Wygodne to i szybkie rozwiązanie, a dziala chyba we wszystkich wersjach Slackware.

Niesamowite jest to, jak przyjemnym w użytkowaniu był Slackware już w 93 roku ubiegłego stulecia…

A działanie binarek effectusa/madsa  na dystrybucji z 1999 roku, czyli sprzed 15 lat daje do myślenia.

Reklamy

VBXE + Action! – Mapa atrybutów.

Kolejny „przełomowy” przykład na podstawie kodu Rybags’a w Basicu. Film ponizej pokazuje szybkosc dzialania w Atari Basic vs Action!

set 14=$8000
set $491=$8000
include "H1:RUNTIME.ACT"

proc main()
 byte vc=$D640, memcont=$D65E, membank=$D65F
 byte xdla0=$D641, xdla1=$D642, xdla2=$D643
 byte pointer p=$A000
 byte i, j, curinh=752
 int bc, lum, ls
 card cs

 if vc<>$10 then
  printe("Brak VBXE FX")
  do od
 fi

 memcont=$A8
 membank=128

 p^=40 p==+1
 p^=14 p==+1
 p^=7 p==+1
 p^=0 p==+1
 p^=16 p==+1
 p^=0 p==+1
 p^=0 p==+1
 p^=0 p==+1
 p^=0 p==+1
 p^=0 p==+1
 p^=7 p==+1
 p^=7 p==+1
 p^=2 p==+1
 p^=255 p==+1

 for i=0 to 75 step 3
  do
   p^=40 p==+1
   p^=0 p==+1
   p^=7 p==+1
  od

 p^=0 p==+1
 p^=128

 membank=129

 for i=0 to 23
  do
   cs=$A000+i*80 lum=6 ls=2 bc=0
   for j=0 to 39 do
    p=cs+j*4
    p^=0 p==+1
    p^=lum p==+1
    lum==+ls
    if lum=15 or lum=6 then
     ls=-ls
    fi
    p^=bc p==+1
    bc==+12
    if bc>255 then bc==-255 fi
    p^=0
  od
 od

 xdla0=0 xdla1=0 xdla2=0

 graphics(0)
 curinh=1
 vc=3

 printf("%EVBXE is cool!")
 do od
return

Różne wartości MAPSTEP i przyrostu bc dają różne efekty:

Od razu przychodzi do głowy żeby te wartości zmieniać w VBI…

VBXE + Action! Animowane sprite’y.

Choć w zasadzie powinienem napisać jeden sprite 🙂

set 14=$8000
set $491=$8000
include "H1:RUNTIME.ACT"

MODULE
int fno=[1], i=[0]
byte bltst=$D653
byte bltmv0=$A115, bltmv1=$A116, bltmv2=$A117

byte array bltsrc =
   [ 0 96 1
   128 96 1
     0 97 1
   128 97 1 ]

proc CIOVE=$E4DF(byte areg, xreg)

proc delay()
 card i
 for i=0 to 30000 do od
 return

proc bltme()
 if fno mod 10 = 0 then
  bltmv0=bltsrc(i*3)
  bltmv1=bltsrc(i*3+1)
  bltmv2=bltsrc(i*3+2)
  bltst=1 fno==+1 i==+1
  if i > 3 then
   fno=1 i=0
  fi
 [$4C $E462]
 fi
 fno==+1
[$4C $E462]

proc main()
 byte vc=$D640, clock=$14
 int i byte memcont=$D65E, membank=$D65F
 byte psel=$D645, csel=$D644, cr=$D646, cg=$D647, cb=$D648
 byte xdla0=$D641, xdla1=$D642, xdla2=$D643
 byte blt0=$D650, blt1=$D651, blt2=$D652 ; bltst=$D653
 byte bkg=710, curinh=752
 byte iocb1cmd=850
 card iocb1buf=852, iocb1len=856
 byte nmien=$D40E
 card vvblkd=$0224

 byte array xdl=[98 136 219 0 0 0 64 1 17 223]

 byte array clrscr=
   [ 0 0 0     ;src addr
       0 0     ;src step y
         0     ;src step x
     0 0 0     ;dst addr ($0000 up)
      64 1     ;dst step y (320)
         1     ;dst step x
      63 1     ;width (320-1)
       239     ;height (240-1)
         0     ;and mask
         0     ;xor mask
         0     ;collision and mask
         0     ;zoom
         0     ;pattern
         0 ]   ;control

 byte array bltmv=
  [ 0 96 1     ;src addr
       0 2     ;src step y
         1     ;src step x
  224 62 0     ;dst addr
      64 1     ;dst step y
         1     ;dst step x
     124 0     ;width
        53     ;height
       255     ;and mask
         0     ;xor mask
         0     ;collision and mask
         0     ;zoom
         0     ;pattern
         0 ]   ;control

 if vc<>$10 then
  printe("Brak VBXE FX")
  delay()
  [$4C $C2AA] ;reset
 fi

 memcont=$A8
 membank=128+20
 moveblock($A000, xdl, 10)
 xdla0=0 xdla1=64 xdla2=1

 moveblock($A100, clrscr, 21)
 blt0=0 blt1=65 blt2=1
 bltst=1 ;blitter's clear scr
 while bltst <> 0 do od
 moveblock($A115, bltmv, 21)
 blt0=21 blt1=65 blt2=1

 graphics(0)
 bkg=0 curinh=1 put(31)

 close(1)
 open(1,"D1:HEL.PAL",4,0)
 psel=1 csel=0

 for i=0 to 255 do
  cr=getd(1) cg=getd(1) cb=getd(1)
 od
 close(1)

 open(1,"D1:HEL.PIC",4,0)
 iocb1cmd=7
 iocb1buf=$A000
 iocb1len=$1000

 for i=22 to 29 do
  membank=128+i
  CIOVE(0,$10)
 od

 close(1)
 vc=3
 membank=128+20

 i=clock while clock=i do od
 nmien=0
 vvblkd=bltme
 nmien=$40
 do od
return

VBXE + Action! Wczytywanie obrazu w overlay.

No i jest, pierwszy eksperyment w Action! + VBXE: obrazek w tle:

set 14=$8000
set $491=$8000

include "H1:RUNTIME.ACT"

proc CIOVE=$E4DF(byte areg, xreg)

proc delay()
 card i
 for i=0 to 30000 do od
return

proc main()

 byte vc=$D640
 int i byte memcont=$D65E, membank=$D65F
 byte psel=$D645, csel=$D644, cr=$D646, cg=$D647, cb=$D648
 byte xdla0=$D641, xdla1=$D642, xdla2=$D643
 byte blt0=$D650, blt1=$D651, blt2=$D652, bltst=$D653
 byte bkg=710, curinh=752
 byte iocb1cmd=850
 card iocb1buf=852, iocb1len=856

 byte array xdl=[98 136 219 0 2 0 64 1 17 223]

 ;clrscr blitterlist
 byte array clrscr=
   [ 0 0 0  ;src addr
     0 0    ;src step y
     0      ;src step x
     0 0 0  ;dst addr ($0000 up)
     64 1   ;dst step y (320)
     1      ;dst step x
     63 1   ;width (320-1)
     239    ;height (240-1)
     0      ;and mask
     0      ;xor mask
     0      ;collision and mask
     0      ;zoom
     0      ;pattern
     0 ]    ;control

 if vc<>$10 then
  printe("No VBXE FX found")
  delay()
  [$4C $C2AA] ;warm reset
 fi

 memcont=$A8  ;memac at $A000, cpu access
 membank=128+20
 moveblock($A000, xdl, 10)
 xdla0=0 xdla1=64 xdla2=1

 moveblock($A100, clrscr, 21)
 blt0=0 blt1=65 blt2=1
 bltst=1 ;blitter start will clear scr
 while bltst <> 0 do od ;let's wait till
                        ;blitter finishes
 graphics(0)
 bkg=0 curinh=1 put(31)

 close(1)
 open(1,"D1:AN.PAL",4,0)
 psel=1 csel=0
 for i=0 to 255 do
  cr=getd(1) cg=getd(1) cb=getd(1)
 od
 close(1)

 open(1,"D1:AN.PIC",4,0)
 iocb1cmd=7
 iocb1buf=$A000
 iocb1len=$1000

 for i=2 to 18 do
  membank=128+i
  CIOVE(0,$10)
 od
 close(1)

 vc=3
 printe("Hej czesc! Daj cos zjesc!")
 do od
return

test

Więcej informacji w tym wątku:

http://atarionline.pl/forum/comments.php?DiscussionID=2623&page=1#Item_15

Z moich przemyśleń dodam tylko uwagę na temat adresu overlay w xdl. Adres overlay w tym przykładzie to 0 2 0, czyli 2^9=512. Obrazek kopiujemy od adresu $2000=8192 i jeśli ustawiłbym  overlay na 0 32 0 to obraz wyświetlany byłby od samej góry, brzydko trochę, nie? Przy pierwszym podejściu ustawiałem ten adres na 0 0 0 i zastanawiałem się, czemu obrazek jest przesunięty? Po dwóch tygodniach naszła mnie właściwa myśl… Otóż, adres overlay musi być taki, aby 8192-adres było podzielne przez 320 (tada!). Czyli np. jeśli chcemy przed obrazkiem 24 linie, to 8192-24*320=512. W powyższym przykładzie blitter zeruje pamięć od $0000 więc mamy ładną ramkę przed i po obrazku.

PMG w Action!

Najwyższy czas na coś nowego. Poniżej pierwszy przykład PMG w Action! na podstawie „Atari Graphics and Arcade Game Design”. Do zerowania pamięci użyłem funkcji zero(), a do kopiowania danych moveblock() z Runtime Action!  Przy przesuwie pionowym duszka dane kopiujemy za pomocą wskaźników (tak btw, to lubię wskaźniki w Action!).


byte array p1data = [0 0 153 153 189 189 255 255 189 189 153 153 0 0]
card spot
byte pointer p1, p2

proc delay()
 int i for i=0 to 1000 do od
return

proc moveup()
 int i
 p1=spot p2=p1-1
 for i=0 to 13 do
  p2^=p1^
  p1==+1 p2==+1
 od
 spot==-1
return

proc movedown()
 int i
 p1=spot+13 p2=p1+1
 for i=0 to 13 do
  p2^=p1^
  p1==-1 p2==-1
 od
 spot==+1
return

proc main()
 byte pm=106, dmactl=559, gractl=53277, apmbase=54279,
      p1size=53256, p1hpos=53248, p1col=704, p1chpos,
      stick0
 card pmbase

 graphics(1+16)
 pm==-8
 pmbase=pm*256
 dmactl=62
 gractl=3
 apmbase=pm
 p1hpos=50 p1chpos=50
 p1size=1
 p1col=88
 spot=pmbase+1024+50

 zero(pmbase+1024, 256)
 moveblock(spot, p1data, 14)

 do
  stick0=stick(0)
  if stick0=11 then
   p1chpos==-1 p1hpos=p1chpos
  elseif stick0=7 then
   p1chpos==+1 p1hpos=p1chpos
  elseif stick0=14 then
   moveup()
  elseif stick0=13 then
   movedown()
 fi
 delay()
od

return

Jako ciekawostkę polecam zakomentować delay(). Action jest chyba jednak dość szybkie…

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 ;).

Action! Jedno RUNTIME, wiele modułów.

To już chyba ostatni wpis  z „linkowaniem” za pomocą type lub cat, który jednak pokaże do czego może się przydać Symbol Table Lister.  Załóżmy, że sklejamy kilka kawałków/modułów w Action! Fajnie byłoby aby Runtime było dołączane tylko raz – wymyśliłem sobie, że skoro STL pokaże mi adresy procedur w Runtime, to można zrobić tak:

  • Uruchomić w monitorze R: „H1:STL.ACT”
  • Otworzyć w edytorze Ctrl+Shift+R H1:RUNTIME.ACT i dodać np. set 14=$8000 set $491=$8000
  • Przejść do monitora Ctrl+Shift+M, skompilować C, zapisać W „H1:RUNTIME.OBX”

W LISTING.TXT (patrz poprzedni wpis o STL) znajdziemy adresy:

PrintE……… $822C PROC(BYTE ARRAY)
PrintF……… $8430 PROC(BYTE ARRAY, CARD, CARD, CARD, CARD, CARD)

Więc w naszym programie możemy zdefiniować:

set 14=$8739
set $491=$8739

proc printf=$8430(byte array a, card b, card c,
                  card d, card e, card f)
proc printe=$822C(byte array a)

proc main()
   printf("%S%E", "Test")
   printe("Runtime")
   do od

Kompilujemy i zapisujemy np. jako TESTRT.OBX
Potem sklejamy cat RUNTIME.OBX TESTRT.OBX > TESTRT.XEX

Dzięki temu każdy z dołączanych kawałków binarnych będzie mniejszy, a dodatkowo kompilacja będzie trwać krócej, bo RT kompilowane będzie tylko raz. Szkoda, że kompilatora uruchomionego w emulatorze nie da się odpalać w skrypcie. Można by do tego napisać makefile albo skrypt w bashu…