W sumie równolegle i bez umawiania się pomyśleliśmy wczoraj/dzisiaj rano z Perinoidem o jeszcze większym przyśpieszeniu generowania szachownicy kolorów – bo serio – ile może się rysować ekran w 80 kolomnowym trybie.
Ponieważ jestem ciekawy czy ktoś nie wymyśli czegoś lepiej – załączam dwa punkty startowe – kod w BASICu znaleziony przeze mnie w internecie, który przerobiłem na Action! i który Perinoid przerobił na C – może ktoś pokusi się o przerobienie tego na Pascala czy inny język w celach testów wydajnościowych 🙂
10 REM * DISPLAY ALL 256 COLORS
11 GRAPHICS 9:FOR V=0 TO 15:COLOR V
12 FOR N=0 TO 4:PLOT 5*V+N,0
13 DRAWTO 5*V+N,191:NEXT N:NEXT V
14 D=256*PEEK(561)+PEEK(560)
15 FOR N=1 TO 16:READ V:POKE D+V,143
16 NEXT N:FOR N=0 TO 25:READ V
17 POKE 1664+N,V:NEXT N:POKE 512,139
18 POKE 513,6:POKE 546,128:POKE 547,6
19 POKE 53248,40:POKE 53249,208
20 POKE 53261,255:POKE 53262,255
21 POKE 53266,0:POKE 53267,0
22 POKE 54286,192
23 GOTO 23
24 DATA 16,28,40,52,64,76,88,102,114
25 DATA 126,138,150,162,174,186,198
26 DATA 8,72,169,0,133,203,104,40,76
27 DATA 95,228,8,72,165,203,24,105,16
28 DATA 141,26,208,133,203,104,40,64
Perinoid sklecił szybki kod w C – gdzie kluczem prędkości jest memcpy kopiujące 40 bajtów (czyli jedną linię grafiki) zamiast wolnego Poke. Jest szybko, bardzo szybko. 0,1 sekundy na całość kodu. Nagrywając na 30fps widzę to w trzech ramkach od początku liczenia do pełnego wyświetlenia.
// powiel 40 bajtow cc65
for(i=1; i<192; i++) {
memcpy(ptr, video_ptr, 40);
ptr+=40;
}
W Action! to samo robi moveblock(gdzie,skąd,ile) – zabawne, bo procedura ta nie przenosi (move) tylko kopiuje – dokładnie na tej samej zasadzie jak memcpy.
; powiel 40 bajtow Action
FOR i=1 TO 192
DO
moveblock(ptr, video_ptr, 40)
SCREEN==+40
OD
Jednak ta sama operacja zajmuje… 0.2 sekundy – dwa razy dłużej niż w C.
Odpowiedź jest oczywiście w asemblerze – biblioteki do CC65 są bardzo mocno zoptymalizowane pod kątem wydajności i tak też jest z kodem memcpy. Czyli przydało by się też coś takiego pod Action!
Ciekawe rzeczy napisał o tym Tebe na atari.org.pl, a Kuba Husak potwierdził – dalsze zwiększenie wydajności to pchanie tematu w asm i pisanie własnej procki… do kopiowania prostokątów (bo w sumie docelowo mi o to chodziło).
Póki co moje wypociny w Action! (tak wiem – Graphics i Poke do wywalenia po zastąpieniu swoimi prockami i DL).
; DISPLAY ALL 256 GTIA COLORS
INCLUDE "RUNTIME.ACT"
BYTE ch=764 ; odczyt klawiatury
BYTE RTCLOCK=20 ; sys timer do pomiaru szybkosci kodu
BYTE SAVMSCL=88 ; lsb of screen addr
BYTE SAVMSCH=89 ; msb
BYTE ARRAY TAB01 = [16 28 40 52 64 76 88 102 114 126 138 150 162 174 186 198]
BYTE ARRAY TAB02 = [8 72 169 0 133 203 104 40 76 95 228 8 72 165 203 24 105 16 141 26 208 133 203 104 40 64]
BYTE ARRAY TAB03 = [
$00 $00 $01 $11 $11 $22 $22 $23 $33 $33
$44 $44 $45 $55 $55 $66 $66 $67 $77 $77
$88 $88 $89 $99 $99 $AA $AA $AB $BB $BB
$CC $CC $CD $DD $DD $EE $EE $EF $FF $FF
]
BYTE V, N
CARD DLIST, SCREEN
PROC SHOW256COLORS ()
; RTCLOCK=0 ; potrzebne gdy mierzymy czas wykonania
GRAPHICS (9)
SCREEN=SAVMSCL+256*SAVMSCH ; adres pamieci ekranu
FOR V=0 TO 191
DO
moveblock(SCREEN, tab03, 40)
SCREEN==+40
OD
; gdzie jest DisplayList???
DLIST=256*PEEK(561)+PEEK(560) ; wychodzi, ze pod adresem 41014 w ACTION
; ponizsza petla laduje kod 143 w displayliste co 12 bajtow
; co robi ten kod - to jest najstarszy bit opcodu Antic'a - włącza przerwanie DLI
FOR N=0 TO 15
DO
V=TAB01(N)
POKE (DLIST+V,143)
OD
; ponizsza petla laduje 26 bajtowy kod asm z tablicy nr 2, kod asm zalaczam na koncu
FOR N=0 TO 25
DO
V=TAB02(N)
POKE (1664+N,V)
OD
POKE (512,139) ; 1675 ($68B) - punkt B w kodzie asm
POKE (513,6) ; pod tym adresem definiujemy wektor przerwań DLI
POKE (546,128) ; 1664 ($680) - punkt A w kodzie asm
POKE (547,6) ; VVBLKI - VBLANK immediate register
; ponizsze ustawiają duszki jako dwie maski po bokach ekranu
POKE (53248,40) ; (W) Horizontal position of player 0
POKE (53249,208) ; (W) Horizontal position of player 1
POKE (53261,255) ; (W) Graphics shape for player 0
POKE (53262,255) ; (W) Graphics for player 1
POKE (53266,0) ; (W) Color and luminance of player and missile 0 (704)
POKE (53267,0) ; (W) Color and luminance of player and missile 1 (705)
; na koniec włączamy przerwania NMI
; Non-maskable interrupt (NMI) enable
POKE (54286,192)
; jezeli mierzymy czas wykonywania kodu to ponizsze dwa do odmarkowania
;PRINTE("czas wykonania")
;PRINTB(RTCLOCK)
; moja tradycyjna koncowka kodu
; LOOP + ESC odczytujemy z rejestru ch czy nacisnieto klawisz ESC, jezeli tak to wyjscie z petli
WHILE ch<>28
DO
OD
RETURN
; kod asm wywylywany przerwaniami:
; ASM PART A ; PHA
; LDA #$00
; STA $CB
; PLA
; PLP
; JMP $E45F ; SYSVBV
; CZESC B ; PHP
; PHA
; LDA $CB
; CLC
; ADC #$10
; STA $D01A ; COLBK
; STA $CB
; PLA
; PLP
; RTI
Na koniec oczywiście refleksja – Action! był reklamowany jako najszybszy język 8bitowy. W tamtych czasach – to pewnie była prawda, poza assemblerem mało co mogło się z nim równać. Co więcej – chyba był planowany do sportowania na Apple II i Commodore 64 – szkoda, że do tego nie doszło. Musiało być to jednak mocno zaawansowane w planach, bo jeżeli wczytacie się w treść poniższej reklamy to:
“OS/A+ the first and finest operating system for BOTH Atari and Apple II computers is NOW included FREE as a part of every OSS systems software package.”
