Autor Wątek: Asembler Z80 i 8080 pod Windows  (Przeczytany 34955 razy)

pear

  • *****
  • Wiadomości: 5509
  • Miejsce pobytu:
    Będzin
  • Z80 only
Odp: Asembler Z80 i 8080 pod Windows
« Odpowiedź #15 dnia: 2019.03.20, 12:50:24 »
Pomysł świetny i sam też bym skorzystał, tylko ... nie ma kto zrobić :(
ZX/Enterprise/CPC/Robotron/C128D

SAJ

  • *****
  • Wiadomości: 1484
  • Miejsce pobytu:
    Terra Prime
Odp: Asembler Z80 i 8080 pod Windows
« Odpowiedź #16 dnia: 2019.03.20, 12:51:42 »
nie ma kto zrobić :(

Trzeba poszukac kogos, kto zawsze twierdzil, ze jest za duzo lutosceny i za malo programowania.

Znamy kogos takiego ?

matofesi

  • *****
  • Wiadomości: 2048
  • Miejsce pobytu:
    Toruń/Poland
Odp: Asembler Z80 i 8080 pod Windows
« Odpowiedź #17 dnia: 2019.03.20, 12:52:21 »
To ja się po raz kolejny bezwstydnie zareklamuję ;)
http://speccy.pl/articles.php?article_id=11 i http://speccy.pl/articles.php?article_id=12
Teksty być może nie są całkiem dla początkujących, ale jak się do tego otworzy opis listy rozkazów to wydaje mi się, że da się załapać jakąś "bazę" ;)

Pisząc starałem się wyjaśniać wszystko po kolei, ale jako, że nie specjalnie mam zacięcie pedagogiczne różnie z tym może być. Dlatego też raczej nie podjąłbym się pisania tekstów zupełnie od podstaw - po prostu uczyłem się tego wszystkiego tak dawno, że nie pamiętam jak to było jak nie umiałem ;)

matofesi

  • *****
  • Wiadomości: 2048
  • Miejsce pobytu:
    Toruń/Poland
Odp: Asembler Z80 i 8080 pod Windows
« Odpowiedź #18 dnia: 2019.03.20, 12:55:14 »
nie ma kto zrobić :(

Trzeba poszukac kogos, kto zawsze twierdzil, ze jest za duzo lutosceny i za malo programowania.

Znamy kogos takiego ?

A to nie było tak, że temat już-już był obcykany i tylko jakichś szlifów brakowało? ;)

SAJ

  • *****
  • Wiadomości: 1484
  • Miejsce pobytu:
    Terra Prime
Odp: Asembler Z80 i 8080 pod Windows
« Odpowiedź #19 dnia: 2019.03.20, 12:55:57 »
Jakas szansa, zeby w komentarzach przy kazdej linii assemblera bylo wytlumczone co linia robi i po co tam jest ?

czy

org 32768

Oznacza, ze ZX Spectrum w polowie pamieci dostaje orgazmu ?

:)

Maryjan

  • *****
  • Wiadomości: 6650
  • Miejsce pobytu:
    Skarżysko-Kam.
  • Scotch whiskey and West Highland Terrier
Odp: Asembler Z80 i 8080 pod Windows
« Odpowiedź #20 dnia: 2019.03.20, 13:01:37 »
... a przy 65536 szczytuje :P
"Co miałem powiedzieć - przeczytałem..." Nikodem Dyzma

matofesi

  • *****
  • Wiadomości: 2048
  • Miejsce pobytu:
    Toruń/Poland
Odp: Asembler Z80 i 8080 pod Windows
« Odpowiedź #21 dnia: 2019.03.20, 13:02:53 »
W tych artykułach? Żadna ;) W tekście jest opis "funkcjonalny", ale niestety zakłada, że rozumiesz poszczególne rozkazy (czyli sięgnąłeś do manuala Z80 albo na wiki). Mogę się ewentualnie pokusić o "rozpisanie" pierwszego ze scrollerów, ale prawdopodobnie na cokolwiek więcej nie będę miał zacięcia ;)

KWF

  • *****
  • Wiadomości: 6823
  • Miejsce pobytu:
    trzecia planeta od Słońca
  • "I co ja robię tu, u-u, co Ty tutaj robisz ..."
    • Insta do lasownia
Odp: Asembler Z80 i 8080 pod Windows
« Odpowiedź #22 dnia: 2019.03.20, 13:37:39 »
Ja niczego więcej na starcie nie miałem ;D
Mało tego - nie miałem nawet komputera i przeliczałem mnemoniki na kody na papierze według tabeli z zeszytu.
Jak się chce, to się da :D

Wszytko OK, jesli masz nascie lat, jestes zdolnym leniem i masz duuzo czasu. Jesli na karku czwarty krzyzyk, do tego zwapnialy mozg niezdolny do szybkiego kojarzenia faktow (pisze o sobie!!!), to juz nie jest tak prosto. :P Bez podrecznika typu "ASM Z80 dla idiotow" raczej nie pojdzie.
« Ostatnia zmiana: 2019.03.20, 13:45:58 wysłana przez Klaud »
KWF
-----
R Tape loading error 0:1
Moje zabawki: https://github.com/McKlaud76

matofesi

  • *****
  • Wiadomości: 2048
  • Miejsce pobytu:
    Toruń/Poland
Odp: Asembler Z80 i 8080 pod Windows
« Odpowiedź #23 dnia: 2019.03.20, 13:54:53 »
OK. Pierwszy przykład z pierwszego artykułu rozpisany do poziomu rozkazów i tego, co one robią ;)

        org 32768         ; dyrektywa assemblera - adres początku programu

main_loop:                ; etykieta - logiczny adres zamiast fizycznego
        halt              ; zaczekaj na przerwanie niemaskowalne
        call one_scroll   ; wywołaj podprogram one_scroll - adres następnego rozkazu
                          ; odkłądany jest na stos
        ld bc,$7ffe       ; załaduj do pary rejestrów bc liczbą $7ffe -
                          ; - adres portu klawiatury zawierającego m.in. spację
        in a,(c)          ; odczytaj bajt z portu z adresem w BC do akumulatora (A)
        and 1             ; wykonaj logiczne I pomiędzy A i liczbą 1 - w tym wypadku
                          ; zeruje wszystkie bity poza najmłodszym i jeśli był zerem
                          ; to ustawia wskaźnik Z procesora
        jr nz, main_loop  ; skocz do main_loop jeśli Z nie jest ustawiony
                          ; w efekcie zamyka pętlę jeśli NIE była wciśnięta spacja
        ret               ; wyjście z podprogramu - w tym wypadku powrót do procedury
                          ; ROM kończącej obsługę funkcji USR

one_scroll:
        ld a,(bpos)       ; załaduj do A bajt z pamięci pod adresem bpos
        or a              ; wykonaj logiczne LUB między A i A - efektem jest
                          ; ustawienie znacznika Z jeśli w A jest zero
        jr z,move_text    ; skocz jeśli w A jest zero
        dec a             ; zmniejsz A o jeden
        ld (bpos),a       ; zapisz A do pamięci pod adres bpos
        jr do_scroll      ; skocz dalej
                          ; cały powyższy kawałek to liczniki pikseli pojedynczego znaku
                          ; warunek nie będzie spełniony 8 razy czyli 8 razy następi
                          ; skok do do_scroll a przy ósmym wywołaniu najpierw nastąpi
                          ; przeskok do move_tekst
move_text:
        ld a,7            ; załaduj do A 7 - licznik pikseli
        ld (bpos),a       ; zapisz A do pamięci pod adres bpos - z wcześniejszego
                          ; kawałka pod bpos było 0 i teraz to zmieniliśmy przygotowując
                          ; kolejną pętlę ośmiu wywołań
text_adr: equ $+1         ; $ to adres aktualnego miejsca do którego zapisana zostanie
                          ; kolejna instrukcja przy assemblacji
                          ; dyrektywa equ $+1 przypisuje stałej text_adr adres o jeden dalej
                          ; niż następny adres assemblacji
        ld hl,text        ; tutaj do pary rejestrów HL ładujemy liczbę będącą adresem
                          ; tekstu scrollera (etykieta text)
                          ; sam rozkaz składa się z trzech bajtów - pierwszy to kod
                          ; rozkazu a dwa kolejne to sam adres - equ $+1 wskazuje właśnie
                          ; na miejsce w pamięci pod którym znajduje się ten adres
        ld a,(hl)         ; ładujemy do A bajt spod adresu znajdującego się w HL
        inc hl            ; zwiększamy HL o 1
        ld (text_adr),hl  ; zapisujemy HL do pamięci pod adres text_adr
                          ; w efekcie przy następnym wywołaniu poprzednie "ld hl,text"
                          ; będzie zawierało ld hl,text+1
        cp 13             ; porównanie A do liczby 13 - tak na prawdę wewnętrznie procesor
                          ; odejmuje 13 od A i ustawia odpowiednio znaczniki - jeśli
                          ; w A było 13 to ustawiony zostanie znacznik Z
        jr nz,get_char    ; skocz jeśli Z nie było ustawione, czyli nie mieliśmy w A 13
        ld hl,text        ; jeśli mieliśmy to znaczy, że doszliśmy do końca tekstu i trzeba
                          ; go "zapętlić" - ładujemy do HL adres etykiety "text"
        ld a,(hl)         ; pobieramy do A bajt spod adresu w HL
        inc hl            ; zwiększamy HL o jeden
        ld (text_adr),hl  ; zapisujemy HL do pamięcie jak poprzednio


get_char:
        ld h,0            ; ładujemy do H (wyższej połówki pary HL) zero
        ld l,a            ; ładujemy do L (niższej połówki pary HL) zawartość A
                          ; w tym wypadku jest to kod kolejnego znaku do "wyscrollowania"
        add hl,hl         ; dodajemy HL do HL - w efekcie mnożymy HL przez 2
        add hl,hl         ; ...przez 4
        add hl,hl         ; ...przez 8
        ld de,$3C00       ; łądujemy do pary rejestrów DE $3C00 - pod adresem $3D00 w ROMie
                          ; znajduje się standardowy generator znaków
                          ; używamy adresu o 256 niższego, bo w A mieliśmy kod ASCII znaku
                          ; które to kody zaczynają się od 32 - 32 * 8 daje właśnie 256, o
                          ; które pomniejszamy adres
        add hl,de         ; dodajemy do HL zawartość DE - w efekcie w HL mamy adres w ROM
                          ; bitmapy kolejnego znaku

        ld de,buf         ; do DE ładujemy adres bufora znaku na którym będziemy dalej pracować 
        rept 8            ; dyrektywa assemblera - powtarza 8 razy wszystko aż do następnego endm
          ldi             ; LDI to złożona instrukcja transferu - pobiera bajt danych spod
                          ; adresu w HL, zapisuje pod adres w DE, zwiększa HL i DE i zmniejsza
                          ; BC (które w instrukcji LDIR jest jużwane jako automatyczny licznik
                          ; powodujący wykonanie całej procedury zadaną w BC liczbę razy)
                          ; nie uzywamy LDIR, bo 8 razy LDI jest szybsze niż LDIR, bo nie
                          ; wykonuje wewnętrznie sprawdzenia zawartości BC
        endm              ; koniec dla rept

do_scroll:
        ld hl,20704+31    ; ładujemy do HL adres końca linii w której chcemy wyświetlać scroller
                          ; adres trzeba sobie policzyć zgodnie z organizacją pamięci Spectrum
                          ; tutaj jest to ostatnia ośmiopikselowa linia ekranu
        ld de,buf         ; ładujemy do DE adres bufora znaku, do którego skopiowaliśmy
                          ; 8 bajtów bitmapy
        ld b,8            ; ładujemy do B 8 - b jest licznikiem dla pętli scrollującej

loop1:                    ; tu zaczyna się pętla zewnętrzna  - 8 linii
        push hl           ; odkładamy HL na stos
        ld c,32           ; ładujemy do C 32 - liczba znaków w wierszu
        ld a,(de)         ; pobieramy do A bajt pamięci adresowany przez DE - bajt bufora znaku
        rla               ; przesuwamy zawartość A arytmetycznie o jeden bit w lewo
                          ; oznacza to, że znacznik CY (przepełnienia) wsuwany jest na najmłodszy
                          ; bit A a najstarszy bit A jest wysuwany do znacznika CY
                          ; to pierwsze nie ma dla nas znaczenia, to drugie powoduje, że piksel
                          ; z bufora znajduje się teraz w CY a w A mamy bajt przesunięty o jeden
                          ; piksel
        ld (de),a         ; zapisujemy bajt z A pod DE - z powrotem do bufora

loop2:                    ; tu zaczyna się pętla wewnętrzna - 32 bajty w linii
        ld a,(hl)         ; ładujemy do A bajt spod HL czyli bajt z ekranu, który będziemy scrollować
        rla               ; przesuwamy ten bajt tak jak poprzednio - tym razem bit, który
                          ; wysunęliśmy z bufora do CY wsuwa się od prawej a najstarszy bit z lewej
                          ; wysuwa się do CY
        ld (hl),a         ; ładujemy bajt z A pod HL - przesunięty i uzupełniony o nowy piksel
                          ; z powrotem w ekran
        dec l             ; zmniejszamy L (a co za tym idzie HL) o 1
        dec c             ; zmniejszamy C o 1
                          ; trzeba pamiętać, że INC i DEC nie są tak na prawdę instrukcjami
                          ; arytmetycznymi i jako takie nigdy nie "psują" CY w którym cały
                          ; czas mamy piksel do wsunięcia do kolejnego bajtu
        jr nz,loop2       ; jeśli C nie zawiera 0 to nie uztawił się znacznik Z i w takim
                          ; wypadku skaczemy na początek pętli wewnętrznej scrollując kolejne
                          ; bajty ekranu
        inc de            ; jeśli pętla wewnętrzna się zakończyła zwiększamy DE o 1 - przeskakujemy
                          ; w buforze do kolejnego bajtu znaku
        pop hl            ; podnosimy HL ze stosu
        inc h             ; zwiększamy H o 1 - w efekcie zwiększamy HL o 256
                          ; dzięki organizacji ekranu Spectrum i wybraniu odpowiedniego adresu
                          ; scrollera daje nam to przeskok adresu dokładnie o jedną linię ekranu
        djnz loop1        ; zamykamy pętlę - DJNZ zmniejsza B o 1 i jeśli w wyniku ustawi się
                          ; znacznik Z (czyli B osiągnęło 0) nie wykonuje skoku, w przeciwnym
                          ; razie skacze domykając pętlę zewnwtrzną
        ret               ; wyskakujemy z podprogramu

buf:    ds 8              ; dyrektrywa assemblera rezerwująca 8 bajtów w pamięci
bpos:   db 0              ; dyrektywa assemblera rezerwująca jeden bajt pamięci ustawiająca go na 0
text:   defm "Tekst scrollera... wpisany jako parametr dla defm albo "
                          ; dyrektywa assemblera zapisująca do pamięci ciąg bajtów
                          ; będących reprezentacją kodów ASCII tekstu
        defm "w dowolne miejsce w pamieci a wtedy zamiast text: defm "
        defm "nalezy uzyc text: equ adres_tekstu "
        db 13             ; dyrektywa assemblera rezerwująca jeden bajt pamięci ustawiająca go na 13
        end 32768         ; dyrektywa assemblera - jeśli użyjemy przy kompilacji typu
                          ; wyniku --tapbas to pasmo automatycznie doda loader w którym podany
                          ; adres będzie użyty jako adres startu a to samo minus jeden jako
                          ; adres RAMTOP (a co za tym idzie stos) ustawiony przed załadowaniem
                          ; kodu do pamięci

Zakładając, że kod zapisany jest w pliku scroller.asm kompilujemy go tak:
pasmo --tapbas scroller.asm scroller.tap

W efekcie dostajemy TAP z automatycznie wygenerowanym loaderem.

KWF

  • *****
  • Wiadomości: 6823
  • Miejsce pobytu:
    trzecia planeta od Słońca
  • "I co ja robię tu, u-u, co Ty tutaj robisz ..."
    • Insta do lasownia
Odp: Asembler Z80 i 8080 pod Windows
« Odpowiedź #24 dnia: 2019.03.20, 14:02:47 »
No to pierwsze pytanie. Dlaczego adres startowy wybrałeś 32768, a nie np. 24000 czy 49159?
KWF
-----
R Tape loading error 0:1
Moje zabawki: https://github.com/McKlaud76

SAJ

  • *****
  • Wiadomości: 1484
  • Miejsce pobytu:
    Terra Prime
Odp: Asembler Z80 i 8080 pod Windows
« Odpowiedź #25 dnia: 2019.03.20, 14:13:29 »
Bo tam jest orgazm  :)

Mysle, ze dobrze jest poznac mape pamieci Komputera, bo na 16Kilo-bajtowym ZetIksie to nie ruszy.

matofesi

  • *****
  • Wiadomości: 2048
  • Miejsce pobytu:
    Toruń/Poland
Odp: Asembler Z80 i 8080 pod Windows
« Odpowiedź #26 dnia: 2019.03.20, 14:18:09 »
No to pierwsze pytanie. Dlaczego adres startowy wybrałeś 32768, a nie np. 24000 czy 49159?

Przyzwyczajenie - pamięć od 32768 nie jest contended i jeśli tylko kod się mieści to zawsze go umieszcza właśnie tam.

Mysle, ze dobrze jest poznac mape pamieci Komputera, bo na 16Kilo-bajtowym ZetIksie to nie ruszy.

A to jest jakby oczywiste. Nigdy nic nie pisałem na ZXS 16K i raczej nie zamierzam sobie tym zawracać głowy ;)

Maryjan

  • *****
  • Wiadomości: 6650
  • Miejsce pobytu:
    Skarżysko-Kam.
  • Scotch whiskey and West Highland Terrier
Odp: Asembler Z80 i 8080 pod Windows
« Odpowiedź #27 dnia: 2019.03.20, 15:09:12 »
Czy taki kod jest relokowalny ?
Tzn. da się go załadować i uruchomić z innego adresu ?

Dlaczego pytam, ponieważ interesuje mnie umieszczanie kodu np. w lini 0 po REM.
Czy umieszczenie takiego programu w 2-gim trybie przerwań, pozwoli na załadowanie czegoś np. z dyskietki ?

Kiedyś widziałem taki loader dla programu dla FDD 3000.
Stacja doczytywała, a w tle grała muzyka i leciał scroll.
"Co miałem powiedzieć - przeczytałem..." Nikodem Dyzma

steev

  • *****
  • Wiadomości: 1362
  • Miejsce pobytu:
    inode 42
Odp: Asembler Z80 i 8080 pod Windows
« Odpowiedź #28 dnia: 2019.03.20, 15:23:08 »
Czy taki kod jest relokowalny ?
Tzn. da się go załadować i uruchomić z innego adresu ?
Zazwyczaj nie.
Musisz go wtedy skompilować tak, żeby wpadł pod konkretny adres.

Kiedyś widziałem taki loader dla programu dla FDD 3000.
Stacja doczytywała, a w tle grała muzyka i leciał scroll.
Z FDD3000 to nie sztuka.
Przy ładowaniu danych procesor albo się nudzi, albo odbiera dane od stacji...
Machines should work. People should think.

matofesi

  • *****
  • Wiadomości: 2048
  • Miejsce pobytu:
    Toruń/Poland
Odp: Asembler Z80 i 8080 pod Windows
« Odpowiedź #29 dnia: 2019.03.20, 15:28:35 »
Czy taki kod jest relokowalny ?
Tzn. da się go załadować i uruchomić z innego adresu ?

Nie jest. Ale jak się uprzeć da się to zrobić tylko to jest albo kombinowanie, żeby adresy zmiennych/tablic jakoś wyliczać w locie albo trzeba zrobić procedurę relokującą na początku. Ogólnie - prostsze rzeczy daje się dość łatwo zrobić tak, żeby były relokowalne, większe znacznie trudniej.

Najprostszą metodą jest skompilowanie pod konkretny adres gdzieś wyżej i dopisanie na początku procedury, która ustali, gdzie się znajduje i przerzuci to co jest za nią we właściwe miejsce i skoczy gdzie trzeba. A na koniec trzeba to wszystko skleić, zrobić odpowiednio dużo miejsca po REM i wkopiować cały sklejony kod.