VBI i DLI w MadPascal-u.

Kiedyś eksperymentowałem z Action!, dziś analogiczny przykład w MadPascal:

uses crt;

const
dl: array [0..32] of byte = (
112, 112, 112, 66, 0, 64, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 130, 86, 72, 67, 65,
lo(word(@dl)), hi(word(@dl))
);

var
col0: byte absolute $2c4;
col1: byte absolute $2c5;
savmsc: word absolute $58;
nmien: byte absolute $d40e;
pc: ^byte; tmp: word;
hscrol: byte absolute $d404;
vcount: byte absolute $d40b;
colt: byte absolute $d017;
dlist: word absolute $230;
i,j,k,l,indx: byte;

procedure dli; interrupt;
begin
 asm { phr };
 inc(indx);
 for i:=0 to 7 do
  begin
   if indx>30 then indx:=0;
   colt:=vcount+indx;
  end;
 asm { plr };
end;

procedure scroll; interrupt;
begin
 j:=j+1;
 if j=16 then
  begin
   j:=0; dec(pc^,2); k:=k+1;
   if k=14 then
    begin
     k:=0; pc^:=tmp;
    end
  end;
  hscrol:=j;
 asm { jmp $E462 };
end;

begin
 i:=0; j:=0; k:=0; indx:=0;
 dlist:=word(@dl);

 SetIntVec(iVBL, @scroll);
 SetIntVec(iDLI, @dli);
 nmien:=$c0;

 pc := @dl;
 inc(pc, 28);

 tmp := pc^+6;
 col0 := 14; col1 := 14;
 savmsc := $4000;

 for l:=0 to 22 do
  writeln(' mp rulez! ');

 repeat until keypressed;
end.

mprulez

Niezaprzeczalną zaletą duetu mp+mads jest optymalizacja i wielkość pliku wynikowego:

$ mads -x -o:scroll.obx -i:/e/mp/base scroll.a65
SYSTEM: $205D..$205C
CRT: $205D..$2070
CODE: $2000..$226F
DATA: $2270..$2282
Writing listing file…
Writing object file…
3983 lines of source assembled in 5 pass
640 bytes written to the object file

 

Reklamy

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

Action!: Finescroll w VBLKD.

Poprzednie przykłady z „Poradnika programisty” brzydko się rwały przy przesuwaniu, zwłaszcza na prawdziwym Atari. Na podstawie różnych „odkryć i znalezisk” powstał poniższy przykład w Action! wykorzystujący Vertical Blank Interrupt. A tutaj analogiczny przykład, który robi to samo w zwykłej pętli i synchronizuje się z VBLANK interrupt za pomocą zegara systemowego.

int j=[0], k=[0]
byte hscrol=54276
card pointer pc
card tmp

include "H1:RUNTIME.ACT"

proc scroll()
 hscrol=j
 j==+1
 if j=17 then
  j=0 pc^==-2 k==+1
  if k=14 then
   pc^=tmp k=0
  fi
 fi
[$4C $E462] ;jmp xitvbv

proc main()
 int i card savmsc=88
 byte clock=$14
 byte nmien=$D40E
 byte array ndl = [112 112 112 66 64 156 2 2 2 2 2 2 2 2 2 2
                   2 2 2 2 2 2 2 2 2 2 2 86 216 159 65 32 156]
 card dlist=560
 card vvblkd=$0224
 byte col0=708
 byte col1=709

 graphics(0)
 dlist=ndl
 savmsc=40000
 col0=14 col1=14

 for i=1 to 23 do
  printf("line: %i%E", i)
 od

 print("Action!")

 pc=dlist+28
 tmp=pc^+6
 i=clock
 while clock=i do od
 nmien=0
 vvblkd=scroll
 nmien=$40
 do od
return

scroll() dodałem jako część opóźnioną procedury obsługi przerwania. Wg Tajemnic Atari powinno się ustawiać vvblkd po „cyknięciu” zegara, żeby się nie okazało, że nie starczy cykli procesora na ustawienie adresu naszej procedury obsługi przerwania. Tak też zrobiłem. Nie jestem przekonany czy to jest konieczne.