tak sobie dzisiaj z Perinoidem porównywaliśmy wydajność prostego kodu w C i Action!

// powiel 40 bajtow cc65
    for(i=1; i<192; i++) {
        memcpy(ptr, video_ptr, 40);
        ptr+=40;
    }
; powiel 40 bajtow Action
FOR i=1 TO 192
   DO
          moveblock(ptr, video_ptr, 40)
          SCREEN==+40
   OD

dla ułatwienia - te same zmienne, typy etc. moveblock robi to samo co memcpy - czyli kopiuje zadaną liczbę bajtów na docelowe miejsce z wskazanego miejsca. Kopiowanie linii danych w pamięci ekranu - no i wydajnościowo - mówimy o mikroułamkach sekund, ale licząc ramki ekranu na grabberze to Action! robi to dokładnie dwa razy dłużej (0.2 sek. vs 0.1 sek.).

Pytanie - czy da się to szybciej w Action?

/|\ 800 Incognito+Supercard - 800XL - 1088XEL CF3 - XE GS Ultimate VBXE - SIO2SD - SIDE2 - CA2001 - 1050 - XF551 clone by Zaxon /|\ PORTFOLIO

2

kod memcpy CC65 jest mocno optymalizowany, korzystam z niego w MP (MadPascal)

; Ullrich von Bassewitz, 2003-08-20
; Performance increase (about 20%) by
; Christian Krueger, 2009-09-13

.proc    @moveu            ; assert Y = 0

ptr1    = edx
ptr2    = ecx
ptr3    = eax

    stx @sp

    ldy    #0

    ldx     ptr3+1        ; Get high byte of n
    beq     L2        ; Jump if zero

L1:     .rept 2            ; Unroll this a bit to make it faster...
    lda     (ptr1),Y    ; copy a byte
    sta     (ptr2),Y
    iny
    .endr

    bne     L1
    inc     ptr1+1
    inc     ptr2+1
    dex            ; Next 256 byte block
    bne    L1        ; Repeat if any

    ; the following section could be 10% faster if we were able to copy
    ; back to front - unfortunately we are forced to copy strict from
    ; low to high since this function is also used for
    ; memmove and blocks could be overlapping!
    ; {
L2:                ; assert Y = 0
    ldx     ptr3        ; Get the low byte of n
    beq     done        ; something to copy

L3:     lda     (ptr1),Y    ; copy a byte
    sta     (ptr2),Y
    iny
    dex
    bne     L3

    ; }

done    ldx #0
@sp    equ *-1
    rts
.endp


@move    .proc (.word ptr1, ptr2, ptr3) .var

ptr1    = edx
ptr2    = ecx
ptr3    = eax

src    = ptr1
dst    = ptr2
cnt    = ptr3

    cpw ptr2 ptr1
    scs
    jmp @moveu

    stx @sp

; Copy downwards. Adjust the pointers to the end of the memory regions.

    lda     ptr1+1
    add     ptr3+1
    sta     ptr1+1

    lda     ptr2+1
    add     ptr3+1
    sta     ptr2+1

; handle fractions of a page size first

    ldy     ptr3        ; count, low byte
    bne     @entry        ; something to copy?
    beq     PageSizeCopy    ; here like bra...

@copyByte:
    lda     (ptr1),y
    sta     (ptr2),y
@entry:
    dey
    bne     @copyByte
    lda     (ptr1),y    ; copy remaining byte
    sta     (ptr2),y

PageSizeCopy:            ; assert Y = 0
    ldx     ptr3+1        ; number of pages
    beq     done        ; none? -> done

@initBase:
    dec     ptr1+1        ; adjust base...
    dec     ptr2+1
    dey            ; in entry case: 0 -> FF
    lda     (ptr1),y    ; need to copy this 'intro byte'
    sta     (ptr2),y    ; to 'land' later on Y=0! (as a result of the '.repeat'-block!)
    dey            ; FF ->FE
@copyBytes:
    .rept 2            ; Unroll this a bit to make it faster...
    lda     (ptr1),y
    sta     (ptr2),y
    dey
    .endr
@copyEntry:            ; in entry case: 0 -> FF
    bne     @copyBytes
    lda     (ptr1),y    ; Y = 0, copy last byte
    sta     (ptr2),y
    dex            ; one page to copy less
    bne     @initBase    ; still a page to copy?

done    ldx #0
@sp    equ *-1
    rts
.endp
*- TeBe/Madteam
3x Atari 130XE, SDX, CPU 65816, 2x VBXE, 2x IDE Plus rev. C

3

robiłem też inne testy, i wyszło że zwykła pętla kopiująca musiałaby minimum po 4 bajty na raz kopiować aby prawie dorównać temu kodowi z cc65, w tym stylu

 lda (src),y
 sta (dst),y
 iny
 lda (src),y
 sta (dst),y
 iny
 lda (src),y
 sta (dst),y
 iny
 lda (src),y
 sta (dst),y
 iny
*- TeBe/Madteam
3x Atari 130XE, SDX, CPU 65816, 2x VBXE, 2x IDE Plus rev. C

4 Ostatnio edytowany przez tooloudtoowide (2020-01-23 19:27:21)

aż odpalę zliczanie z zegarka, bo nie widzę po rysowaniu w pamięci, żeby to 4x szybciej było - ale dzięki za podpowiedź, muszę zmajstrować tak jak myślałem własną prockę do tego.

Oryginalnie zrobili to tak:

 PROC MoveBlock=*(BYTE POINTER d,s,CARD sz)
[$A085$A186$A284$A0$0$A5A5$16F0$A2B1$A091$C8$F9D0$A1E6$A3E6$A5C6$F1
D0$5F0$A2B1$A091$C8$A4C4$F7D0$60]
$664E P_MOVEBLOCK STA FRET
            STX FRET+1
STY BPTR2
LDY #$00
LDA L00A5
BEQ L6670
LDA (BPTR2),Y  
STA (FRET),Y
INY
BNE L665A
INC FRET+1
INC L00A3
DEC L00A5
BNE L665A
BEQ L6670
L666B       LDA (BPTR2),Y  
STA (FRET),Y
            INY
L6670       CPY L00A4
BNE L666B 
RTS
/|\ 800 Incognito+Supercard - 800XL - 1088XEL CF3 - XE GS Ultimate VBXE - SIO2SD - SIDE2 - CA2001 - 1050 - XF551 clone by Zaxon /|\ PORTFOLIO

5 Ostatnio edytowany przez qbahusak (2020-01-24 10:46:35)

tooloudtoowide napisał/a:

Pytanie - czy da się to szybciej w Action?

Bez stosowania szczególnych rozwiązań - nie. Szczególne rozwiązanie to podmienić moveblock na to memcpy z cc65, i będzie tak samo szybko, lub napisać szybką procedurę "blit", która pobierze dodatkowe parametry i mieć możliwość kopiowania prostokąta za jednym wywołaniem.

Trzeba pamiętać, że protokół wywołania procedury w action różni się w zal. od liczby bajtów parametrów: do trzech bajtów parametrów - rejestry  axy. Powyżej - przez komórki pamięci na stronie zerowej (a już nie przez rejestry).

6 Ostatnio edytowany przez tooloudtoowide (2020-01-24 13:45:02)

dzięki Kuba - z tym prostokątem to czytasz mi w myślach :)

a punkt odniesienia i moje nieśmiałem próbki w Action! tutaj:
http://tooloudtoowide.marcinrusinowski. … vs-action/

/|\ 800 Incognito+Supercard - 800XL - 1088XEL CF3 - XE GS Ultimate VBXE - SIO2SD - SIDE2 - CA2001 - 1050 - XF551 clone by Zaxon /|\ PORTFOLIO

7 Ostatnio edytowany przez zbyti (2021-04-25 23:42:05)

TDC po 30 latach dokonał wiekopomnego odkrycia a ja to opisałem rok temu w poście 48 https://atarionline.pl/forum/comments.p … e=1#Item_0 po 2-mc zabawy ;)

DEFINE
  RBARON="[$A9$E$8D$D40A$8D$D01A]",RBAROFF="[$A9$0$8D$D01A]"

BYTE ARRAY MATRIX=0
BYTE ARRAY MEMMATRIX(21)

CARD
  MEMADDR=$CA

BYTE
  I=$CC

PROC RSYNC=*(BYTE L)[$CD$0B$D4$D0$FB$60]

PROC OLDSTUFF=*()
  FOR I=0 TO 20 DO
    MATRIX(MEMADDR)=255
    MEMADDR==+1
  OD
RETURN

PROC NEWSTUFF=*()
  FOR I=0 TO 20 DO
    MEMMATRIX(I)=255
  OD
RETURN

PROC MAIN=*()

  MEMMATRIX^=$9000

  DO
    MEMADDR=$9000
    RSYNC(40)
    RBARON OLDSTUFF() RBAROFF

    RSYNC(80)
    RBARON NEWSTUFF() RBAROFF
  OD

RETURN
Post's attachments

atari000.png 1.34 kb, nikt jeszcze nie pobierał tego pliku. 

Tylko zalogowani mogą pobierać załączniki.

8

Oj, coś mi tu śmierdzi wojną polsko-polską a nie wojenka A8 i C= :-)

https://systemembedded.eu/ ... https://www.youtube.com/watch?v=GwS7Es1x6mw
""Ja bardzo przepraszam, ale podejrzenia panów są całkowicie bezpodstawne. Ja niczym nie handluję. Ta pani przyszła do mnie w tym Pancake-u i w nim wychodzi.""
ABBUC Member #319. Preferowana forma kontaktu: email

9 Ostatnio edytowany przez zbyti (2021-04-26 08:49:52)

A gdzie tam... Skoro ten trick jest taki wiekopomny a TDC ociąga się z jego udokumentowaniem to "na każdym zebraniu jest taka sytuacja, że ktoś musi zacząć pierwszy". :D

10

boje sie zapytac... ktos zauwazyl roznice miedzy trybem indeksowanym i posrednim indeksowanym? bo jesli tak czekam na odkrycie operacji dodawania.

http://atari.pl/hsc/ad.php?i=1.

11 Ostatnio edytowany przez zbyti (2021-04-26 09:51:07)

@xxl

OLDSTUFF()

0E25: A0 00     LDY #$00
0E27: 84 CC     STY $CC
0E29: A9 14     LDA #$14
0E2B: C5 CC     CMP $CC
0E2D: B0 03     BCS $0E32
0E2F: 4C 52 0E  JMP $0E52
0E32: 18        CLC
0E33: AD 08 0E  LDA $0E08
0E36: 65 CA     ADC $CA     ;LOADFLG
0E38: 85 AE     STA $AE     ;LELNUM+1
0E3A: AD 09 0E  LDA $0E09
0E3D: 65 CB     ADC $CB
0E3F: 85 AF     STA $AF     ;STENUM
0E41: A9 FF     LDA #$FF
0E43: A0 00     LDY #$00
0E45: 91 AE     STA ($AE),Y ;LELNUM+1
0E47: E6 CA     INC $CA     ;LOADFLG
0E49: D0 02     BNE $0E4D
0E4B: E6 CB     INC $CB
0E4D: E6 CC     INC $CC
0E4F: 4C 29 0E  JMP $0E29
0E52: 60        RTS

NEWSTUFF()

0E53: A0 00     LDY #$00
0E55: 84 CC     STY $CC
0E57: A9 14     LDA #$14
0E59: C5 CC     CMP $CC
0E5B: B0 03     BCS $0E60
0E5D: 4C 6C 0E  JMP $0E6C
0E60: A9 FF     LDA #$FF
0E62: A6 CC     LDX $CC
0E64: 9D 0A 0E  STA $0E0A,X
0E67: E6 CC     INC $CC
0E69: 4C 57 0E  JMP $0E57
0E6C: 60        RTS

Trzeba by przykład w Action! dopracować, ale nie będę na to czasu poświęcał bo dokładnie o to chodzi.

MEMMATRIX^=$9000

Nie pisałem już dawno w Action! na to miałem jakieś obejście ale już nie pamiętam, po prostu jak się to zrobi tak by strzelało w $9000 to dokładnie chodzi o to co piszesz.

12

jak sie czyta zrodla co on generuje... nie da sie uratowac tego kompilatora

http://atari.pl/hsc/ad.php?i=1.

13

Już wiem:

SET $E=$2000 SET $491=$2000

DEFINE
  RBARON="[$A9$E$8D$D40A$8D$D01A]",RBAROFF="[$A9$0$8D$D01A]"

BYTE ARRAY MATRIX=0
BYTE ARRAY MEMMATRIX(21)=$9000

CARD
  MEMADDR=$CA

BYTE
  I=$CC

PROC RSYNC=*(BYTE L)[$CD$0B$D4$D0$FB$60]

PROC OLDSTUFF=*()
  FOR I=0 TO 20 DO
    MATRIX(MEMADDR)=255
    MEMADDR==+1
  OD
RETURN

PROC NEWSTUFF=*()
  FOR I=0 TO 20 DO
    MEMMATRIX(I)=255
  OD
RETURN

PROC MAIN=*()

  DO
    MEMADDR=$9000
    RSYNC(40)
    RBARON OLDSTUFF() RBAROFF

    RSYNC(80)
    RBARON NEWSTUFF() RBAROFF
  OD

RETURN

------------

BYTE ARRAY MEMMATRIX(21)=$9000
PROC NEWSTUFF=*()
  FOR I=0 TO 20 DO
    MEMMATRIX(I)=255
  OD
RETURN
2036: A0 00     LDY #$00
2038: 84 CC     STY $CC
203A: A9 14     LDA #$14
203C: C5 CC     CMP $CC
203E: B0 03     BCS $2043
2040: 4C 4F 20  JMP $204F
2043: A9 FF     LDA #$FF
2045: A6 CC     LDX $CC
2047: 9D 00 90  STA $9000,X
204A: E6 CC     INC $CC
204C: 4C 3A 20  JMP $203A
204F: 60        RTS

14

Język wysokiego poziomu (ACTION!) powstał aby skrócić pisanie programów. To co robisz jest w procedurach bibliotecznych języka. Z ciekawości dołączyłem do twojego testu taką procedurę żeby sprawdzić ile zajmuje czasu.
Jeżeli jest za długa, to jak widzę nieźle sobie radzisz z wstawkami maszynowymi i na pewno możesz napisać własną.


SET $E=$2000 SET $491=$2000

DEFINE
  RBARON="[$A9$E$8D$D40A$8D$D01A]",RBAROFF="[$A9$0$8D$D01A]"

BYTE ARRAY MATRIX=0
BYTE ARRAY MEMMATRIX(21)=$9000

CARD
  MEMADDR=$CA

BYTE
  I=$CC

PROC RSYNC=*(BYTE L)[$CD$0B$D4$D0$FB$60]

PROC OLDSTUFF=*()
  FOR I=0 TO 20 DO
    MATRIX(MEMADDR)=255
    MEMADDR==+1
  OD
RETURN

PROC NEWSTUFF=*()
  FOR I=0 TO 20 DO
    MEMMATRIX(I)=255
  OD
RETURN

PROC MAIN=*()

  DO
    MEMADDR=$9000
    RSYNC(40)
    RBARON OLDSTUFF() RBAROFF

    RSYNC(80)
    RBARON NEWSTUFF() RBAROFF

    RSYNC(100)
    RBARON
    SETBLOCK(MEMMATRIX,20,255)
    RBAROFF
  OD  

RETURN

PS.
Życzę dużo satysfakcji w poznawaniu 8-bitowców, powodzenia w budowie i tworzeniu gier.

15 Ostatnio edytowany przez zbyti (2021-04-27 13:13:45)

supaplex napisał/a:

To co robisz jest w procedurach bibliotecznych języka.

Ja ich celowo nie używam lub dołączam jako własny runtime aby po zapisaniu programu do XEX nie był potrzebny cartridge Action! w komputerze.

Do tego napisałem tak jak napisałem bo to narzucił artykuł TDC https://tdc-smakowitosci.blogspot.com/2 … ction.html

TDC napisał/a:

Korzystaliśmy z tego rozwiązania latami, będąc przekonanymi, że nie ma w żadnym języku czegoś szybszego i bardziej sprytnego;)

(...)

Okazało się, że myk jaki wymyśliłem - Action! kompiluje do 5 bajtów kodu dla stałej i do 8 bajtów przy zmiennym adresie (animacji). Jest to najmniejszy rozmiar kodu jaki da się wygenerować, więc krócej i szybciej na Atari się już nie da;))

Coś niesamowitego, naprawdę sądziłem przez kilkadziesiąt lat, że szybciej się już nie da... A jednak!;)

Sednem tego artykułu nie jest wypełnienie pamięci jakąś jedną wartością tylko wymuszenie szybkiego trybu indeksowego. TDC SETBLOCK używa od zawsze, nie o to chodzi.

Jak pokazałem rok temu na AOL ta metoda pozwala także na osiągnięcie upragnionego LDA/STA w miejsce PEEK i POKE.

---

TDC napisał/a:

Wrato zaznaczyć, że do dziś wszyscy pamiętają, że Action! to znaczy szybkość i że nie ma możliwości odnalezienia innego języka, który byłby prawie tak szybki jak asembler.

xxl napisał/a:

jak sie czyta zrodla co on generuje... nie da sie uratowac tego kompilatora

16 Ostatnio edytowany przez zbyti (2021-04-27 23:39:40)

Widzę, że Tomek nie odpuszcza i wyzwanie wciąż "aktualne" ;)

Widocznie przedstawienie przeze mnie idei (i sposobu jak to osiągnąć w Action!), którą praktycznie od razu odgadł Ilmenit patrząc na raster time nie wystarczy.

Ilmenit napisał/a:

3. Nie patrzyłem w wynikowy kod, ale twoje "odkrycie" to prawdopodobnie wygenerowanie dostępu do tablicy w trybie adresowania "Absolute Indexed", co wcześniej nie działało, ponieważ inkrementowałeś dwubajtowy wskaźnik a teraz masz stałą. Zakładam, że podobny efekt można uzyskać w wielu kompilatorach z tamtego okresu, bo nie ma powodu, aby nie można było.

Może trzeba podać dokładne rozwiązanie?

BYTE ARRAY FastP(0)=$9000

Tak, każdy wie, że Action! nie pilnuje zakresu tablic :]

Na podstawie snippetów z wpisu TDC na blogu obaj mamy szybką tablicę bajtów, obaj mamy takie same raster time dla tego kodu ale Tomek to robi inaczej?

17

TeDeC tu nie pisze już.

18 Ostatnio edytowany przez zbyti (2021-04-28 09:57:32)

@AS... doskonale o tym wiem, ale stosuję erystyczną sztuczkę "gadki pod publiczkę" ;)

Ja jestem z tych sofistów co otwarcie mówią jakie metody stosują, tyle, że ja dążę do prawdy a nie do tego by moje było na wierzchu :]

--- ed ---

TDC napisał, że zawstydziłem Ilmenita. Ja osobiście nie bardzo wiem gdzie. Jeżeli ktoś byłby łaskaw przykleić moje stanowisko na forum AOL to brzmi ono:

zbyti napisał/a:

TDC przestań robić wyzwania programistyczne w Action! Ilmenitowi. Dla każdego znającego jego osiągnięcia jest jasne, że gdyby Ilmenit uznał to za istotne to zmusił by kompilator Action! do prania jego starych gaci w rzece i jednoczesnego śpiewania przy tym międzynarodówki :]