Z80: Revizyonlar arasındaki fark

Retrojen Wiki sitesinden
Gezinti kısmına atla Arama kısmına atla
İlkerg (mesaj | katkılar)
Ref (mesaj | katkılar)
 
(3 kullanıcıdan 27 ara revizyon gösterilmiyor)
6. satır: 6. satır:


== Genel Bilgi ==
== Genel Bilgi ==
Z80, 8bitlik bir işlemci olup 8bitlik data hattına, 16 bitlik adres hattına ve çeşitli kontrol sinyallerine sahip bir işlemcidir. 64KByte adresleyebilir. Normal memory adreslemesinin yanında çeşitli IO komutları sayesinde 64K IO bölgesi adresleyebilir.
Z80, 8bitlik bir işlemci olup 8bitlik data hattına, 16 bitlik adres hattına ve çeşitli kontrol sinyallerine sahip bir işlemcidir. 64KByte belleğe erişebilir. Normal bellek adreslemesinin yanında çeşitli IO komutları sayesinde 64K IO bölgesi adresleyebilir.


== Yazmaçlar ==  
== Yazmaçlar ==  
13. satır: 13. satır:
===Program Kontrol Yazmacı===
===Program Kontrol Yazmacı===


PC : Program Counter. İşlemcinin a onda çalışmakta olduğu hafıza adresini gösterir.
PC : Program Counter. İşlemcinin o anda çalışmakta olduğu hafıza adresini gösterir.


===Yığıt Yazmacı===
===Yığıt Yazmacı===
134. satır: 134. satır:
== Ayrıca Bakınız ==
== Ayrıca Bakınız ==


[[:Kategori:Z80 İşlemci Komutları]] | [[Z80 Bayrakları]] | [[:category:Z80 İşlemcisi Özellikleri]]
[[:Kategori:Z80 İşlemci Komutları]] | [[Z80 Bayrakları]] | [[:category:Z80 İşlemcisi Özellikleri]] | [[Zx Spectrum Kodlama Örnekleri]] | [[byte ve bit]]
 
== Sıkça Sorulan Sorular ==
'''Soru 1 (HADES):'''
Yazdığım kodlarda IM 2'yi kullanıyorum ama Basic ekranına geri dönüş yapmayıp normal rutinde JR ile döngü yapıyorum.
Hem Irq kullanıp hem Basic nasıl kullanılır? Aklıma IM 1 kullanmak geliyor ama nasıl olacak?
 
'''Cevap 1 (REF):'''
Anladığım kadarıyla bir basic programı çalışırken, diğer taraftan asm ile müzik çaldırmak istiyorsun.
 
Spectrumda bir tek IM2'yi kullanabiliyoruz. IM1 ROM'a göre zıplıyor, dolayısı ile yapacak bişey yok.
 
IM2'yi kurması da gıcık aslında. Çünkü şöyle bir durum var. IM2 işaretçi adresinin hesaplanacağı adres şu şekilde hesaplanıyor (evet suyunun suyu şeklinde):
 
Adresin üst byte'ı I yazmacında tutuluyor. Fakat alt byte'ı takılı olan aygıt belirliyor. Eğer bir aygıt takılı değil ise, floating bus sebebi ile bu alt byte random olabiliyor. Dolayısı ile IM2 kurmak için 257 byte'lık bir alanı *aynı* byte'lar ile doldurmak gerekiyor ki, adres nereye düşerse düşsün pointer değişmesin.
 
Örnek. Diyelim ki I'yı 254 yaptınız. Bu şekilde IM2 pointer'ının okunacağı adres (yüksek byte'a göre) 65024 oldu. Fakat IM2 düşük byte 0-255 arasında rast gele bir değer. Dolayısı ile eğer düşük byte 0 olursa sizin kesme rutininizin bulunacağı adres 65024 ve 65025 byte'larından hesaplanacak. Eğer bu adreslerin ilkinin değeri "1", ikincisinin değer i"0" olursa, interrupt olduğunda, 255 adresine zıplanır.  Fakat IM2 düşük byte başka bir rakam olsa, zıplanacak adres başka bir lokasyondan hesaplanacağı için, IM2 başka bir yere zıplar.
 
Ben asmp multicolor aracını kodlarken şöyle bir yöntem izledim. 65024'den itibaren 257 byte boyunca #FD ile doldurdum. I'ya 254 yükleyince her durumda IM2 vektörü #FDFD oluyor, yani 65021'e zıplanıyor. Bu adrese istediğin şekilde dallanabilirsin, ben timing için yaptığım için buraya RET girdim, böylece halt ile durduktan sonra IM2 olduğu gibi program senkronize olarak devam ediyor.
 
Dikkat, Interrupt rutini asla 32768'den aşağıda olmamalı!
 
Senin durumunda ise basic çalışsın istiyorsun, fakat IM1 servis rutinide çalışsın istiyorsun. Bu durumda servis rutininin yaptığı işi senin yapman gerek.
 
Neyse benim kodu asmp'den copy-paste ediyorum:
Önce IM2'yi kuralım
di  ;interrupt'ı kapatalım
 
ld hl,65021
 
ld (hl),#C3 ;jump kodunu yerleştirelim, dikkat bu şekilde yapmak mecburi değil
inc hl        ;vektör tablosunu 253'le değil başka bir rakamla doldurursanız
ld hl, #c0  ;istediğiniz yere zıplatırsınız zaten
inc hl
ld hl, #c7  ; yani #C3 #C0C7 (JP 47040)
               
 
ld  hl,65024  ;şimdi aralığı FD ile dolduracağız.
ld  de,65025
ld  (hl),253
ld  b,e
ld  c,e
ldir
 
ld  a,254  ;Artık IM2'yi kurabiliriz.
ld  i,a
im  2 ;im2'ye geçtik
 
ei  ;interruptlar açık
Bu da basic'i çalışır durumda tutmanın bir yöntemi:
org #C0C7  ;yukarıdaki örneğe göre kod 47040'dan başlamalı.
 
di  ;alışkanlık
ld (stackpointer),sp ;mecbur değilsen sp'yi yazmayabilirsin
ld sp,stackpointer  ;garanti olsun diye yerini de değiştiriyorum (18 byte'lık bir yer lazım)
 
Push HL  ;basic'in kullandığı yazmaçları saklayalım
Push BC
Push DE
Push AF 
 
exx        ;söylentiye göre basic için alternatif yazmaçları saklamaya gerek yok
Push HL  ;ama yine de koyalım bir kenara
Push BC
Push DE
 
CALL muzik  ;müziğimizi çalalım
 
rst 56 ;ROM'daki servis rutini, klavyeyi okur, sayacı ilerletir
 
LD sp,stackpointer-14 ;basic'e dönmeden önce herşeyi geri yerleştirelim
Pop DE
Pop BC
Pop HL
 
exx
pop af
pop de
pop bc
pop hl
 
ld sp,(stackpointer) ;herşeyi geri aldık
;IM1 ;Bu noktada IM1 işletsek, basic'e olduğu gibi geri dönülmüş olur.
ei  ;interrupt'ı çalıştır.
ret  ;geri dön, dilerseniz RETI de kullanabilirsiniz.
 
stackpointer:
defb 0
----------------------
Bu koda göre IX/IY registerini kullanamazsınız, basic kullanıyor, istiyorsanız onları da kaydetmelisiniz.
 
Bu efektif yöntem mi bilmiyorum ama benim kullandığım yöntem bu. Özetlersek (değerler decimal):
 
1. IM2 için 257 byte uzunluğunda vektör tablosu oluştur. (tablo 220'lerden oluşursa adres 220*256+220= 56540 olacak)
2. I'yı bu tablonun başına point et.
3. vektör tablosundaki adrese rutinini koy
4. rutin başladığında basic değişkenlerini sakla (PUSH <hepsi>)
5. işini yap: (CALL x)
6. basic servis rutinini çağır (rst 56)
7. basic değişkenlerini geri çağır (POP <hepsi>)
8. geri dön (reti/ret)
 
 
'''Soru 2 (İLKER):'''
Örnek kodlardan biri ekrandaki resmi dikey olarak ters çeviriyor (Vertical Flip). Ancak ben bunu denemek için ekranda bir oyundan resim olsun istiyorum bunu yapabilir miyim?
 
'''Cevap 2 (MEMRAH):'''
Soyledigini yapmanin bir suru yolu var. En basitlerinden bahsedeyim. ZX Spin kullandigini varsayarak, herhangi bir SCR dosyasini Spin'in emulasyon penceresine cekersen zaten icerigini spectrum'da 16384'ten itibaren ekran bellegine yukler. Elimizde bir tane SCR dosyası olsun. SCR dosyasini bir kenara (ornegin masa ustune) alıyoruz. Uzerinde calistigin kodu assemble et. Daha sonra eger 128 modunda isen EDIT menusunden SCREEN moduna gecmeni tavsiye ederim ki editor surekli ekrani silmeye kalkmasin. Daha sonra SCR dosyasini SPIN'in ana penceresi uzerine surukle ve birak... Resim ekranda... Daha sonra RANDOMIZE USR XXXXX ile kodu calistirabilirsin..
 
Diger yollar, oyunlarin TAP dosyasinin icine tape browser ile girip SCREEN$ dosyasini 16384 ile 16384+6912 arasina yuklemek, vs.
 
(istedigin oyunun TAP dosyasini indir, Spin'de Tape Browser'da ac, uzunlugu 6912 olan dosya ekran dosyasidir, bunu bul, LOAD "" CODE 16384,6912 yaz ve TAPE' i baslat)
 
== Açıklamalı Örnek Kodlar ==
'''HADES ÖRNEK 01 - HAFIZADA 4K'LIK BİR BÖLGEYİ TEMİZLEYEN BİR RUTİN:'''
 
LD HL,$8000 <br>
LD DE,$8001 <br>
LD BC,$1000 <br>
LD (HL),0 <br>
LDIR <br>
RET <br>
 
$8000-$9000 arasını "0" ile dolduruyoruz.
 
'''Açıklaması:''' <br>
'''LDIR komutu''':  <br>
Bellekteki herhangi bir alani baska bir alana kopyalamak icin kullanilan dongusel komutlardan birisidir. (Bir digeri icin bkz. LDDR)
<br>
'''Calisma sekli:'''  <br>
LDIR komutu yurutulmeden once 3 yazmac gerekli parametreler ile yuklenir.
 
HL ciftine, kopyalanmak istenen (kaynak) alanin baslangic adresi,
DE ciftine hedef alanin baslangic adresi,
BC ciftine ise baslangic adresinden itibaren kac byte kopyalanacagi yuklenir.
 
Ardindan LDIR komutu verilerek kopyalama gerceklestirilir.
 
Gercekte LDIR komutu bir islemler dongusunu baslatir. Adim adim incelersek, LDIR komutu verildiginde, ilk olarak;
 
LD (DE),(HL) islemi ile DE'nin isaret ettigi adrese HL'nin isaret ettigi adresteki deger yuklenir.
 
Ardindan DE ve HL 'nin degerleri 1 arttirilir ve BC 'nin degerinden ise 1 eksiltilir. Dongu kontrol degiskeni olarak BC yazmaci kullanilir ve dongu BC'nin degeri 0 oluncaya kadar tekrar eder. Komutun calisma suresi kopyalanacak byte miktarina bagli olarak degisir.
 
Hades'in verdigi ornekte, hedef alan, kopyalanacak kaynak alanin sadece 1 byte ilerisinde oldugu icin, kaynak alanin ilk byte'inda tutulan deger (Hades'in orneginde 0) hemen bir ilerisindeki adrese yazilacak.  Ardindan da HL ve DE yazmaclari birer arttirilacagi icin bir bu defa bir onceki adimda hedef alanda olan adres bu kez kaynak alana girecek, ve icerisinde tutulan deger (0) yine kendisinden sonraki adrese kopyalanacak. Bu da BC'deki deger yani $1000 (dec.4096) sifirlanana kadar, yani 4096 kere tekrarlanarak, 4K'lik bir RAM alanini 0'larla dolduracaktir.
 
Bu tarz bir kullanim ornegin ekran bellegi bolgesini (ZX Spectrum'da 16384 ten baslayan 6912 byte) sifirlamak sureti ile ekrani silmek amaci ile kullanilabilir. Tabi kullanim alani bununla sinirli degildir.
 
LDIR genel olarak son derece kullanisli bir komuttur.
DJNZ (Decrease and Jump if Not Zero) ()
255 defa'ya kadar tekrarlanmasi istenen islemleri bir donguye sokmak icin kullanilabilir.  Dongu kontrol degiskeni olarak B yazmaci kullanilir. B yazmacindaki sayi 0'dan buyuk oldugu surece, DJNZ komutu isletildiginde, komutun isaret ettigi adrese atlanir.
 
B yazmacindaki deger her DJNZ komutu calistirildiginda bir eksiltilir ve 0'a ulastiginda, DJNZ komutunun isaret ettigi adrese atlama yapilmaz. Onun yerine DJNZ komutundan bir sonraki komuta atlanir.
 
Ornegin asagidaki rutin NOP komutunu 128 kere calistirir:
 
LD B,128
islemyok:
NOP
DJNZ islemyok
RET


== Kaynakça ==
== Kaynakça ==

17.09, 16 Ekim 2015 itibarı ile sayfanın şu anki hâli


Genel Bilgi

Z80, 8bitlik bir işlemci olup 8bitlik data hattına, 16 bitlik adres hattına ve çeşitli kontrol sinyallerine sahip bir işlemcidir. 64KByte belleğe erişebilir. Normal bellek adreslemesinin yanında çeşitli IO komutları sayesinde 64K IO bölgesi adresleyebilir.

Yazmaçlar

('Register'lar)

Program Kontrol Yazmacı

PC : Program Counter. İşlemcinin o anda çalışmakta olduğu hafıza adresini gösterir.

Yığıt Yazmacı

SP : Stack Pointer. Yığın işlemleri için kullanılacak bölgenin başlangıç adresini gösterir. Kullanıcı tarafından değiştirilebilir.

Sayım Yazmaçları

B ve C yazmaçları genellikle sayım işlemi yapan komutlar tarafından kullanılır. Örn. DJNZ, LDIR.

Birikeç (Akümülatör)

A, Özel bir yazmaçtır. Birçok komut değerin önce A'ya yüklenmesini gerektirir.

Adres Yazmaçları

D, E, H, L ya da çift olarak kullanıldıklarında DE ve HL yazmaçları, genellikle bir adresi göstermek için kullanılırlar. DE genellikle DEstination (hedef) olarak kullanılır. HL ise adresin Hi(üst) ve Low(alt) byte sırasını daha kolay göstermesi için HL olarak isimlendirilmiştir.

8 bitlik registerlerden B ve C, D ve E, H ve L birlikte kullanılarak BC, DE, HL registerleri 16 bitlik olarak kullanılabilir. Yazmaç çiftleri alfabetik sıra ile yazılır ve kullanılırlar. Örn. CB=yanlış, BC=doğru.

Bayrak Yazmacı

Yapılan işlemin sonucuna göre değişen bitlere sahip F (Flag) yazmacı. Bu yazmaç ve bayraklar hakkında detaylı bilgi için Z80 Bayrakları başlığına bakınız.


Değiş-Tokuş Yazmaçları

Ayrıca Alternate register denilen AF', BC', DE' ve HL' registerleri vardır. Bu registerlere doğrudan erişim yoktur. EX AF,AF' komutu ile AF register çifti AF' register çiftiyle, EXX komutuyla ise BC, DE, HL register çiftleri BC', DE', HL' register çiftleriyle yer değiştirir. Daha doğrusu bu register çiftlerinde tutulan değerler yer değiştirir. Mesela LD BC,$4000 - LD DE,$5000 ve LD HL,$6000 olsun. EXX komutuyla $4000, $5000 ve $6000 değerleri Alternate registerlere aktarılır. Alternate registerlerdeki değerler asıl registerlere aktarılır. POP ve PUSH komutlarını kullanmaya gerek kalmadan Alternate registerleri geçici olarak saklama yeri gibi düşünebilirsiniz.

İndeks Yazmaçları

Z80'de iki adet index registeri bulunur ve 16bitlik yapıdadır. IX ve IY olarak adlandırılır. Gerekirse sanki 8 bitlik iki registerden oluşmuş gibi kullanılabilir. Alt 8 bitleri için LX, LY ve üst 8 bitleri için HX, HY olarak adlandırılan -undocumented opcodes- komutları bulunmaktadır.

İndeks yazmaçları IX ve IY aslında kullanım olarak HL yazmacına benzer. Fakat benzer komutların IX/IY ile kullanılan biçimleri 1 byte daha uzundur. Dolayısı ile bu indeks komutları, aynı işi yapan diğer komutlara göre daha yavaştır.

Diğer Yazmaçlar

  • I Registeri : Interrupt kontrol registeridir
  • R Registeri: Dinamik Ramler için kullanılan Refresh registeridir.
  • Son olarak IFF1 (Interrupt Flip Flop 1) ve IFF2 (Interrupt Flip Flop 2) registerleri bulunmaktadır. Herhangi bir IRQ veya NMI oluştuğunda içerikleri değişmektedir.

Bayraklar

('Flag'ler)

Detaylı bilgi için bkz. Z80 Bayrakları

Yapılan işleme göre durum değiştiren bitlerdir.

7.bit - S - İşaret biti 6.bit - Z - Sıfır biti 5.bit - Kullanılmıyor. 4.bit - H - Yarı-Elde biti 3.bit - Kullanılmıyor. 2.bit - PV - Eşlik biti 1.bit - N - Çıkarma biti 0.bit - C - Elde biti


Giriş/Çıkış birimlerinin kontrolü

Z80 özellik olarak G/Ç komutlarına sahiptir. IN ve OUT komutlarıyla herhangi bir donanımla bilgi alışverişi yapabilir. Mesela ZX Spectrumun ekran belleği, donanımsal olarak IO adreslemeli bir yapıda olsaydı komutlarımız aşağıdaki şekilde olacaktı.

LD BC,$4000 ; 16384 ekran belleğinin başlangıç adresi. LD A,$FF ; Akümülatöre $FF (255) sayısını yerleştiriyoruz. OUT (C),A ; 16384 numaralı ekran belleği adresine aküdeki değeri yazıyoruz.

Normalde ZX Spectrumda ekran belleğine aşağıdaki şekilde yazarız.

LD A,$FF LD ($4000),A

veya

LD HL,$4000 LD (HL),$FF

Z80'nin G/Ç komutlarına sahip olması donanım tasarımı açısından büyük esneklik sağlar. Nitekim Spectrum'un joystickleri IN komutuyla okunur.


İşlem Komutları

(Opcode'lar)

Opcode : Operation Code. Yani bir işlemcinin yapacağı işlemi belirten koddur. İşlemci o anki opcode'a göre ne işlem yapacağını bilir. Z80'de komutların opcode'ları aşağıdaki şekilde olabilir.

(Opcode'lar hexadecimal formatta verilmiştir) (nn : $00..$FF arasında bir baytlık değer) (nnnn : $00 ... $FFFF arasında iki baytlık bir değer)

Z80 komutları 1, 2, 3 veya 4 bayt uzunluğunda olabilir.

Teorik olarak 256 komut var gibi gözüksede CB, DD, ED, FD opcode'ları birer önkod olup devamında 1, 2 veya 3 bayt daha olabilir. Ön koda sahip komutlarla beraber toplam komut sayısı 705 dir. Eğer kullanıcı kılavuzunda dökümante edilmemiş opcode'ları da sayarsak toplam komut sayısı 1278 olmaktadır.


Tek baytlık ve parametre almayan opcode'lar

00 : NOP
76 : HALT
C9 : RET 

Tek baytlık ve bir parametre alan opcode'lar

06 nn : LD B,nn
DE nn : SBC A,nn

Tek baytlık ve iki parametre alan opcode'lar

21 nn nn : LD HL,nnnn 
FC nn nn : CALL M,nnnn


İki baytlık ve parametre almayan opcode'lar

ED B8 : LDIR
DD E5 : PUSH IX 

İki baytlık ve bir parametre alan opcode'lar

DD 7E nn : LD A,(IX+nn)
DD AE nn : XOR (IX+nn)

İki baytlık ve iki parametre alan opcode'lar

DD 21 nn nn : LD IX,nnnn
FD 22 nn nn : LD (nnnn),IY


Üç baytlık ve bir parametre alan opcode'lar

FD CB nn 06 : RLC (IY+nn)
DD CB nn FE : SET 7,(IX+nn)


Ayrıca Bakınız

Kategori:Z80 İşlemci Komutları | Z80 Bayrakları | category:Z80 İşlemcisi Özellikleri | Zx Spectrum Kodlama Örnekleri | byte ve bit

Kaynakça

Hades | Ref