26

drac030: Zrobiłem dużo testów, ale niewiele to pomogło.. Od samego początku staram się maksymalnie zoptymalizować grę, przez kilka tygodni robiłem tylko pomiary, testy, przyspieszenia i nie wiem co to wszystko.. :D

16-bit A: cały silnik = max 6,1 % klatki (0,35 fps przy 5,7) - para rep/sep kosztuje 6 cykli, tyle samo, ile oszczędza jedno 16-bitowe dodawanie; przerobiony blok w paint_col dał netto 1 cykl, drugi wywalił boot. clc/adc #1 = 0,1 %.

mvn/mvp: w klatce nie ma czego przenosić - te lda/sta to próbkowanie tekstur, nie kopiowanie bloku. Jedyna pętla kopiująca (spr_fcopy) chodzi przy ładowaniu, a jej cel to 4 KB okno VBXE, które trzeba przebankowywać co 4 KB, więc mvn musiałby iść bank po banku: 341 ms na wczytanie poziomu, zero fps.

27

Zależy ile się gra i ile jest założone :-)

Pamięć studenta ma charakter kwantowy - student wie wszystko, ale jednocześnie nic nie pamięta.
- Kilka(naście?) pudełek z klawiszami i światełkami. I jeden Vectrex, żeby nimi wszystkimi rządzić.

28

w1k napisał/a:

16-bit A: cały silnik = max 6,1 % klatki (0,35 fps przy 5,7) - para rep/sep kosztuje 6 cykli, tyle samo, ile oszczędza jedno 16-bitowe dodawanie; przerobiony blok w paint_col dał netto 1 cykl, drugi wywalił boot. clc/adc #1 = 0,1 %.

Tak, ja wiem, ile zajmuje rep/sep, i oczywiście, przy całkowicie ośmiobitowym kodzie, nie zawsze się opłaca przełączenie (dla pojedynczej operacji - prawie nigdy). Ale tam są takie oto na przykład ciągi rozkazów 8-bitowych:

https://www.atari.org.pl/forum/misc.php?action=pun_attachment&item=13796

Nie patrzę całościowo, więc nie wiem, czy ten kawałek ma jakikolwiek wpływ na renderowanie klatek, ale wygląda, jakby danie rep #$20 na początku, a sep #$20 gdzieś na końcu pozwoliło go skrócić o połowę.

Widziałem podobny kawałek kopiujący w podobny sposób z miejsca na miejsce bodaj 12 bajtów przy użyciu 24 rozkazów - 72 bajty, 96 cykli, przy przełączeniu na 16-bitowy akumulator zeszłoby to do 40 bajtów i 14 rozkazów na sumę 66 cykli.

Jakieś ciągi lsr/ror/lsr/ror na dwóch kolejnych bajtach, w pętlach i bez - to wszystko jest do optymalizacji.

Post's attachments

ciag_rozkazow.png 51.65 kb, nikt jeszcze nie pobierał tego pliku. 

Tylko zalogowani mogą pobierać załączniki.
KMK
? HEX$(6670358)

29

drac030 zapomniał że w1k nie jest programistą, co już w1k wyjaśniał

*- TeBe/Madteam
3x Atari 130XE, SDX, CPU 65816, 2x VBXE, 2x IDE Plus rev. C

30

Dzięki za troskę, ale o niczym nie zapomniałem - w1k może to wkleić Claudowi tak samo, jak wkleja tu jego odpowiedzi.

KMK
? HEX$(6670358)

31

drac030, dzięki, wprowadziłem zmiany, zmiana prędkości jest rzeczywiście tylko kosmetyczna. dziś/jutro opublikuję ostatnią wersję z poprawkami, zanim opuszczę słowację na 10 dni.

32

w1k napisał/a:

drac030, dzięki, wprowadziłem zmiany, zmiana prędkości jest rzeczywiście tylko kosmetyczna. dziś/jutro opublikuję ostatnią wersję z poprawkami, zanim opuszczę słowację na 10 dni.

Nie ma pośpiechu, dzięki.

Popatrzyłem sobie jeszcze tu i tam i nadal mi się wydaje, że coś można osiągnąć mikrooptymalizacjami niekoniecznie nawet polegającymi na zastosowaniu 16-bitowego akumulatora, bo i kod czysto ośmiobitowy można ulepszyć, np.

https://www.atari.org.pl/forum/misc.php?action=pun_attachment&item=13797

Zakładając, że nie ma odwołań z zewnątrz pod $4d60 (a nie widzę, żeby były), reforma da 8 cykli zysku (a ten kawałek kodu jest wywoływany bardzo często).

Co więcej, zawartość akumulatora jest potem (po odgałęzieniu bcc pod $4d66 do rts w $4d76) tracona, więc można zastąpić cmp $1353 przez sec/sbc $1353, a sec i sbc stojące poniżej odgałęzienia zlikwidować całkowicie. To da razem 10 cykli zysku - a cały kawałek od adresu $4d5a do $4d6d ma ich, o ile dobrze liczę, 28.

No, i tak dalej, i tym podobnie, usque ad mortem.

Post's attachments

doom_procedurka.png 9.8 kb, nikt jeszcze nie pobierał tego pliku. 

Tylko zalogowani mogą pobierać załączniki.
KMK
? HEX$(6670358)

33

Altirra ma świetną opcję "Performance Analyzer". Można tam zobaczyć która część kodu zajmuje najwięcej cykli w ramce.

Antonia 2 / ATW800/2 / Atari V4sa / Lynx I / Mega ST 1 / 7800 / Portfolio / Lynx II / Jaguar / TT030 / Mega STe / 800 XL / 1040 STe / Falcon030 / 65 XE / 520 STm / SM124 / SC1435
SUB/AVGcart / FujiNet / DDD HDD / AT Speed C16 / TF536 / SDrive / PAK68/3 / Lynx Multi Card / LDW Super 2000 / XCA12 / SkunkBoard / CosmosEx / SatanDisk / UltraSatan / USB Floppy Drive Emulator / Eiffel / SIO2PC / Crazy Dots / PAM Net
http://260ste.atari.org

34 Ostatnio edytowany przez w1k (2026-08-30 18:38:42)

benche.. + SPEEDUP_LOG.md (jest napisane po słowacku)

Post's attachments

bench.zip 10.2 kb, liczba pobrań: 2 (od 2026-08-30) 

Tylko zalogowani mogą pobierać załączniki.

35 Ostatnio edytowany przez drac030 (2026-08-31 08:59:10)

w1k napisał/a:

benche.. + SPEEDUP_LOG.md (jest napisane po słowacku)

Nie no, statystyki fajne.

Co nie zmienia faktu, że procedura, która zajmuje połowę czasu CPU (draw_twall_clip wraz z przyległościami) jest, jak napisałem powyżej, pełna nieporadnego kodu, ze zbędnymi rozkazami (jak powyżej, albo np. zamiast STZ nagminnie jest LDA #$00 / STA), z seriami 32-bitowych operacji (move'ów, dodawań, odejmowań) rozbitymi bez sensu na serie rozkazów ośmiobitowych itp.

A potem konkluzja brzmi np., że "brzdou je CPU" - przy takim kodzie to nie jest wcale dziwne.

EDIT: przykład tego, o czym mowa (z pliku renderer.asm)

a) oryginał

.proc calc_nodeptr
        lda zp_nid
        sta m_a
        lda zp_nid+1
        and #$7F
        sta m_a+1
        jsr m_x4                     ; m_prod = nid*28 via shifts (= *32 - *4).
        lda m_prod        ;3
        sta m_ma          ;3
        lda m_prod+1    ;3
        sta m_ma+1      ;3           ; m_ma = nid*4
        asl m_prod        ;5
        rol m_prod+1    ;5           ; nid*8
        asl m_prod        ;5
        rol m_prod+1    ;5           ; nid*16
        asl m_prod        ;5
        rol m_prod+1    ;5           ; nid*32
        sec                    ;2
        lda m_prod        ;3
        sbc m_ma          ;3
        sta m_prod        ;3
        lda m_prod+1    ;3
        sbc m_ma+1      ;3
        sta m_prod+1    ;3           ; nid*28
        clc                      ;2
        lda m_prod        ;3
        adc #<MAP_NODES    ;2           ; MAP_NODES = offset inside the EXT bank; the
        sta zp_nodeptr   ;3           ;   readers go [zp_nodeptr],y (long indirect)
        lda m_prod+1     ;3           ;   with zp_nodeptr+2 = MAP_EXT_BANK, set ONCE
        adc #>MAP_NODES ;2           ;   by init_level -- nothing else writes +2
        sta zp_nodeptr+1 ;3 - suma: 80 cykli CPU, 46 bajtów
        rts
.endp

b) ja bym spróbował tak

.proc calc_nodeptr
        lda zp_nid
        sta m_a
        lda zp_nid+1
        and #$7F
        sta m_a+1
        jsr m_x4
        rep #$20        ;3
        lda m_prod      ;4
        sta m_ma        ;4
        asl             ;2
        asl             ;2
        asl             ;2
        sec             ;2
        sbc m_ma        ;4
        clc             ;2
        adc.w #MAP_NODES ;3 
        sta zp_nodeptr    ;4 
        sep #$20        ;3 - suma: 35 cykli CPU, 20 bajtów
        rts
.endp

PS. to m_x4 zapewne też można przyśpieszyć.

KMK
? HEX$(6670358)

36

drac030, tak, pozwoliłem AI na to spojrzeć i przyznać, że niektóre rzeczy są tam zbędne. w rzeczywistości takie zmiany w kodzie dają około −302 µs/f = +0,18% fps. jutro wydam nową wersję, a potem będę miał 10-dniową przerwę.

37

w1k napisał/a:

drac030, tak, pozwoliłem AI na to spojrzeć i przyznać, że niektóre rzeczy są tam zbędne. w rzeczywistości takie zmiany w kodzie dają około −302 µs/f = +0,18% fps.

No, cóż, pokazałem trzy miejsca, w których sekwencje rozkazów dają się skrócić aż o połowę albo o 1/3. Tylko trzy, chociaż takich miejsc jest multum, gdzie nie spojrzeć, aż się prosi, żeby to zrobić. Myślę, że, zwłaszcza w krytycznych procedurach, dałoby to mierzalny efekt. Szkoda, że nie chcesz spróbować (skłonić do tego AI).

KMK
? HEX$(6670358)

38 Ostatnio edytowany przez w1k (2026-08-31 09:17:30)

Zdecydowanie nie o to chodzi. Próbuję oszukać AI, żeby pomyślała, co piszesz, a konkretnie skopiowała i wkleiła Twoją reakcję. Pracuję nad tym, tak :)

fps 2.94 - 3.12

http://turiecfoto.sk/atari/doom-test/doom.zip

39

może wydzielisz to do osobnych plików i podasz AI z zadaniem optymalizacji, jako oddzielny projekt, albo innemu modelowi AI

*- TeBe/Madteam
3x Atari 130XE, SDX, CPU 65816, 2x VBXE, 2x IDE Plus rev. C

40

tak, robię to dokładnie tak samo. zwracam też szczególną uwagę na same pliki, używam też gemini pro i przesyłam wyniki do rozpatrzenia w opus 5, fable 5.

41 Ostatnio edytowany przez drac030 (2026-08-31 11:07:41)

w1k: wrzuć na github bieżące źródła, zanim wyjedziesz.

PS. Ten kawałek jest przecudny:

00:7408: 18        CLC
00:7409: A5 F8     LDA $F8
00:740B: 69 04     ADC #$04
00:740D: 8D B8 0E  STA $0EB8
00:7410: A5 F9     LDA $F9
00:7412: 69 00     ADC #$00
00:7414: 8D B9 0E  STA $0EB9
00:7417: 4E B9 0E  LSR $0EB9
00:741A: 6E B8 0E  ROR $0EB8
00:741D: 4E B9 0E  LSR $0EB9
00:7420: 6E B8 0E  ROR $0EB8
00:7423: 4E B9 0E  LSR $0EB9
00:7426: 6E B8 0E  ROR $0EB8
00:7429: AD B8 0E  LDA $0EB8
00:742C: 0D B9 0E  ORA $0EB9
00:742F: D0 03     BNE $7434
00:7431: EE B8 0E  INC $0EB8
00:7434: A9 08     LDA #$08
00:7436: 8D B7 0E  STA $0EB7
00:7439: AD A7 0E  LDA $0EA7
00:743C: D0 26     BNE $7464
00:743E: AD A6 0E  LDA $0EA6
00:7441: C9 41     CMP #$41
00:7443: B0 1F     BCS $7464
00:7445: A9 01     LDA #$01
00:7447: 8D B7 0E  STA $0EB7
00:744A: 4E B9 0E  LSR $0EB9
00:744D: 6E B8 0E  ROR $0EB8
00:7450: 4E B9 0E  LSR $0EB9
00:7453: 6E B8 0E  ROR $0EB8
00:7456: 4E B9 0E  LSR $0EB9
00:7459: 6E B8 0E  ROR $0EB8
00:745C: AD B8 0E  LDA $0EB8
00:745F: D0 03     BNE $7464
00:7461: EE B8 0E  INC $0EB8
00:7464: A9 00     LDA #$00
00:7466: 85 EF     STA $EF
00:7468: 85 F0     STA $F0
00:746A: A9 01     LDA #$01
00:746C: 85 F1     STA $F1
00:746E: AD A8 0E  LDA $0EA8
00:7471: 85 F6     STA $F6
00:7473: AD A9 0E  LDA $0EA9
00:7476: 85 F7     STA $F7

Tak poza wszystkim, ten model AI jest chyba przekonany, że zapisanie akumulatora do pamięci przez STA powoduje utratę jego zawartości. Stąd numery typu LDA $1361 / STA $1354 / LDA $1354, albo STA $0EB9 / LSR $0EB9 itp.

Jest też odporny na zwiększanie akumulatora przez INC (zamiast CLC / ADC #$01), zmniejszanie go przez DEC (zamiast SEC / SBC #$01) i przeważnie na zerowanie komórek pamięci przez STZ (prawie wszędzie wali LDA #$00 / STA).

KMK
? HEX$(6670358)

42

a nie możesz tych wytycznych które podał ci drac030 wprowadzić jako skill? Bo to przecież normalne żeby go uczyć tego jak ma pisać. i dokładnie opus czy fable radzi sobie z tym idealnie.

kupię Atari 815 i 820 :)

43 Ostatnio edytowany przez w1k (2026-08-31 13:09:23)

ok, tu: http://turiecfoto.sk/atari/doom-test/doom31-08-2026.zip

github aktualny

F - FPS count

44 Ostatnio edytowany przez drac030 (2026-08-31 13:23:27)

Jeszcze się przyczepię, bo to trochę pokazuje, jak u tego całego Claude'a jest z myśleniem, a tym samym, z jakością kodu. Mamy takie coś:

00:E9EA:    REP #$20
            LDA $D1
            AND #$7FFF
            ASL
            ASL
            CLC
            ADC #$2C74
            STA $84
            SEP #$20
            LDY #$00
            LDA [$84],Y
            STA $E7
            INY
            LDA [$84],Y
            STA $E8

Jak widać, wersja testowa w końcu używa 16-bitowego akumulatora (i robi to dużo częściej niż poprzednia, naliczyłem 47 wystąpień rozkazu rep #$20). I bardzo dobrze. Ale byłoby lepiej, gdyby to było robione z głową:

1) rozkaz AND #$7FFF jest w ogóle niepotrzebny, a zajmuje 3 bajty i 3 cykle
2) dalej mamy przełączenie na 8-bitowy akumulator (SEP #$20), po czym kod radośnie pobiera z pamięci 16-bitowe słowo bajt po bajcie i takoż bajt po bajcie odkłada je do dwóch kolejnych komórek pamięci.

Powinno być tedy:

00:E9EA:    REP #$20
            LDA $D1
            ASL
            ASL
            CLC
            ADC #$2C74
            STA $84
            LDA [$84]
            STA $E7
            SEP #$20

Oszczędza się 10 bajtów i 15 cykli, głównie dzięki przestawieniu jednego rozkazu w inne miejsce.

Dalej idzie wywołanie podprogramu, który: a) kopiuje owo $E7-$E8 do $EF-$F0, oczywiście znowu bajt po bajcie, robiąc jednocześnie mnożenie przez 8 przez trzykrotne przesunięcie w lewo, oczywiście też bajt po bajcie (tym razem przynajmniej pierwsze przesunięcie robi razem z kopiowaniem, brawo; ale resztę już na pamięci, niebrawo). Chociaż można to zrobić tak:

00:E9EA:    REP #$20
            LDA $D1
            ASL
            ASL
            CLC
            ADC #$2C74
            STA $84
            LDA [$84]
            STA $E7
            ASL
            ASL
            ASL
            STA $EF           
            SEP #$20

W następnym kroku do obliczonej wartości trzeba dodać 256 i zapisać ją pod $BF-$C0. Kod:

            CLC
            LDA $EF
            ADC #$00
            STA $BF
            LDA $F0
            ADC #$01
            STA $C0

Chociaż wystarczyłoby tak:

00:E9EA:    REP #$20
            LDA $D1
            ASL
            ASL
            CLC
            ADC #$2C74
            STA $84
            LDA [$84]
            STA $E7
            ASL
            ASL
            ASL
            STA $EF
            CLC
            ADC #$0100
            STA $BF          
            SEP #$20

Oryginał: 36 rozkazów (w tym dwie pary JSR/RTS), 67 bajtów, 130 cykli CPU.

Modyfikacja: 17 rozkazów, 29 bajtów, 53 cykle CPU. Przy czym STA $E7 może być w ogóle niepotrzebne, jeśli tak, to 16 rozkazów, 27 bajtów, 49 cykli.

KMK
? HEX$(6670358)

45 Ostatnio edytowany przez w1k (2026-08-31 14:47:48)

wielkie dzięki

http://turiecfoto.sk/atari/doom-test/doom31-8-2026b.zip
http://turiecfoto.sk/atari/doom-test/doom31-8-2026c.zip

46 Ostatnio edytowany przez drac030 (2026-08-31 21:55:31)

Ostatnia dzisiejsza wersja ma błąd. Krok po kroku:

1) ładujemy całość
2) przechodzimy do menu
3) wybieramy New game
4) wybieramy którykolwiek z epizodów, np. nr 3, wciskamy Return
5) robimy parę kroków
6) wciskamy Esc, żeby wrócić do menu
7) wybieramy New game - już w tym momencie panel na dole zamienia się w kaszkę
8) wybieramy inny epizod, np. nr 2, wciskamy Return (panel się odtwarza)
9) robimy parę kroków
10) wciskamy Esc, żeby wrócić do menu
11) wybieramy New game (panel = kaszka)
12) wybieramy epizod nr 1, wciskamy Return - w tym mniej więcej momencie następuje zwis, program przestaje reagować na klawiaturę i joystick

https://www.atari.org.pl/forum/misc.php?action=pun_attachment&amp;item=13802

Post's attachments

doom_zwis.png 39.37 kb, nikt jeszcze nie pobierał tego pliku. 

Tylko zalogowani mogą pobierać załączniki.
KMK
? HEX$(6670358)

47 Ostatnio edytowany przez w1k (2026-08-31 22:53:04)

Już czekam na samolot ..

48

pamiętaj żeby przy odprawie zażartować że masz bombę w plecaku... wtedy widzimy się wkrótce

*- TeBe/Madteam
3x Atari 130XE, SDX, CPU 65816, 2x VBXE, 2x IDE Plus rev. C

49 Ostatnio edytowany przez Jacques (2026-09-01 10:32:27)

Przed żartem może wklepać IDDQD i go nie ruszą ;-)
Swoją drogą to kody mogłyby działać, choćby te podstawowe:  IDDQD oraz IDKFA

50 Ostatnio edytowany przez drac030 (2026-09-08 10:59:49)

Pozwoliłem sobie w sposób bardziej systematyczny posiedzieć nad kodem źródłowym, bo, szczerze mówiąc, kiedy patrzyłem na ten program pod disasemblerem, robiło mi się gorzej. Przykłady były powyżej, ale zasadniczo tak samo jest wszędzie.

Zrewidowałem ręcznie 17 modułów, które załączam. Kodu nie kompilowałem, zatrudniłem tylko Gemini, żeby sprawdził go pod względem formalnym. Co zrobił i twierdzi, że jest OK, ale wiadomo, że to nie musi być prawda.

Wg jego oceny zmiany mają spowodować zaoszczędzenie ok. 1,7 KB pamięci oraz ok. 450 tys. cykli czasu renderowania klatki, czyli, znowu wg jego oceny, ok. 11% tegoż czasu. Czy te szacunki są poprawne, i czy w ogóle cokolwiek tu jest poprawne, powinno wyjść w praniu. Proponuję moduły dołączać do projektu po kolei i sprawdzać za każdym razem, czy się buduje i działa. Jeśli nie, zatrudnić AI do poprawek.

EDIT: zapomniałem napisać, zmiany wprowadzone są w blokach .if 1 / .else / .endif, gdzie w sekcji od .if 1 do .else znajduje się kod poprawiony, natomiast w sekcji .else / .endif - kod oryginalny. Można więc sobie na bieżąco porównywać wersję nową ze starą.

Mam nadzieję, że, jeśli się to przyda do czegokolwiek, to przynajmniej do tego, żeby Claude nauczył się korzystać z rozkazów DEC, INC, STZ, BRA, XBA, PHX, PHY, PLX, PLY, PEA, pseudorozkazów Jcc, pośrednich trybów adresowania bez indeksu, no i, rzecz jasna, przeprowadzania złożonych obliczeń rozkazami 16-bitowymi w akumulatorze, a nie 8-bitowymi całkowicie w pamięci (zwłaszcza dotyczy serii par ASL aaa/ROL aaa+1).

To jest jedna sprawa. Druga sprawa: odniosłem wrażenie, że dość kluczowy dla ogólnej wydajności renderowania klatek jest moduł math.asm, a zwłaszcza znajdujące się w nim procedury mnożenia i dzielenia.

Otóż Antonia II ma zaimplementowane mnożenie i dzielenie 16-bitowych int-ów bez znaku w sprzęcie. Jeśli prawdą jest to, co można wywnioskować z komentarzy umieszczonych w kodzie źródłowym, że rendering jednej klatki używa setek i tysięcy mnożeń tudzież dzieleń, przypuszczam, że zamiana procedur kalkulujących to na piechotę na wspomagane sprzętowo powinna dać zauważalny zysk w płynności działania programu.

EDIT 2: usunąłem załącznik, nowsza wersja w poście poniżej.

KMK
? HEX$(6670358)