1

Mam kilka pytan odnosnie 65816, liczylem ze odpowie na nie Laoo jako ze juz cos napisal dla 816, ale widocznie jest tak zapracowany ze nie odpowie :). Teraz wiec licze na to ze znajdzie sie kilka osob na aarrea ktore programowaly na 816 i udziela odpowiedzi na n/w pytania.

1. Jak to jest aktualnie i czy bedzie mozliwe gdy dopalka Pasia ujrzy swiatlo dzienne, konkretnie chodzi o adresowanie 24 bitowe:

[zp] - strony zerowej pośredni długi - jak wyżej, jednak pobierany ze strony zerowej adres jest 24-bitowy.

[zp],Y - strony zerowej pośredni długi postindeksowany - tak, jak (zp),Y tylko z 24-bitowym adresem na stronie zerowej.

[abs] - pośredni długi - jak (abs) tyle tylko, że adres jest 24-bitowy.

long - absolutny długi - argumentem jest 24-bitowy adres.

long,X - absolutny długi indeksowany

Czy wogole mozna uzywac trybu [] lub long piszac program dla 65816,nie majac pamieci widzianej jako ciagly obszar. Czy w tym adresowaniu najstarszy bajt to kod banku pamieci, czyli czy mozna by wpisac adres kod_banku$4000..$7FFF np. "lda $835000" bo wtedy nie trzeba by miec pamieci zorganizowanej liniowo tylko sprytniejszy asembler.

2. Jak w asemblerze dla 65816 zapisac ten tryb adresowania:

ds,S - wskaznika stosu z przesunięciem - ośmiobitowa dana natychmiastowa ds jest dodawana do wartości wskaĽnika stosu. Tryb ten pozwala na adresowanie 256 bajtów wewnątrz stosu, licząc od jego szczytu.

(ds,S),Y - wskaznika stosu z przesunięciem pośredni indeksowany - do adresu pobranego z miejsca wskazanego przez ds,S dodawana jest wartość rejestru Y. Pozwala to na trzymanie wektorów na stosie, jeśli gdzie indziej nie ma miejsca.

czy asembler rozpoznaje jakies wyrazenia kluczowe 'ds' i 'S'

i w kodzie programu piszemy lda ds,S ?

3. Czy asembler dla 65816 rozpoznaje wartosc rejestru D, ktory okresla adres strony zerowej, tak aby podczas asemblacji odwolania do nowo ustawionej strony zerowej byly zasemblowane jako 2-bajtowe rozkazy a nie 3-y bajtowe.

Moze mi ktos przedstawic przyklad programu w ASM ze zmiana wartosci rejestru D i odwolanie do tak nowo ustawionej strony zerowej ?

4. Jakiego asemblera uzywal Laoo do napisania benchmarka porownujacego 6502 i 816 ?

5. Jak realizowana jest obsluga makr w asemblerach ?

Czy po napotkaniu komendy .MACRO nastepuje przepisanie zawartosci takiego makra gdzies do wydzielonego obszaru pamieci, aby pozniej podczas dalszej asemblacji tylko odwolywac sie w ten obszar i ciagle go asemblowac, czy tez zapamietac w tym obszarze dane zamienione na jakies symbole (tokeny) i potem je juz szybciej interpretowac, a moze zawartosc makra jest wysylana do pliku zewnetrznego pozniej po napotkaniu odwolania do makra wywolywana jest asemblacja pliku z makrem i parametrami ?

Wiadomo ze kazdy moze napisac sobie obsluge makr po swojemu, ale chcialbym sie dowiedziec jak to jest robione "zwyczajowo", jako ze wczesniej nie mialem okazji zetknac sie z takim zadaniem.

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

2

Odpowiedzi na temat adresowania znajdziesz w artykule Procesor MOS 65C816 w dziale Artykuły

Długie (24-bitowe) tryby adresowania tyczą się TYLKO i WYŁĄCZNIE pamięci liniowej. Skąd procesor ma wiedzieć, że masz jakieś banki pamięci w obszarze $4000-$7FFF?

W 65c816 najstarsze osiem bitów szyny adresowej pokrywa się z szyną danych (8-bit). Podczas odwołań 24-bitowych na szynie danych pojawia się najpierw najstarszy bajt adresu a później dane (pisał o tym Draco kilka dni temu). Sęk w tym, że nie za bardzo da się odróżnić dane od adresu na szynie danych. Chyba. :) I nie jest to kwestia "sprytniejszego" asembera, tylko sprzętu. Jako koder powinieneś to wiedzieć.

MAE rozpoznaje tylko S jako wskaźnik stosu. ds jest takim samym oznaczeniem jak zp czy abs i jest po prostu skrótem od bodajże displacement.

Asembler nie miesza się do rejestru D. Jak napiszesz LDA $23, to CPU dorzuci do tego jeszcze wartość D i z tak otrzymanego adresu pobierze wartość. Np. D=$DF34, procesor wykonuje rozkaz LDA $47, wtedy pobrany zostanie bajt spod $DF7B w 3 cykle. Jeśli podasz LDA $DF7B, to odczyt nastąpi z tego samego adresu ale w 4 cykle, niezależnie od tego, czy D będzie wskazywał w tym miejscu stronę zerową.

Oto przykład zmiany adresu strony zerowej:

    .816         ; jedyne info dla asemblera, że może natknąć sie na rozkazy i tryby adresowania 816
    CLC         ; przełączenie procesora w tryb natywny (65c816)
    XCE
    .AW         ; przełączenie akumulatora w tryb 16-bit (info tylko dla MAE, to nie jest rozkaz procesora)
    REP #$20    ; akumulator i odwołania do pamięci 16-bitowe
    LDA #zp_ptr ; wskaźnik "nowej" strony 0
    TCD         ; przeniesienie akumulatora do D
    SEP #$20    ; akumulator i odwołania do pamięci 8-bitowe
    .AB         ; przełączenie akumulatora w tryb 8-bit (info tylko dla MAE, to nie jest rozkaz procesora)
    SEC         ; przełączenie procesora w tryb emulacji (65c02)
    XCE

4. Jakiego asemblera uzywal Laoo do napisania benchmarka porownujacego 6502 i 816 ?

Może MAE? Jako jedyny wspiera 65c816.

Makra działają tak samo jak #include w C/C++. Kawałek kodu makra wstawiany jest w miejsce odwołania do niego, z czego nazwy parametrów zastępowane są ich wartościami. Najlepiej zrozumieć to na przykładzie:

!!!ldreg .MD     ; załadowanie wartości do wskazanego rejestru
    LD:1 :2 ; brak odstępu pomiędzy LD a :1!!!
    .EM     ; o ile dobrze pamiętam mnemonik, chodzi o zamknięcie definicji makra

Wywołujemy makro:

    LDREG a $20
    LDREG x #%1111

Asembler najpierw zamieni powyższy fragment na:

    LDa $20
    LDx #%1111

a następnie zasembluje, to co stworzył. ;)

Wszystkie powyższe dywagacje na podstawie arta wymienioinego na wstępie, doświadczeń Draco i własnych oraz dokumentacji do MAE. :)

Zawsze mam rację, tylko nikt mnie nie słucha.

3

Może MAE? Jako jedyny wspiera 65c816.

.. nie MAE. Mówił coś o jakimś krosie - wydaje mi się, że na grzybie - i to jest dla mnie dziwne ..

Kontakt: pin@usdk.pl

4

No tak, zapomnialem, ze jest jakis crossasm do 65816.

Tebe: na przyszlosc, jak czytasz manuale, to staraj sie cos z nich zrozumiec, bo twoj post swiadczy tylko o czyms zupelnie przeciwnym. :(

Zawsze mam rację, tylko nikt mnie nie słucha.

5

moj post swiadczy o tym ze przeczytalem manuala (bo skad niby skopiowalem te fragmenty dotyczace adresacji), ale nie zauwazylem w nim praktycznego zastosowania teorii

moj post swiadczy o tym, ze nie pisalem nic dla 816 i nie uzywalem MAE

moj post swiadczy o tym, ze kazdy moze inaczej zinterpretowac manuala, szczegolnie jesli nie moze podeprzec sie przykladem, bo sucha teoria to nie wszystko

pozatym gdybys dokladniej doczytal pytanie dotyczace makr moze zrozumialbys ze nie chodzilo mi o to o czym napisales (o tym juz bylo kiedys w moich wczesniejszych pytaniach i zdaje sie ze najpełniej udzielil na nie odpowiedzi Pecus), ale i tak dziekuje ze poswieciles czas

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

6

Panowie - bez nerwów - zaznaczam - to tylko 65c816 ...  :)

Kontakt: pin@usdk.pl

7

moj post swiadczy o tym ze przeczytalem manuala (bo skad niby skopiowalem te fragmenty dotyczace adresacji), ale nie zauwazylem w nim praktycznego zastosowania teorii

To co powyżej napisałeś, że nie czytasz jednak uważnie. Nie napisałem, że nie czytałeś. Cytaty poznałem od razu, choć ostatni raz cytowany tekst widziałem rok temu. Myślę, że chcąc pisać nowy asmbler nalezy zacząć od dokładnego poznania i zrozumienia procesora, czyli poznania teorii.

moj post swiadczy o tym, ze nie pisalem nic dla 816 i nie uzywalem MAE

Też nie pisałem pod 816, a jednak wiem to i owo m.in. na podstawie wspomnianego artykułu.

moj post swiadczy o tym, ze kazdy moze inaczej zinterpretowac manuala, szczegolnie jesli nie moze podeprzec sie przykladem, bo sucha teoria to nie wszystko

Rozbieżność interpretacji manuali bierze się z ich niezrozumienia. A ten akurat jest najbardziej przejrzystym jaki widziałem.

pozatym gdybys dokladniej doczytal pytanie dotyczace makr moze zrozumialbys ze nie chodzilo mi o to o czym napisales (o tym juz bylo kiedys w moich wczesniejszych pytaniach i zdaje sie ze najpełniej udzielil na nie odpowiedzi Pecus)

A mnie się wydaje, że odpowiedziałem dokładnie na Twoje pytanie. Na przykładzie prostych makr, jak radzi sobie z nimi MAE. Mogę tylko dopisać, że MAC/65 przechowuje makra w pamięci w takej postaci jak resztę źródła (w postaci mnemoników) i asembluje za każdym razem, gdy napotyka wywołanie makrorozkazu. A to z tej prostej przyczyny, że musi zamienić nazwy parametrów na ich wartości (o czym pisałem poprzednio).

Nie ukrywam, że zdziwiły mnie Twoje wątpliwości, gdyż to co jest na AA o 65c816 jest na tyle jasne, że nie powinno wzbudzać wątpliwości.

Pin: to nie 65c816, to tylko scenowi koderzy. :-p

Zawsze mam rację, tylko nikt mnie nie słucha.

8

no widzisz Lizard, jak chcesz to potrafisz :) o to mi chodzilo, a pytania zadaje aby sie upewnic, bo nie ma nic gorszego od niepewnosci ;)

jakie sa ograniczenia co do ilosci makr ?


pozatym sa inne manuale, a w nich

Several new addressing modes are used to access the full address space. A 65816 assembler would decode "long" addressing given this input: 

LDA $0445F2  ; load byte from $45F2 of RAM  
             ; bank 4  

Stad wzielo sie koncowe pytanie z punktu 1, moze w 816 wewnetrznie przepisuje najstarszy bajt do rejestru $d301 :) a reszta jest adresem w obszarze tego banku, fajnie by bylo :), no ale Lizard mowi ze nie, wiec ...


tutaj http://www.programmersheaven.com/zone8/cat715/13292.htm znalazlem asembler 816 podobny do QA, przyklad (to tylko ciekawsze fragmenty programu):

; assemble at $8000
    org $8000
; equates
    animationPointer equ $00

; include decompression code
    include "compress.src"

; program start
programStart
    sei             ; disable interrupts
    phk
    plb
    clc
    xce             ; native 16-bit mode

; set register modes
    rep #$10        ; X & Y 16-bits
    sep #$20        ; A 8-bits

; initialise graphics hardware
    lda #$03        ; graphics mode 3
    sta $2105

    lda #$01        ; enable playfield 0
    sta $212c

    lda #$7C        ; set playfield 0 map to $7C00
    sta $2107
    lda #$00        ; set playfield 0 tile set to $0000
    sta $210b

; characters $0000 to $031F
    ldx.w #$0000
initMapLoop1
    stx $2118
    inx
    cpx.w #$320
    bne initMapLoop1

; 7 rows of character $320
    ldx.w #$0000
    ldy.w #$320
initMapLoop2
    sty $2118
    inx
    cpx.w #$E0
    bne initMapLoop2

; clear playfield 0 tile data
    ldx.w #$0000
    stx $2116
    ldy.w #$0000
initTileLoop
    sty $2118
    inx
    cpx.w #$7C00
    bne initTileLoop

; animation data
cry_anm
    incbin "cry.sad"

Czyli tutaj opcjonalnie stosowane jest rozszerzenie mnemonika po kropce '.b','.w'. Dzieki czemu wiadomo ze chcemy zaladowac bajt lub slowo do rejestru.

Czy w innych asemblerach 816 jest podobnie, moze to standard ?
Czy moze wystarczy jak asembler bedzie decydowac jaki tryb wybrac, na podstawie obliczonej wartosci argumentu mnemonika, a moze lepiej nie ?

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

9

Jedynym znanym mi asemblerem posiadającym jakieś ograniczenia jest Quick Assembler. W pozostałych jakie znam jedynym ograniczeniem jest pamięć, ew. długość nazw etykiet (na ogół 15 i więcej znaków, czyli wystarczająca).

Przykład z LDA $0445F2, gdzie najstarsze $04 oznacza numer banku asembler powinien zamienić na większy kawałek kodu, bo procesor naprawdę nie wie, że najstaszy bajt adresu oznacza bank pamięci. Poza tym,  Twój przykład należałoby rozumieć jako odwołanie do 4-go elementu tablicy kodów banków. Inaczej, gdyby oznaczał konkretny bank, Twój program musiałby modyfikować cały swój kod pod rozszerzenie, na którym jest uruchamiany (z tablicą byłoby dużo prościej). Jednym słowem asembler musiałby dorzuać, gdzieś na początku procedurę inicjującą i modyfikującą program. Zauważ, że w tym momencie odchodzimy już od asemblera i zmierzamy w kierunku wysokiego poziomu, gdyż pewne rzeczy robi za nas automatycznie kompilator. Nawet jeśli coś takiego zrobisz, to zawsze znajdzie się ktoś, komu nie sodoba się Twoje rozwiązanie i zacznie kombinować po swojemu (w ostateczności napisze nowy asembler :twisted: ).

Kombinacje typu LDA.W zaporzyczone zostały z asemblera MC680xx. W przypadku oryginału ma to sens, gdyż rozmmiar danej zapisany jst w kodzie rozkazu. W przypadku 65816 musiałbyś zamieniać odwołania typu LDA.w #$ffff na coś takiego:

    xce        ; zapamieujemy tryb pracy (emu/nat)
    php
    clc
    xce        ; przełączamy w tryb natywny (konieczny dla operacji 16-bit)
    rep #$20   ; przełączamy akumulator i pamięć na 16-bit
    lda #$ffff
    plp        ; przywracamy stan procesora na poprzedni (emu/nat)
    xce

Sam widzisz, że to co proponujesz przestaje być asmem, tylko jakąś hybrydą asemblera i języka wysokiego poziomu.

Powyższy przykład można zrobić jeszcze inaczej bez używania trybu 16-bitowego:

    lda #$ff
    xba
    lda #$ff

Lepiej nie dawać możliwości wyboru trybu pracy asemblerowi, bo będzisz musiał implementować takie cuda jak powyżej. W MAE są pseudo rozkazy: .816, .02, .AB, .AW, .IB, .IW, które przełączają asembler we właściwy tryb. Przełączanie procesora pozostawione zostało użytkownikowi.

Sprawdzałeś co podany przez Ciebie asm wyprawia z takim CPX.W #$7C00. Ja sprawdziłem:

    org    $8000
    lda.w    #$1234
    ldx.b    #$12
    sta.b    $80
    end

Łącznie 7 bajtów zamienił na plik o wielkości ponad 32kB! Mnemoniki pozamieniał na ciąg bajtów:

LDA.w #        LDX.b #   STA.b
$A9, $34, $12, $A7, $12, $85, $80

A gdzie przełączanie wielkości rejestrów? Bez tego, powyższy kod można o kant potłuc.

Zawsze mam rację, tylko nikt mnie nie słucha.

10

sa przelaczniki w oryginale, tylko ja tego nie umiescilem, zaznaczylem ze jest to wylko fragment

w oryginale najpierw ustawiane sa rejestry na 16-bit, a potem moga wystepowac mnemoniki z '.b' lub '.w', zeby nie bylo watpliwosci oto caly kod:

; assemble at $8000
    org $8000


; equates
    animationPointer equ $00
    sourcePointer    equ animationPointer+$04
    sourceOffset     equ sourcePointer+$04
    decompressLength equ sourceOffset+$02
    collectCount     equ decompressLength+$02
    repeatCount      equ collectCount+$02
    framePointer     equ repeatCount+$02
    frameIndex       equ framePointer+$04
    animatedBytes    equ frameIndex+$02
    frameCount       equ animatedBytes+$02
    frameRate        equ frameCount+$02

    joypad           equ $1000
    animationIndex   equ joypad+$02


; include decompression code
    include "compress.src"


; include frame code
    include "frames.src"


; include animation code
    include "animate.src"


; program start
programStart
    sei             ; disable interrupts
    phk
    plb
    clc
    xce             ; native 16-bit mode

; initialise SNES
    sep #$30        ; X, Y & A  8-bits

    lda #$8F        ; clear registers
    sta $2100
    stz $2101
    stz $2102
    stz $2103
    stz $2105
    stz $2106
    stz $2107
    stz $2108
    stz $2109
    stz $210A
    stz $210B
    stz $210C

    stz $210D
    stz $210D
    stz $210E
    stz $210E
    stz $210F
    stz $210F
    stz $2110
    stz $2110
    stz $2111
    stz $2111
    stz $2112
    stz $2112
    stz $2113
    stz $2113
    stz $2114
    stz $2114

    lda #$80
    sta $2115
    stz $2116
    stz $2117
    stz $211A
    stz $211B
    lda #$01
    sta $211B
    stz $211C
    stz $211C
    stz $211D
    stz $211D
    stz $211E
    sta $211E
    stz $211F
    stz $211F
    stz $2120
    stz $2120
    stz $2121
    stz $2123
    stz $2124
    stz $2125
    stz $2126
    stz $2127
    stz $2128
    stz $2129
    stz $212A
    stz $212B
    stz $212C
    stz $212D
    stz $212E
    lda #$30
    sta $2130
    stz $2131
    lda #$E0
    sta $2132
    stz $2133

    stz $4200
    lda #$FF
    sta $4201
    stz $4202
    stz $4203
    stz $4204
    stz $4205
    stz $4206
    stz $4207
    stz $4208
    stz $4209
    stz $420A
    stz $420B
    stz $420C
    stz $420D

; set register modes
    rep #$10        ; X & Y 16-bits
    sep #$20        ; A 8-bits

; initialise graphics hardware
    lda #$03        ; graphics mode 3
    sta $2105

    lda #$01        ; enable playfield 0
    sta $212c

    lda #$7C        ; set playfield 0 map to $7C00
    sta $2107
    lda #$00        ; set playfield 0 tile set to $0000
    sta $210b

    lda #$F3        ; position screen vertically in centre
    sta $210E
    lda #$1F
    sta $210E

; initialise playfield 0 map data
    ldx.w #$7C00    ; set VRAM pointer to playfield 0 map
    stx $2116

; characters $0000 to $031F
    ldx.w #$0000
initMapLoop1
    stx $2118
    inx
    cpx.w #$320
    bne initMapLoop1

; 7 rows of character $320
    ldx.w #$0000
    ldy.w #$320
initMapLoop2
    sty $2118
    inx
    cpx.w #$E0
    bne initMapLoop2

; clear playfield 0 tile data
    ldx.w #$0000
    stx $2116
    ldy.w #$0000
initTileLoop
    sty $2118
    inx
    cpx.w #$7C00
    bne initTileLoop

    lda #$81        ; enable vertical blank interrupt & joypad read
    sta $4200

    cli             ; enable interrupts

    rep #$20        ; A 16-bits

; initialise variables
    lda.w #$0000
    sta animationIndex

; do the next animated sequence
doAnimation
    ldx animationIndex ; get index into animations

    lda frameTableLow,x ; get frame pointer for this animation
    sta.b framePointer
    lda frameTableHigh,x
    sta.b framePointer+$02

    stz.b frameIndex ; clear frame index

    lda animationTableLow,x ; get animation data pointer for this animation
    sta.b animationPointer
    lda animationTableHigh,x
    sta.b animationPointer+$02

    lda speedTable,x ; get frame rate
    sta.b frameRate

    inx             ; update animation index
    inx
    cpx.w #frameTableLowEnd-frameTableLow ; if past last animation
    bne saveAnimationIndex
    ldx.w #$0000    ; then reset index
saveAnimationIndex
    stx animationIndex

    jsr readyNextFrame ; ready frame data
    jsr decompressData ; decompress animation data
    jsr processAnimationFrame ; update screen image with animation data

    jsr readyNextFrame ; ready frame data for next frame
    jsr decompressData ; decompress animation data

    jsr fadeIn      ; fade in display now that first frame is visible

mainLoop

    stz.b frameCount ; reset frame count

    wai             ; wait for vertical blank

    jsr processAnimationFrame ; update screen image with animation data

    jsr readyNextFrame ; ready frame data for next frame
    jsr decompressData ; decompress animation data

    ldy.b frameCount ; get frame count

delayLoop

    lda joypad      ; is B pressed?
    bit.w #$8000
    bne B_pressed   ; then branch

    iny             ; if enough frames delayed
    cpy.b frameRate
    bpl mainLoop    ; then branch

    wai             ; wait for vertical blank

    bra delayLoop   ; and repeat

B_pressed
    stz joypad
    wai             ; wait for vertical blank
    lda joypad      ; loop if B is still pressed
    bit.w #$8000
    bne B_pressed

    jsr fadeOut     ; fade out display

    stz joypad

    brl doAnimation ; and repeat for next animation


; function to fade out current display
fadeOut
    php

    sep #$20        ; A 8-bits

    lda #$0F
fadeOutLoop
    sta $2100
    wai
    sec
    sbc #$01
    bpl fadeOutLoop

    lda #$80        ; disable screen
    sta $2100

    plp

    rts


; function to fade in current display
fadeIn
    php

    sep #$20        ; A 8-bits

    lda #$00        ; enable screen, brightness off
    sta $2100

    wai

    lda #$00
fadeInLoop
    sta $2100
    wai
    clc
    adc #$01
    cmp #$10
    bne fadeInLoop

    plp

    rts


; vertical blank interrupt routine
verticalBlankInterrupt
    sep #$20        ; A 8-bits

    pha             ; save accumulator

    lda.b frameCount ; increment frame count
    clc
    adc #$01
    sta.b frameCount

    lda #$1F        ; delay before attempting to read joypad
joypadDelayLoop
    sec
    sbc #$01
    bne joypadDelayLoop

waitForJoypad
    lda $4212       ; wait until the joypad is ready to read
    and #$01
    bne waitForJoypad

    lda $4218       ; read joypad
    ora joypad
    sta joypad
    lda $4219
    ora joypad+$01
    sta joypad+$01

    pla             ; restore accumulator
    rti             ; exit vertical blank


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;                               ANIMATION DATA                              ;
;---------------------------------------------------------------------------;
; To add an animation to this program you will need to add new entries to   ;
; the...                                                                    ;
;                                                                           ;
; speedTable - the number of vertical blank periods each frame should be    ;
;              displayed for                                                ;
;                                                                           ;
; frameTableLow  - pointer to the .SAF file data                            ;
; frameTableHigh                                                            ;
;                                                                           ;
; animationTableLow - pointer to the .SAD file data                         ;
; animationTableHigh                                                        ;
;                                                                           ;
; You will also need to include the .SAF and .SAD file data.                ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


; speeds
speedTable
    dc.w $0006,$0004


; frame table (low word)
frameTableLow
    dc.w cry_fra&$FFFF
    dc.w merm_fra&$FFFF
frameTableLowEnd


; frame table (high word)
frameTableHigh
    dc.w cry_fra/$10000
    dc.w merm_fra/$10000


; frame data
cry_fra
    incbin "cry.saf"

merm_fra
    incbin "merm.saf"


; animation table (low word)
animationTableLow
    dc.w cry_anm&$FFFF
    dc.w merm_anm&$FFFF


; animation table (high word)
animationTableHigh
    dc.w cry_anm/$10000
    dc.w merm_anm/$10000


; vertical blank interrupt vector
    pad $FFEA
    dc.w verticalBlankInterrupt


; run/reset vector
    pad $FFFC
    dc.w programStart


    pad


; animation data
cry_anm
    incbin "cry.sad"

merm_anm
    incbin "merm.sad"

plik TEST.ASM znajduje sie w pliku ANISNES.zip

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

11

Witam. Przepraszam, ze tak pozno, ale nie mam jeszcze sieci w akademiku i rzadko zagladam na net
Na poczatek.

.. nie MAE. Mówił coś o jakimś krosie - wydaje mi się, że na grzybie - i to jest dla mnie dziwne ..

Ale dlaczego dziwne? Niektorzy ludzie nie maja twardych dyskow, a na dodatek APE dziala im tylko z podstawowa predkoscia. Czy dziwne jest to, ze nie marnuja masochostycznie czasu na te wszystkie pip-pip-pip przy kazdej asemblacji? Ja nie moge sobie na to pozwolic. Dodatkowo jestem na tyle szalony, ze szukam nowych rozwiazan przy pisaniu dem na atari i elastycznosci, ktora chce teraz osiagnac, nie mozna praktycznie uzyskac pracujac tylko przy atari.

Do napisania benchmarku uzylem asemblerka acme. Jesli kogos to zainteresuje, to moge podczepic gdzies zrodelka. Liste wielu crossasemblerow mozna znalec na 6502.org/crossdev/asm. Z tego co wiem, to niestety rzaden z nich nie supportuje atari i o automatycznym generowaniu naglowkow ff ff mozemy zapomniej (ew. mozna napisac sobie makra radzace sobie z tym problemem, tylko wydaje mi sie to troche kulawym rozwiazaniem). Przy pisaniu benchmarku z braku lepszego pomyslu kod 8-bitowy pisalem w miesmiertelnym x-asmie a fragment dla 16-bit incbinowalem w odpowiedni fragment. Teraz pracuje nad nowym demosystemem wykorzystujacym crossassembler ca65 z pakietu cc65 (a wlasciwie troche zmodyfikowana dla moich potrzeb wersje). Ogolnie uwazam, ze pisanie dla atari w ca65 wydaje mi sie nie najgorszym pomyslem, gdyz standardowy linker (jak wiemy uwzgledniajac doswiadczenia z pisania w C) potrafi wyprodukowac kod dla atari. Dodatkowo ca65 wydaje mi sie byc najsilniejszym crossem dla rodziny 65xxx z segmentami, relokowalnym kodem, silnymi makrami, wiec polecam.

Asembler, ktory za przyklad podal TeBe jest destynowany do generowania ROMow na konsole SNESa (prawdopodomnie stad ten 32-kilobajtowy plik wynikowy). Cale zamieszanie z dlugimi i krotkimi operandami jest niestety nie do unikniecie i uzycie tych samych kodow rozkazow dla dlugich i krotkich instrukcji jest wg mnie najslabsza strona 65c816. Koder i tak sam musi dbac o to czy dany rozkaz jest krotki czy dlugi i rozwiazanie przelaczania stanu asemblacji czy zaznaczania explicite dlugosci instrukcji jest wg mnie kwestia preferencji bo oba rozwiazania sa rownie zle :)

Dość kompetentne zrodlo informacji o 65c816 (i to o dziwo ostatnio modyfikowane w czerwcu 2004) mozemy znalezc TU. Jedyna uwaga, ze wciaz nie zostal poprawiony blad, ze adresy przerwan w trybie natywnym sa pod ffex a nie fffx.

12

...Ale dlaczego dziwne? Niektorzy ludzie nie maja twardych dyskow, a na dodatek APE dziala im tylko z podstawowa predkoscia. Czy dziwne jest to, ze nie marnuja masochostycznie czasu na te wszystkie pip-pip-pip przy kazdej asemblacji?...

Nie o to mi chodziło. To, że grzyb jest szybszy - to jest oczywiste. Dlatego powstją rzeczy typu xasm itd. Napisałem tak; bo byłem prawie przekonany, że wspomniany kross nie istnieje (dla A8bit).  ;) - a słyszałem co innego. Po prostu "źle szukałem" :lol:

Kontakt: pin@usdk.pl

13

Jedynym znanym mi asemblerem posiadającym jakieś ograniczenia jest Quick Assembler.

Też nie rozumiem przywiązania niektórych to tego badziewia.

Kombinacje typu LDA.W zaporzyczone zostały z asemblera MC680xx. W przypadku oryginału ma to sens, gdyż rozmmiar danej zapisany jst w kodzie rozkazu.

Wbrew pozorom w przypadku 65c816 też ma to pewien sens, jeśli

LDA.W #$2000

zastępuje

.AW
LDA #$2000

Czyli w LDA.W mamy swego rodzaju kombinację mnemonika i pseudorozkazu. Próbowałem do tego kiedyś przekonać Johna Harrisa (twórcę MAE) nim jeszcze się MAE 1.0 pokazało, ale bez większych sukcesów.

Wadą tego rozwiązania byłaby niewątpliwie konfuzja juzerów: co drugi myślałby, że LDA.W to rzeczywisty rozkaz i w zwiątku z tym nie trzeba już robić REP/SEP.

KMK
? HEX$(6670358)

14

to

lda #$2000

jeszcze asm moglby zrozumiec jako word, ale z tym

lda #$0000


byloby ciezko, wiec zapisa tego w ten sposob

lda.w #$0000

 
jednak wydaje sie calkiem logiczne

no ale user, wiadomo bedzie musial wiedziec ze przed chwila wlaczyl 16-bitowe rejestry i tylko dla takich rejestrow bedzie dodawal za mnemonikiem '.b' lub '.w'

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

15

to

lda #$2000

jeszcze asm moglby zrozumiec jako word, ale z tym

lda #$0000


byloby ciezko, wiec zapisa tego w ten sposob

lda.w #$0000

 
jednak wydaje sie calkiem logiczne

no ale user, wiadomo bedzie musial wiedziec ze przed chwila wlaczyl 16-bitowe rejestry i tylko dla takich rejestrow bedzie dodawal za mnemonikiem '.b' lub '.w'

Alternatywnie (co również używane jest na m68k) można byłoby zamiast

.AW
LDA #$0000

dawać

LDA #$0000.W

Myślę, że pozwoliłoby to uniknąć problemów z braniem LDA.W za rozkaz różny od LDA.B czy też LDA.

KMK
? HEX$(6670358)

16

Zdzisiu, nie mieszajmy dwóch różnych systemów walutowych.

Spieszę z wyjaśnieniem, że pisząc pod 65816 i tak trzeba pamiętać jakiego rozmiaru są aktualnie rejestry, bo będzie zwis. Nie widzę więc potrzeby stosowania przyrostków i wg mnie wystarczy dyrektywa typu .aw czy .ab.

Zawsze znajdzie się inteligent, który nie będzie mógł zrozumieć dlaczego asembler wywala błąd (ostrzeżenie) dla ciągu rozkazów: ldx #$00.w, ldy #$01.b. Bo przyrostki raczzej powinny służyć tylko celom informacyjnym, ew. ostrzegawczym podczas asemblacji, ale rozmiar operandu powinien być dobierany w zależności od "ręcznych" ustawień asemblera (.ib/.iw).

Właśnie. Co powinien wg was wyprodukować asembler z powyższych rozkazów zapisanych jeden po drugim, i w jakim stanie zostawić rozmiar rejestrów indeksowych po zasemblowaniu tego kawałka kodu?

Zawsze mam rację, tylko nikt mnie nie słucha.

17

Spieszę z wyjaśnieniem, że pisząc pod 65816 i tak trzeba pamiętać jakiego rozmiaru są aktualnie rejestry, bo będzie zwis. Nie widzę więc potrzeby stosowania przyrostków i wg mnie wystarczy dyrektywa typu .aw czy .ab.

Przecież teoretyzujemy. Zauważ jednak, że lda #xxxx.w zamiast .aw/lda pozwoliłoby *przynajmniej* zaoszczędzić 1 wers na ekranie :)

KMK
? HEX$(6670358)

18

latwiej znalezc informacje w tej samej linii co rozkaz niz przeszukiwac linie wczesniejsze, jesli jakis as bedzie umieszczal .ab lub .aw kilka, kilkadziesiat liniii wczesniej przez wlasciwymi rozkazami no to program traci na przejrzystosci

pozatym skoro REP i SEP maja tylko jeden tryb adresowania '#', asembler moglby łatwo sledzic zmieniajace sie poprzez te mnemoniki wartosci i odpowiednio interpretowac nastepne rozkazy odwolujace sie do rejestrow, przez co wlasciwie niepotrzebne bylyby dodatkowe informacje typu '.b' lub '.w' lub '.ab' lub '.aw'

user zawsze moglby sprawdzic w listingu jakie rozkazy zostaly wygenerowane

jednak odbywaloby sie to tylko liniowo, jesli w programie wystepowalyby skoki (jsr, jmp i inne) taki asembler nie reagowalby juz prawidlowo, czyli na poczatku kazdej procedury czy bloku trzebaby bylo umieszczac REP lub SEP.

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

19

Zauważ jednak, że lda #xxxx.w zamiast .aw/lda pozwoliłoby *przynajmniej* zaoszczędzić 1 wers na ekranie :)

Od optymalizacji na objętość kodu źródłowego zawsze byłem ja. ;)

Skoro to tylko teoria, to ja pozwolę sobie powiedzieć co zrobiłbym z asemblerem, który po napotkaniu etykiety np. LABEL.W wywaliłby Undefined label z powodu potraktowania końcówki .W jako rozmiaru operandu, a nie części nazwy:

killdir asm

;)
Dla nie znających tematu: kropka jest poprawnym znakiem w asemblerach takich jak MAC/65 i MAE i wolę jej używać zamiast podklreślenia.

Zawsze mam rację, tylko nikt mnie nie słucha.

20

Zawsze znajdzie się inteligent, który nie będzie mógł zrozumieć dlaczego asembler wywala błąd (ostrzeżenie) dla ciągu rozkazów: ldx #$00.w, ldy #$01.b. Bo przyrostki raczzej powinny służyć tylko celom informacyjnym, ew. ostrzegawczym podczas asemblacji, ale rozmiar operandu powinien być dobierany w zależności od "ręcznych" ustawień asemblera (.ib/.iw).

Właśnie. Co powinien wg was wyprodukować asembler z powyższych rozkazów zapisanych jeden po drugim, i w jakim stanie zostawić rozmiar rejestrów indeksowych po zasemblowaniu tego kawałka kodu?

Powinien zrobić to samo co po

.iw
ldx #0
.ib
ldy #0
KMK
? HEX$(6670358)

21

jeszcze jedno pytanie

skoro w makrach uzywany jest znak % jako oznaczenie parametru, to jak przedstawiane sa wartosci binarne, bo w QA itp znak % wlasnie oznacza wartosci binarne

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