atarionline.pl Assembler 6502 - odwapnianie mózgu :) - Forum Atarum

Jeśli chcesz wziąć udział w dyskusjach na forum - zaloguj się. Jeżeli nie masz loginu - poproś o członkostwo.

  • :
  • :

Vanilla 1.1.4 jest produktem Lussumo. Więcej informacji: Dokumentacja, Forum.

  1.  
    Hej,
    Jestem właśnie w trakcie gimnastykowania mózgu Assemblerem :) Droga jeszcze daleka, a początki trudne. Na razie idzie mi jak krew z nosa... Ale, z pomocą paru postów na Forum Atarum oraz na "równoległych" stronach, udało mi się zestawić środowisko programistyczne :) Działam w jEdit + Mads i nawet już udało mi się wygenerować plik .xex, który nie wywala Atarynki :)

    Chciałbym zbierać w tym wątku moje pytania - może przydadzą się komuś innemu, kto zaczyna z Assemblerem albo też przysłużą się do napisania jakiegoś skromnego tutka :)

    Na początek mój pierwszy program, wyświetlający X w lewym, górnym rogu ekranu (spokojnie, nie robię drugiego Psa Antoniego). Wygenerowałem go na podstawie przykładów z Mads oraz książki Assembler 6052 Ruszczyca. Może tu być parę nadmiarowych instrukcji wynikających z moich eksperymentów.
    org $40
    curpos .ds 0
    offhi .ds 156
    offlo .ds 64

    org $2000
    opt c-

    cld
    clc

    loop
    lda # 56
    sta 40000
    jmp loop

    Problem: Ponieważ chciałbym przesuwać mój X po ekranie (spokojnie, naprawdę nie robię drugiego Psa), powiedzmy że na początek w prawo, chciałbym do STA podawać najpierw 40000, potem 40001, itp. Nie wiem tylko jak :/

    Mam zatem dwa pytania:
    1. Jak można "adresować pośrednio", zwłaszcza liczbami 16-bitowymi? Np.
    adres = 40000
    sta @adres
    inc @adres
    ...


    2. Mogę zapisać 40000 do dwóch bajtów (156*256+64). Załóżmy, że jakoś uda mi się je umieścić w pamięci obok siebie, jak można je "przekazać" do sta?
    • 2: CommentAuthornosty
    • CommentTime6 Mar 2012
     
    Twoj program jest chyba bardzo niepoprawny. Nie definiujesz nigdzie pamieci ekranu ani DL...

    Co do pytan: pokazują, że nie rozumiesz podstaw asemblera. Wez pierwsza z brzegu ksiazke i przeczytaj o trybach adresowania 6502 i sam znajdziesz odpowiedz.
    Sorry za RTFM - nie chce Cie zniechecac, ale rownie dobrze moglbys pytac "co to jest LDA?". Zabierzesz ludziom czas bez sensu na cos co akurat mozna wszedzie wyczytac.
    • 3: CommentAuthorbob_er
    • CommentTime6 Mar 2012
     
    no, nosty dobrze pisze - coś o 6502 poczytaj. a tak na zachętę (byś się nie zniechęcił):
    1. sta 40000,x gdzie x (rejestr) zwiększasz co chwilę. może być też rejestr y - wedle uznania.
    2. zapisanie liczby 40000 wymaga dwóch rozkazów sta - każdy po bajcie zapisze. tu się objawia 8bitowość 6502.
    • 4:
       
      CommentAuthorlarek
    • CommentTime6 Mar 2012 zmieniony
     
    Sam spróbuj rozpoznać, co poniższy kod robi
    .
    ldy #0
    nast
    lda #$38
    sta $9c41,y
    lda #0
    sta $9c40,y
    iny
    bne nast


    .
    lda <$9c40
    sta $600
    lda >$9c40
    sta $601
    • 5: CommentAuthorBrix
    • CommentTime6 Mar 2012 zmieniony
     
    W przypadku ośmiobitowców najlepiej niestety zapomnieć wszystko co było na maszynach o "większej" ilości bitów. Tu nie ma tak dobrze, aczkolwiek jak się od biedy zrozumie wszystkie ograniczenia, to da się przeżyć. To tylko komp ośmiobitowy i nie ma tak, że jedną komendą możesz korzystając ze zmiennej w rejestrze zapisać / odczytać coś w zakresie 64kb jak to było np. na Amidze ;)

    Jeśli chodzi Ci o następne bajty, to np. można to zrealizować przez "sta 40000, x" ze zwiększanym tu rejestrem x - ale tylko do 255 bajtów. Albo sta adres+1, sta adres+2 itp. Zapoznaj się też z adresowaniem typu ($80), x - ale jest koszmarnie wolne. Można też samozmodyfikować kod i zwiększyć adres po komendzie sta przez np. clc \ adc lub odpowiednie makra asemblera (pamiętając, że najpierw jest młodszy bajt, potem starszy) - patrz też "znaczki" "<" i ">".

    Ale najlepiej najpierw stwórz ekran (czyli pobaw się antikiem), bo to nie basic - nie masz nic i sam musisz sobie wszystko zrobić :) Polecam też emulator procesora 6502, dużo się można nauczyć.

    EDIT: musisz zrozumieć, że cały czas operujesz tylko na danej wielkości tylko bajta. Jak to zrozumiesz i opanujesz, będzie dobrze :)
    • 6:
       
      CommentAuthorlarek
    • CommentTime6 Mar 2012 zmieniony
     
    • 7:
       
      CommentAuthormgr_inz_rafal
    • CommentTime6 Mar 2012 zmieniony
     

    nosty:

    Twoj program jest chyba bardzo niepoprawny. Nie definiujesz nigdzie pamieci ekranu ani DL...
    Pewnie nie ma tu jeszcze wielu innych rzeczy, bo to właściwie nawet nie jest program :) Ale wszystko w swoim czasie...

    nosty:

    Wez pierwsza z brzegu ksiazke i przeczytaj o trybach adresowania 6502

    bob_er:

    coś o 6502 poczytaj

    Bardzo chętnie. Jutro dalej męczę Ruszczyca.

    nosty:

    Sorry za RTFM - nie chce Cie zniechecac (...) Zabierzesz ludziom czas bez sensu
    Spoko, nie tak łatwo mnie zniechęcić :) Pozwolę szanownym czytelnikom zdecydować, czy traktują odpowiedź jako stratę czasu.

    bob_er:

    sta 40000,x gdzie x
    Rzeczywiście... Jakoś nie zarejestrowałem, że po przecinku jesteśmy ograniczeni do X lub Y i dostawałem "Illegal addressing mode". Jutro powtórka rozdziału 5 :) Istotnie - to było czerstwe pytanie :)

    bob_er:

    tu się objawia 8bitowość 6502

    Brix:

    W przypadku ośmiobitowców najlepiej niestety zapomnieć wszystko co było na maszynach o "większej" ilości bitów.
    Ograniczenia 8 bitów dość mocno mnie zaskoczyły :) Nie sądziłem, że aż tak będę musiał zmienić tok myślenia...

    Brix:

    Ale najlepiej najpierw stwórz ekran (czyli pobaw się antikiem), bo to nie basic - nie masz nic i sam musisz sobie wszystko zrobić :)

    Wstępnie planuję wykorzystać ASMa do wygenerowania procedur, które potem będę wywoływał z poziomu BASICa, czyli muszę ogarnąć te ośmiobitowe dodawania, itp. Pod 40000 chciałem po prostu zapisywać sobie wyniki moich działań, żeby sprawdzić ich poprawność na ekranie. Jeśli ogarnę takie podstawy, to może coś dalej...

    Dzięki za pomoc i "podstawy podstaw" :) Kolejny krok do przodu. Za ciąg dalszy zabiorę się jutro jak się wyśpię, żeby znowu z czymś banalnym nie wyskoczyć ;)
    • 8: CommentAuthorBluki
    • CommentTime7 Mar 2012 zmieniony
     
    Chyba wszyscy zapominacie o "Programowaniu procesora 6502 w komputerach ATARI XL/XE" - kursie zamieszczonym w "Tajemnicach Atari" od nr 3/91.
    • 9: CommentAuthormono
    • CommentTime7 Mar 2012 zmieniony
     
    ->link<-
    Edit: ->link<- błędy zauważone w książkach Wojciecha Zientary
    • 10:
       
      CommentAuthormgr_inz_rafal
    • CommentTime7 Mar 2012 zmieniony
     
    Wprawdzie to tylko proste dodawanie, ale 16 bitowe ;)

    Pierwsze koty za płoty. Idę przyspieszać generator znaków...

    Dzięki raz jeszcze za materiały.

    • 11:
       
      CommentAuthorjhusak
    • CommentTime7 Mar 2012 zmieniony
     
    Zapoznaj się też z adresowaniem typu ($80), x - ale jest koszmarnie wolne.

    2 błędy w powyższym zdaniu.
    albo ($80,x) - imho nie mam dla tego zastosowania , no może tablica jakichś wektorów, ale nie można jmp ani jsr na tym zrobić.
    albo ($80),y

    pośrednie postindeksowane y jest super trybm adresowania i nie jest koszmarnie wolne. Jest wolniejsze o 1 cykl od indeksowanego adr,y czyli o 16 do 20 procent. Dodawany jest cykl przy przekroczeniu granicy strony (256 bajtów) i tu i tu.

    Ogólnie optymalizacja pośredniego postindeksowanego y do indeksowanego sprawdza się tylko w przypadku jednokrotnego użycia bądż nie zmieniania w trakcie pętli wartości adresu (cokolwiek by to nie znaczyło :P )

    --------------
    generalnie kodując w mads zauważyłem, że rzeczywiście jest to assembler dla scenowców. Łatwość tworzenia tablic wszystkiego powoduje, że się tego czasem nadużywa, ale kod się znacznie szybciej pisze.
    --------------
    I jeszcze jedno, kod 6502 przypomina kod RISC, jest takim pośrednim etapem między RISC a CISC. Daje mu to możliwośc niemal dorównania prędkością do Z80 w niektórych zastosowaniach (wiem, co piszę), ale zmusza do myślenia w sposób riscowy. I tu MADS pokazuje ząbki, bo zdejmuje z nas ten sposób myślenia (aczkolwiek nie zwalnia od wiedzy o tym)
    • 12:
       
      CommentAuthorjhusak
    • CommentTime7 Mar 2012 zmieniony
     
    A tak a'propos błędów w książce Ruszczyca najbardziej podobał mi się ten:

    inc - do dodawania małych liczb.
    np.

    inc $4000
    inc $4000

    jest prostsze i szybsze od:

    lda $4000
    clc
    adc #2
    sta $4000

    Oróż NIE JEST SZYBSZE - oba fragmenty zajmują 12 cykli!
    Tyle, że pierwsze nie używa akumulatora, co czasem może być korzystne.
    • 13: CommentAuthorBrix
    • CommentTime7 Mar 2012
     
    @jhusak: Rzeczywiście, moja pomyłka z tym "y" i gruba przesada z tym koszmarem, ale tak to jest jak się pisze na gorąco, szybko i późno. No ale pamięć mam jak sito, stale zapominam składni, komend i tak dalej, to mój problem przy każdym języku programowania i jeszcze większy w prozie życia :/ Ale jak ma się w kodzie naprawdę dużo kopiowania i jeśli da się zastąpić ($80), y przez "adres, x/y", to osobiście zauważyłem zaskakująco sporą jak dla mnie poprawę szybkości działania programu. No ale sam ciągle się uczę, także na błędach.
    • 14:
       
      CommentAuthormgr_inz_rafal
    • CommentTime15 Mar 2012 zmieniony
     
    Dzięki za wszystkie powyższe informacje. Po paru dniach eksperymentów z ASM zaczynam już rozumieć, o czym piszecie powyżej :)

    Po ostatnich zabawach mam jeszcze dwa pytania dotyczące tego kawałka programu, który umieszcza "X" w lewym, górnym rogu ekranu:
    .

    lda <$9c40
    sta $80
    lda >$9c40
    sta $81
    lda #56
    ldy #0
    sta ($80),y

    Otóż wykorzystuję tutaj bajty 128 i 129 ze strony zerowej.

    Pytanie 1:
    Czy dwie ostatnie linijki można jakoś uprościć? Tzn., czy muszę tutaj angażować rejestr Y (lub X)? Mówiąc inaczej, czy istnieje tryb adresowania "pośredni strony zerowej", ale żeby nie był preindeksowany albo postindeksowany?

    Pytanie 2:
    Zmiana ostatniej linijki na sta($8100),y powoduje "Illegal addressing mode", co jest zrozumiałe, bo to tryb "pośredni strony zerowej". Czy można jakoś adresować pośrednio z wykorzystaniem innych stron? Pytam z ciekawości, strona 0 w zupełności mi wystarcza :)
    • 15: CommentAuthormono
    • CommentTime15 Mar 2012
     
    ldy #0
    inaczej zadziała tzw. cudem tylko jeśli w komórce 0 będzie wartość 0.

    ad.1. Nie istnieje; można to zrealizować samomodyfikującym kodem
    lda #<$9c40
    sta addr+1
    lda #>$9c40
    sta addr+2
    lda #'X'
    addr: sta.w 0

    ale taki blok będzie działał tylko w RAM (jeśli planujesz grę na carcie musisz taki blok przepisać do RAM).

    ad.2. Pośrednio nie - tylko absolutnie. Samomodyfikujący kod też tutaj ma zastosowania.
  2.  
    Miało być LDY #0 - przeoczenie. Poprawiłem już posta.

    Samomodyfikujący się kod - brzmi interesująco, ale jeszcze nie na teraz :)

    Dziękuję za odpowiedzi.
    • 17: CommentAuthorBrix
    • CommentTime15 Mar 2012 zmieniony
     
    Jeśli przeszkadza "zaśmiecenie" rejestru Y, można go zachować np. przez sty 200 (edit) i odtworzyć później przez ldy 200 (edit). Jeśli adres jest stały i przesunięcie jest stałe, można użyć "adresowania" typu "sta $9c40+jakaśwartość" (policzy to asembler). No i oczywiście samomodyfikacje, jak wspomniał wyżej mono. Samomodyfikacje są wbrew pozorom bardzo proste, bo przy konstrukcji np. "etykieta sta $CAFE" mamy kolejno trzy bajty:

    sta : młodszy bajt adresu ($FE) : starszy bajt adresu ($CA)

    Etykieta to adres rozkazu "sta", więc etykieta+1 wskaże na młodszy bajt, a etykieta+2 na starszy.

    IMHO lepiej samomodyfikacji nie nadużywać także z innych przyczyn, bo np. spada czytelność kodu, łatwiej zrobić błąd itp.
    • 18: CommentAuthorbob_er
    • CommentTime15 Mar 2012
     
    jak rejestr zapiszesz na stronie zerowej, a nie poza - to będzie i krócej i szybciej.
    • 19:
       
      CommentAuthorjhusak
    • CommentTime15 Mar 2012
     
    Kod Amaurote to dość mocne użycie samomodyfikującego się kodu, i to np:
    Sprite ma 4 bajty szerokości, ale czasem jest na krawędzi ekranu.
    Co jest w kodzie? Ify? nie. 4 różne procki sprajta? nie. Otóż są 4 docelowe adresy kolumn, które są podmieniane w przypadku wyjścia poza ekran na fejkowe (puste miejsce).

    Podobnie jest, jak sprajt wychodzi poza ekran w górę lub w dół, ale tylko w niektórych przypadkach, bo tu można wspórzędne pionowe zmieniać (startowa i końcowa)
    • 20: CommentAuthorBrix
    • CommentTime15 Mar 2012
     
    bob_er: o to mi właśnie chodziło (sty 200), a zawsze walnę jakiś głupi błąd, jak szybko piszę odpowiedź ;)
  3.  
    Hej,

    Mam następne pytania. Dziergam sobie procedurki w ASM i w pewnym momencie napisałem dzielenie dwóch liczb ośmiobitowych (divByte), która wynik zostawia w akumulatorze.

    Następnie gdzieś w kodzie pojawiło mi się:
    divByte s1, #8
    więc od razu pomyślałem - optymalizacja za pomocą LSR.

    Zamieniłem więc powyższe wywołanie na
    lsr s1
    lsr s1
    lsr s1
    lda s1


    Zastanawiam się jednak, czy nie lepiej jest zrobić tak:
    lda s1
    lsr
    lsr
    lsr


    Pytanie 1: czy jest jakaś różnica w ilości cykli zużytych przez dwa powyższe bloki komend? Mam mgliste wrażenie, że działania na akumulatorze są szybkie (szybsze od tych nie na akumulatorze).

    Pytanie 2: czy istnieje w miarę prosty sposób profilowania kodu? Chodzi mi o obliczenie ile cykli zjadł mój kod od punktu A do punktu B. Na razie szukam wskazówek odnośnie pazerności poszczególnych rozkazów w Ruszczycu, ale to trochę nieinnowacyjna metoda :)
    • 22: CommentAuthorilmenit
    • CommentTime20 Mar 2012
     
    Opcody:
    ->link<-

    Profiler ma nowa Altirra albo możesz użyć mojego:
    ->link<-
    • 23: CommentAuthor0xF
    • CommentTime20 Mar 2012
     
    lsr na akumulatorze to 2 cykle, na stronie zerowej 5. Jeśli chcesz pisać wydajny kod, to powinieneś wiedzieć, ile zajmują poszczególne instrukcje - tabelka w Ruszyczycu. Wbrew pozorom nie jest to trudne, bo jest dużo regularności - lsr zajmuje tyle samo co asl, rol, ror.

    Emulatory wyświetlają liczbę cykli rozkazu przy disasemblacji (pomijając dodatkowy cykl na przekroczenie strony lub odgałęzienie). Altirra ma też wbudowany profiler.

    Historycznie do pomiaru wydajności często używało się "barów" - zmieniasz kolor ekranu w czasie wykonywania procedury wykonywanej co ramkę i szacujesz, ile linii zajmuje. Może też przydać się VCOUNT.

    Dla krótkich fragmentów kodu stosowałem też rozpisywanie na kartce liczby cykli obok instrukcji i ręczne sumowanie. W ten sposób możesz sobie porównywać różne warianty kodu.
    • 24:
       
      CommentAuthorjhusak
    • CommentTime20 Mar 2012 zmieniony
     
    Te regularności, o których wspomina 0xF, są nawet regularniejsze, można z dokładnością do cyklu założyć, że to tryb adresowania ma ileś cykli, a nie rozkaz. Wyobrazić sobie, że zapis do jednej komórki pamięci to dodatkowy cykl, odczyt to dodatkowy cykl, a odczyt/zapis to dodatkowe dwa cykle i jeszcze operand jednobajtowy opisujący dostęp do pamięci to jeden cykl dodatkowo, a operand dwubajtowy to 2 cykle dodatkowo czyli:

    rol $4000 będzie miał 2(rol)+2(operand)+2(odczyt/zapis) = 6 cykli

    lda (20),y = lda+(2 cykle) operand (1 lub 2 cykle) + 1(odczyt) = 5(6)

    lda (20,x) = lda(2 cykle) operand(1 cykl), pobranie adresu z dwóch komórek (2) +read (1 cykl) = 6 cykli

    W ten sposób pomylisz się o co najwyżej cykl, albo ekstremalnie 2 (przekroczenie strony pamięci).

    Z góry piszę, że to co powyżej to ilustracja (i mój domysł), co mniej więcej trzeba zrobić, aby wykonać rozkaz. a nie to, co robi procesor. Ale tu chodzi o wyczucie, a nie o ścisłe wykonywanie instrukcji jak procesor.

    Gdzieś jest jeszcze myk pipeliningu, gdzie 6502 pobiera nowy operand podczas cyklu read/write poprzedniego rozkazu.
    • 25: CommentAuthorepi
    • CommentTime20 Mar 2012
     
    W skrócie: najprościej zapamiętać, że na wykonanie rozkazu potrzeba co najmniej tyle cykli, ile jest niezbędnych dostępów do pamięci. A te łatwo policzyć, bo powinieneś wiedzieć co robi instrukcja w konkretnym trybie adresowania, skoro jej używasz. :)
    • 26:
       
      CommentAuthorjhusak
    • CommentTime20 Mar 2012
     
    A czy tu się objawia bug/cecha pipeliningu, że asl i np. lda #0 mają po dwa cykle, mimo, że lda #0 ma o 1 więcej dostęp do pamięci?

    (takie pytanie, aby wpleść jeszcze jeden aspekt 6502, który jest risco-ciscem z pipeliningiem :)
    • 27: CommentAuthor0xF
    • CommentTime20 Mar 2012
     
    jhusak: lda (20,x) ma zawsze 6 cykli - popraw, bo jeszcze ktoś się nauczy, że czasami 7
    • 28: CommentAuthorepi
    • CommentTime21 Mar 2012
     
    Określenia RISC, CISC i pipeline są nieco na wyrost w kontekście 6502. :)
    Pierwszy cykl to zawsze zatrzaśnięcie opkodu i nic więcej. Dopiero w następnych cyklach opkod w rejestrze instrukcji oraz nr cyklu podane na wejście dekodera sterują połączeniem bloków funkcjonalnych w procku w sposób, który może wywołać sensowne działanie. Stąd minimum 2 cykle na rozkaz.
    W tym samym czasie, kiedy zatrzaśnięty zostaje opkod, po adresie rozkazu na szynie adresowej pojawia się zawsze adres kolejny. Dla instrukcji 1-bajtowych odczytana stamtąd wartość jest ignorowana.
    • 29:
       
      CommentAuthorlaoo
    • CommentTime21 Mar 2012 zmieniony
     
    Patrząc z innej strony cykl czytania opcodu jest ostatnim cyklem rozkazu, w którym równolegle wykonywane jest ostatnie działanie (z wyjątkiem rozkazów zapisów, w których procesor nie robi wtedy nic poza czytaniem opcodu).

    Dla lda #0 byłoby wtedy:
    1. Czytaj operand. Domyśl się, że opcode to "lda #", w którym operand zawiera istotną daną, a więc zwiększ PC.
    2. Załaduj operand do akumulatora. Wczytaj następny opcode. Zwiększ PC.

    Dla asl:
    1. Czytaj operand. Domyśl się, że opcode to "asl", w którym operand jest ignorowany, więc nie zwiększaj PC.
    2. zrób asl na akumulatorze. Wczytaj następny opcode. Zwiększ PC.
    • 30: CommentAuthorepi
    • CommentTime21 Mar 2012
     
    Nie musisz się domyślać, opcode jest już zatrzaśnięty i to już dekoder steruje tym, czy w PC w kolejnym cyklu zatrzaśnie się PC+1, czy nie. :)
    Trzask! :)
  4.  
    Jestem pod wrażeniem tego, w jak ciekawą dyskusję rozwija się proste pytanie początkującego :) Dzięki po raz kolejny za informacje. Szacunek za wiedzę :)
    • 32:
       
      CommentAuthorjhusak
    • CommentTime21 Mar 2012 zmieniony
     
    jhusak: lda (20,x) ma zawsze 6 cykli - popraw, bo jeszcze ktoś się nauczy, że czasami 7

    o f#%k.

    Poprawione.

    Powiem tak. Epi, 0xF, tebe, xxl to są tacy wymiatacze, że głowa mała (sorki, jak kogoś pominąłem) Rozmowa z nimi tylko z opuszczoną głową. Za to nigdy nie jest nudna, amerytoryczna i ZAWSZE człowiek się czegoś nauczy.

    Cociażby wystarczy jeden równoważnik zdania typu:
    Co za bzdura!

    I już człowiek mądrzejszy, a przynajmniej uważniejszy :)

    Jesteś naprawdę w dobrych rękach. Trust me.
    • 33:
       
      CommentAuthorjhusak
    • CommentTime21 Mar 2012 zmieniony
     
    A tak swoją drogą, najdłuższe rozkazy (7 cykli) to:
    BRK
    ASL, LSR, ROR, ROL, INC, DEC Q,X, czyli np.

    inc $4000,x ma 7 cykli i ani cykla mniej (rozkaz RW)

    edit: ja smoka miałem na myśli.
    • 34: CommentAuthorxxl
    • CommentTime21 Mar 2012
     
    najdluzsze to 8 cyklowe (niektore niepublikowane np DCP, ISB, RRD, ASO itd.)
    • 35: CommentAuthor0xF
    • CommentTime21 Mar 2012
     
    Dłuższy jest STA $D40A.
    • 36: CommentAuthorKonop
    • CommentTime21 Mar 2012
     
    Ale nie tak długi jak BRK.
    • 37:
       
      CommentAuthorjhusak
    • CommentTime21 Mar 2012 zmieniony
     
    0xF, ty podpuszczaczu.
    Konop, kiedy BRK ma więcej cykli niż STA WSYNC? (poza trzema przypadkami, kiedy STA WSYNC ma <= 7 cykli)
    Bo ja już zgłupiałem. Może jest sytuacja, gdy BRK wykonuje się 115 cykli lub więcej :) a ja o tym jeszcze nie wiem :)

    Ale tak naprawdę to jest kwestia: ile czasu może trwać pojedynczy rozkaz?
    I tu 0xF ma rację. Ale tak naprawdę to STA WSYNC wykonuje się 4 cykle, ale cykl zapisu jest dłuuuuuugi, ale jeeeeeeeeeeden (jak procek jest zhaltowany to i cykle się nie wykonują)
    W związku z tym Konop ma rację.

    Są jeszcze takie twory jak badlines w trybie tekstowym. I tutaj może być ciekawie. Bo zwykła instrukcja lda $4000 może trwać i trwać i trwać...
    • 38: CommentAuthorepi
    • CommentTime22 Mar 2012 zmieniony
     
    A to nie jest tak, że cykl zapisu się już skończył, skoro ANTIC zdążył zareagować wystawieniem HALTa?

    BTW: 6502 wykonuje dwa cykle zapisu w rozkazach RMW. Sprawdzaliście, czy INC WSYNC odczeka do końca bieżącej linii + całą następną?
    • 39:
       
      CommentAuthorKrótki
    • CommentTime22 Mar 2012
     

    epi:

    A to nie jest tak, że cykl zapisu się już skończył, skoro ANTIC zdążył zareagować wystawieniem HALTa?

    Nie tylko. Przed zHALTowaniem CPU "zwykle" wykonuje jeszcze 1 cykl następnej instrukcji.

    epi:

    Sprawdzaliście, czy INC WSYNC odczeka do końca bieżącej linii + całą następną?

    Zob. Altirra Hardware Reference Manual p. 4.8.
    • 40:
       
      CommentAuthorlaoo
    • CommentTime22 Mar 2012
     
    Ale żądna z tych instrukcji nie jest tak długa jak KIL!
    • 41: CommentAuthorepi
    • CommentTime22 Mar 2012
     
    Instrukcja żądna cykli. ;)

    Krótki: dzięki!
    • 42: CommentAuthorat0mic
    • CommentTime22 Mar 2012 zmieniony
     
    ;
    ; procedura system_off - wylaczamy OS, podlaczamy RAM pod ROMem i
    ; zajmujemy sie na wlasna reke obsluga NMI
    ;
    org $600
    system_off equ *

    lda #0
    sta $d40e ; wylaczamy NMI
    sei ; oraz IRQ
    lda #$fe ; oraz podlaczamy RAM pod ROMem, wylaczajac OS
    sta $d301

    ; poniewaz nie mamy juz systemu nalezy zadbac o wlasna obsluge przerwan NMI

    lda <NMI
    sta $fffa
    lda >NMI
    sta $fffb
    lda #$c0 ;wlaczamy NMI
    sta $d40e
    petla jmp petla ; nieskończona pętla po włączeniu przerwań

    NMI bit $d40f ; sprawdzamy czy przerwanie to VBL czy DLI
    bpl _no
    jmp DLI
    _no sta $d40f
    jmp VBL

    DLI lda$d20a ;wczytuje rnd
    sta$d01a ;zmienia kolor ramki na wartość rnd
    rti
    VBL lda$d20a ;wczytuje rnd
    sta$d018 ;zmienia kolor tła na wartość rnd
    rti


    coś tam bzyka na ekranie ale nie mam pojęcia co wpisać żeby te przerwania następowały 50 razy na sekundę a nie 60 razy jak to ma miejsce teraz.

    Czy oprócz komórek D20E,D40F,D40A,D40B powinienem jeszcze czegoś szukać w mapie pamięci?

    Chciałbym uzyskać taki efekt że ustawiam przerwanie tak, że wybieram linię rastra w której ono ma nastąpić i następuje ono w każdej ramce czyli 50 razy na sekundę.

    Wartość 0c->d40E włącza przerwania VBL i DLI.
    Dla VBL zmieniam kolor tła, a lda DLI ramki z tym że nie rozumiem gdzie jest źródło przerwań i wychodzi na to że przerwania DLI jakby nie następowały. Trochę to robię po omacku bo mimo mapy pamięci atari nie wszystko rozumiem.

    np: nie rozumiem dlaczego Antic ma generować przerwać NMI a nie IRQ - może źle coś zrozumiałem z opisu. Czy to jest jakaś specyficzna cecha Atari że układ wizyjny generuje NMI ?


    Czy Wszystkie źródła przerwań ustawia się w POKEY lub PIA ? Potrzebuję takiej informacji żeby zawęzić ilość komórek pamięci do przewertowania w mapie pamięci Atari.
    • 43: CommentAuthorxxl
    • CommentTime22 Mar 2012
     
    po pierwsze: brakuje przechowania wartosci rejestrow w przerwaniach

    > żeby te przerwania nactępowały 50 razy na sekundę a nie 60 razy jak to ma miejsce teraz.

    zmien NTSC na PAL

    > Czy oprócz komórek D20E,D40F,D40A,D40B powinienem jeszcze czegoś szukać w mapie pamięci?

    tak,

    > a lda DLI ramki z tym że nie rozumiem gdzie jest źródło przerwań i wychodzi na to że przerwania DLI jakby nie następowały.

    to w ktorej linii brazu chcesz wywolac przerwanie najlepiej ustawic w programie antica (DL)
    • 44:
       
      CommentAuthorjhusak
    • CommentTime22 Mar 2012 zmieniony
     
    Bez utraty ogólności:
    Antic generuje NMI - vblank i dli. Można ich zabronić.
    Pokey generuje IRQ.
    Przy czym Antic jest nadrzędny do CPU (cpu tańczy tak, jak mu zagra antic)

    Generalnie z tymi przerwaniami jest tak:
    albo używasz ich sam, i masz problem, bo musisz sporo się nauczyć hardware.
    albo używasz ich poprzez SO (ma piękne procedurki ustawienia przerwań irq) i musisz się nauczyć sporo software.

    Ja generalnie w obcych środowiskach posługuję się przykładami, zrozumienie przychodzi później, po eksperymentach. Jest to wbrew pozorom bardzo szybka droga nauki.

    Stosuj gotowce.

    Co do twojego zadania:
    SO ma jeden wektor na DLI i vblank. Rodzaj przerwania rozpoznawany jest instrukcją BIT zaraz na początku przerwania. I teraz testujesz NMIST. Jeśli jest obsadzony bit 7, to jest to DLI, w p. p. reset lub vblank (reset nas nie obchodzi, traktujemy jak vblank)

    Więc w procce przerwania (tak z pamięci piszę)
    ; proc dlint
    pha
    bit NMIST
    bpl vbl
    lda #$ff
    sta COLBK
    pla
    rti
    vbl:
    lda #0
    sta COLBK
    pla
    rti

    Do tego gdzieś w display list w wyświetlaniu linii (standardowo 02 - tryb tekstowy) sobie obsadź bit 8 i zezwól na przerwania DLI - NMIEN ustawiając na $C0

    I będziesz miał od połowy ekranu (czy skądśtam) białą ramkę o 1 kolor wyżej po prawej, niż po lewej (prawdopodobnie)

    Aby tak nie było, trzeba:
    ;
    lda #$ff
    sta WSYNC
    STA COLBK

    w dli.

    w vblk tak nie trzeba, bo i tak nie widać.

    Jak będziesz obczajał irq, to tam jest malutki haczyczek, ale wkurzający niezorientowanych.
    • 45:
       
      CommentAuthorjhusak
    • CommentTime22 Mar 2012
     
    I jeszcze a propos 50/60hz. Tak jak napisał XXL, w emulu można sobie zmienić. Ale real atari nie bardzo. Wiąże się to z wymianą szeregu układów różnych w wersji pal i ntsc (pół komputera), oraz chyba dwóch kwarców, o ile się nie mylę (a na pewno 1).
    • 46: CommentAuthor0xF
    • CommentTime22 Mar 2012
     
    sta $d40f nie jest potrzebne.
    • 47: CommentAuthor0xF
    • CommentTime22 Mar 2012
     

    epi:

    A to nie jest tak, że cykl zapisu się już skończył, skoro ANTIC zdążył zareagować wystawieniem HALTa?

    Jeśli dobrze pamiętam, WSYNC załatwia RDY. HALT służy do DMA.

    BTW. ciąglę mam niewyjaśnioną zagadkę:
    ->link<-
    • 48: CommentAuthorat0mic
    • CommentTime22 Mar 2012 zmieniony
     
    jak zrobić żeby w trybie szerokim 35>559 ANTIC brał przypisany adres ekranu z DLI dosłownie a nie z przesunięciem 3 bajtów.

    jeśli zapiszę do pamięci od $6000 napis: ATARI to pokazuje się tylko RI

    więc piszę to do adresu $6003 ale niestety burzy mi to myślenie a będę elementy przeciągał po ekranie i potrzebuję żeby nie było takich pułapek.


    źródło jest w MADs
    obraz equ $6000
    org $5000

    lda #$23
    sta 559
    lda <ant ;młodszy bajt adresu programu ANTIC-a
    sta 560 ;do młodszego bajtu cienia DLPTR(560), czyli znajdzie sie to potem w $d402
    lda >ant ;starszy bajt adresu programu ANTIC-a
    sta 561 ;do starszego bajtu cienia DLPTR(561), czyli znajdzie sie to potem w $d403

    lda #$c0 ;wartość $c0
    sta $d40e ;do NMIEN

    never jmp never


    ant ;dta b($70,$70) ;2 x 8 pustych linii
    ;dta b($70+$80) ;8 pustych linii z przerwaniem DLI, bo `+$80`
    dta b($c2),a(obraz)
    dta b(5,5,5,5,5,5,5,5,5,5,5,5,5,5)
    dta b($41),a(ant)


    org $6000


    .array txt 39 .byte
    [3] = "ATARI"
    .enda


    czy raczej ustawić ekran w DLI od $5FFD i zachowywać się tak jakby był od $6000 ?
    • 49: CommentAuthor0xF
    • CommentTime22 Mar 2012
     
    Trybu szerokiego praktycznie się nie używa, bo jak sam zauważyłeś z lewej strony widać jeden znaczek więcej (trzech nie widać), z prawej ew. trochę więcej, ale to mocno zależy od ustawień telewizora/monitora.

    Jeśli chcesz mieć pamięć obrazu o innej szerokości linii, możesz podawać adresy linii w DL.

    A adres musiałbyś ustawić na $6FFD, bo następne bajty pamieci obrazu to $6FFE, $6FFF, $6000
    • 50: CommentAuthorxxl
    • CommentTime22 Mar 2012 zmieniony
     
    granica 4k przy LMS