Gönderen Konu: Retrospektif: Speedlock  (Okunma sayısı 23311 defa)

0 Üye ve 3 Ziyaretçi konuyu incelemekte.

Çevrimdışı matahari

  • RAAT
  • Retro Meraklısı
  • *
  • İleti: 209
    • The Blog of Mert Börü
Retrospektif: Speedlock
« : 22 Nisan 2022, 01:04:00 »
Retrospektif: Speedlock

Önsöz

Retrojen Forum’a yazdığım iletilerin birçoğunda;
  • 80’lerin başında bana vizyon katan ECOM Mühendislik’ten bahsetmiş, üzerimde çok emeği olan rahmetli Mahir Bey’in ismini birkaç kez anmış, ancak forum üyelerinin ilgisini çekmeyeceğini düşünerek detaya girmekten sakınmıştım.
  • 80’li yıllar boyunca oyun kırmamın ve reverse engineering yapmamın bana ne kadar fayda sağladığından ısrarla söz etmiş, ancak yazabileceklerimin fazlasıyla kişisel ve sıkıcı bulunabileceğinden çekinerek daha ileri gitmemiştim.
  • Z80 kodlama ve Amstrad temalı başlıklara ileti gönderme konusunda pek bonkör davranırken, Sinclair ZX81 ve ZX Spectrum temalı başlıklara birkaç istisna dışında -nedense- pek ilgi göstermemiştim. (Açıkçası sebebini hâlâ anlayabilmiş değilim.)
Bilge dostum @Alcofribas’ın farklı zaman ve mekanlarda birçok kez kulağıma üflediği "bilginin zekâtı" kavramının sanırım din-imanla bir ilgisi olmadığını nihayet idrak etmiş olacağım ki, yukarıda sözünü ettiğim eksiklikleri giderme vaktinin geldiğine inanarak, Sinclair ZX Spectrum’un 40. doğum günü vesilesiyle yeni bir ileti hazırlamaya karar verdim.

İtiraf etmeliyim ki, bu kararı vermemde;
  • Retrojen Sayı:1 için kaleme aldığım "Turbo Loader" makalemin yıllar içerisinde giderek artan bir ilgiyle okunması, paylaşılması ve tartışılması,
  • Aynı makale için yazdığım Z80 Assembly kodlarını blog’umda paylaştıktan sonra bazı uluslararası retro forum ve YouTube kanallarının bu kodları kucaklayarak sahiplenmesi,
  • Fazlasıyla kişisel olmasından dolayı biraz çekinerek paylaştığım "Retrospektif: Mission Genocide" isimli anı-teknik inceleme çalışmamın beni şaşırtacak derecede ilgi ve beğeniyle karşılanması,
çok etkili oldu. Zira, yazdıklarımın "güzel işlere vesile olduğunu" görmek beni fazlasıyla motive etti. Benzer duyguları, yıllar önce yazdığım bir kitap sayesinde programlamaya ilgi duyarak kodlamaya başlayan ve hatta meslek olarak programcılığı seçen genç okurlarımın geribildirimlerinde de yaşamıştım. İşte tam da bu sebeple; üzerimizdeki ölü toprağını silkeleyerek coğrafyanın kader olmadığının (!) anlaşılmasına belki bir nebze katkı sağlayabilirim umuduyla, yeni iletimi kişisel blog’umda İngilizce olarak yayınlamak yerine, herkesin kolayca erişebileceği tamamen açık bir ortam olan Retrojen Forum’da anadilimde paylaşmaya karar verdim.

Uluslararası literatürde Z80 tabanlı turbo loader’lar hakkında yok denecek kadar az sayıda yazılı çalışma olması ve başta Jon North, Richard P. Swann, Craig Daines, Frantisek Fuka ve Chris Smith’in kişisel notları olmak üzere, mevcut çalışmaların "tecrübeye ve karşılaştırmalı örneklere dayalı olmaksızın" her kitapta kolayca bulunabilen türden bilgiler içermesi sebebiyle, az sonra okuyacaklarınızı biraz da bu eksiklikleri gidermeyi umarak kaleme alıyorum. 38 yıl önce yaşadıklarımı en ince detayına kadar hatırlamaya çalışarak, o günlerden elimde hiçbir kaset/disket olmaması nedeniyle sadece yazılı notlarıma sadık kalarak, tüm kodlarımın çalışırlığını emülatör üzerinde hassasiyetle doğrulayarak sizlerle paylaşıyorum. Yazdıklarımı birebir takip etmek (ve hatta uygulamak!) isteyen okurlar için, bu iletinin sonuna metnin içinde sözü edilen oyunların .TZX dosyalarını da ekliyorum. Gözümden kaçan eksiklikler ve/veya yazım hataları mutlaka vardır; şimdiden affolunmasını rica ediyorum.

Bilenler bilir; gerekmedikçe geçmişten söz etmeyi, "şöyle yaptım, böyle yaptım" demeyi pek sevmem. Ölü Ozanlar Derneği’nden kalma bir iz olsa gerek, içinde bulunduğumuz anı yaşamayı, daha ziyade bugünden bahsetmeyi, şu anda üzerinde çalıştığım güncel projelerden söz etmeyi tercih ederim. Buna karşın, eğer kaçınılmaz olarak geçmişten bahsetmem gerekirse de, anlattıklarım içerisinde edinilecek bilgi ya da alınacak ders olmasına özen gösterir, böylece dinleyenlerin vaktini boşa harcamamaya çalışırım. Aşağıdaki metni bu vizyon doğrultusunda kaleme aldığımı vurgular, hem bir dönemi kayıt altına almak hem de okuyanlara fayda sağlamak amacıyla paylaştığımı içtenlikle belirtmek isterim. Asıl kalıcı olan, kişiler ve mekanlar değil, yaşananlardır.

Keyifli okumalar dilerim…

Çevrimdışı matahari

  • RAAT
  • Retro Meraklısı
  • *
  • İleti: 209
    • The Blog of Mert Börü
Ynt: Retrospektif: Speedlock
« Yanıtla #1 : 22 Nisan 2022, 01:04:41 »
Bölüm 1
"Uncle Ted"

Eylül, 1984.

Okulların açılmasına birkaç hafta vardı. Yaşıtlarımın eğlenerek geçirdiği yaz tatili, benim için fazlasıyla yoğun ama bir o kadar da keyifli geçmişti. Ne de olsa, Kadıköy Yazıcıoğlu Pasajı’nın 2. katındaki ECOM Mühendislik bünyesinde Sinclair ZX Spectrum için geliştirilen ve Tepum tarafından pazarlanacak olan Kartoteks programının yazılmasına katkıda bulunmuştum. Özünde BASIC ile çalışan bu uygulamanın arka planındaki kasetten veri yükleme/kaydetme kodlarının tümünü Assembly ile yazmıştım. Güvenlik sebebiyle dosya içeriklerini headerless olarak saklamam ECOM bünyesinde pek olumlu karşılanmış, teknik açıdan Mahir Çelikkanat Bey’den tam not almıştım.

Aslında oldukça basit bir işti yaptığım. Örneğin, hafızanın 32768. byte’ından itibaren toplam 2 KB’lık veriyi binary (data) formatta kasete kaydetmek için

Kod: [Seç]
ld ix,32768
ld de,2048
ld a,255
scf
call &04c2

benzeri minik fonksiyonlar yazmış, tüm headerless yükleme işlemleri için LD-BYTES (&0556), kaydetme işlemleri için de SA-BYTES (&04C2) subroutine’lerini ZX Spectrum’un ROM’undan çağırmıştım.

Ne iyi etmiştim Mahir Bey’in sözünü dinlemekle; bana ısrarla "Bu kitabı mutlaka edinmelisin!" diyerek Melbourne House tarafından yayınlanan 1983 baskısı The Complete Spectrum ROM Disassembly isimli eseri tavsiye etmiş, bir bakıma çok daha low-level kod yazmamın önünü açmıştı. Harçlığımı aşan fiyatı sebebiyle kitabı uzun süre alamamış, her gidişimde Mahir Bey’in kitabından okuyabildiğimi okur, işime yarayan kısımları defterime not ederdim. Kartoteks programını yazarken, aldığım bu notlardan çok faydalanmış, Spectrum’un ROM’unu oluşturan fonksiyonların nasıl yazıldığını kavrayarak çok daha iyi kod yazmaya başlamıştım. Neyse ki proje bitimine birkaç ay kala kitabı edinebilmiş, bir bakıma kendimi ödüllendirmiştim.

Kartoteks uygulaması teslim edildikten kısa bir süre sonra, ECOM bünyesinde bulunan envai çeşit Epson dot-matrix yazıcılar yardımıyla fiyat listeleri kağıda dökülmüş, ürün raflardaki yerini almıştı. İşin en güzel yanı, uzun süredir satın almak istediğim, Tepum’un Nişantaşı’ndaki merkezine her gittiğimde vitrine yapışıp kalmama neden olan, büyük bir merak ve hayranlıkla arzuladığım Currah μSpeech donanımı, emeğimin karşılığı olarak bana hediye edilmişti. Zaten insan 14 yaşındayken başka ne isteyebilir ki?! Dünyalar benim olmuştu. Artık o donanımı kullanarak uzun süredir kafamda dönüp duran heceleme yazılımı fikrine odaklanabilirdim.

Hemen kolları sıvadım. Sabahtan akşama kadar yeni projem üstünde çalışmam sebebiyle, lastik tuşlu (ki biz ona güzel kokulu Japon silgilerini hatırlatması sebebiyle "silgi tuşlu" demeyi tercih ederdik) ZX Spectrum’umun uzun süreler boyu açık kalması, en azından okullar açılana kadar bu yoğun tempoya dayanması gerekiyordu. Yaz sonu sıcağında bilgisayarımın bu kadar uzun süre açık kalmasından rahatsız olduğumu gören babam, dergilerde birkaç ay önce müjdesi verilen ve çok yakında piyasaya çıkması beklenen QL kasalı ZX Spectrum+ için arada bir ağzımı arar, "Nasıl o yeni model, havalandırması daha mı iyi?" diye damarıma basar, şakayla karışık beni kızdırırdı.

Sanırım adamcağızın içine doğmuş… Birlikte Beşiktaş’ta güzel bir Cumartesi gezisi yaparken, Çırağan yolunun solundaki kırtasiyecinin rafında duran ZX Spectrum+ kutusu gözümüze ilişti. "Bu alet ne zaman piyasaya çıktı yahu?!" diyerek, şaşkınlıkla birbirimize baktık. Hemen dükkana girdik. Satıcı bize bu modelden elinde sadece 1 tane olduğunu, ürünün Almanya’dan kaçak geldiğini, Tepum garantisinde olmadığını ve üzülerek (!) tüm kitaplarının İngilizce olduğunu söyledi. Babam, anlatılan "çelişkili" bilgilerin tümünü dikkatle dinledikten sonra, bir dakika bile düşünmeden cebinden çek defterini çıkarıp ödemeyi yaptı. Ben hâlâ olayın şokunu atlatamamış, kucağımdaki kutu ile bir an önce eve gitmek için heyecanlanırken, satıcı arkamdan seslenerek "Oyunlarını almayacak mısın, delikanlı?" diye seslendi. Şeffaf kapağı sayesinde içerisindeki 8 adet oyunu (Cookie, Reversi, Backgammon, Chequered Flag, Jet Pac, Pssst, Chess, Flight Simulation) kolaylıkla görebildiğim ince siyah kutuyu ZX Spectrum+ paketinin üstüne koydu, ardından da gevrek gevrek gülümseyerek "Haydi, şimdi git bakalım!" dedi. Oyunlardan birkaçı kaçak kopya olarak zaten bende vardı. Şimdi hiç yoktan 8 tane orijinal kasette oyunum olmuştu!

İşin aslını yıllar sonra forumlardan öğrendim; meğer o yıl Eylül başında Almanya’da piyasaya sürülen ilk parti Spectrum+’lar, ters çevirilince tuşlarının dökülmesi sebebiyle apar topar piyasadan geri çekilmiş, sorun kısmen giderildikten sonra dünya çapındaki dağıtım Ekim’in ikinci haftasına sarkmış, bu kez de İngiltere’deki şikayetlerin ardı arkası kesilmemiş ve Sinclair ürünlerinin düşük üretim kalitesi yerel basında uzun süre sorgulanıp tartışılmış. Bilgisayarımı ters çevirmek aklıma bile gelmediği için, o günlerde bu sorunun varlığından habersizdim elbet...

O akşam gıcır gıcır parlayan simsiyah kutusuyla ZX Spectrum+ evimizin baş köşesindeki yerini alırken, emektar silgi tuşlu Spectrum da ECOM’a konsinye olarak bırakıldı. Artık keyfime diyecek yoktu. Çok daha serin çalışan, reset tuşlu, QL görünümlü ZX Spectrum+ ve arkasına takılı olan Currah μSpeech ile yoluma devam edecektim. Artık günler-geceler boyunca kod yazabilecek donanım ve motivasyona sahiptim.

24 saat geçmeden hiç hesapta olmayan bir olay patlak verdi! Annem gülücükler saçarak, "Senin için sürpriz bir tatil planımız vardı, nihayet işlemler tamamlandı. Gemi ile 12 günlük Akdeniz seyahatine çıkıyoruz" dedi. Açıkcası, ZX Spectrum+’ıma daha yeni kavuşmuşken tatile matile gitmek istemiyordum. İsteksizce sevinmiş gibi yapıp, sıkılmamak için yanıma Sinclair User ve Sinclair Programs dergilerimi alacağımı söyleyerek kendimi avuttum.

Yola çıkacağımız sabah Karaköy Limanı’na gittiğimizde yaşadığım şaşkınlığı dile getiremem. Bildiğimiz Aşk Gemisi’ydi bu! Geminin ismi olan "Akdeniz", yüzen şatonun beyaz gerdanına yakışan bir kolye edasıyla beni büyülemiş, bir anda tatil fikrine sıkıca sarılmamı sağlamıştı. Gemi her gece seyredecek, her sabah gözümüzü yeni bir limanda açacaktık. Sanırım hayatımın en güzel yazı olacaktı bu…

Yola çıkışımızın ikinci gününde gemideki herkes birbiriyle kaynaştı. Çok kısa süre içerisinde bir sürü arkadaş edindim. Bunlardan biri de, geminin havuzuna atlamak isterken ayağı kayıp düşen 50’li yaşların sonunda hafif göbekli bir İngiliz amcaydı. Yardım etmek için yanına koşup, "Bir şeye ihtiyacınız var mı efendim?" diye sordum. Uzun uzun beni süzdükten sonra BBC’de doğa belgeseli sunan Sir David Attenborough edasıyla "Nerede öğrendin bakayım sen İngilizceyi?" yanıtını verdi. İçimden, "Sanırım adam kafayı kötü çarptı" diye geçirsem de, nazik bir tonla aldığım eğitimi ve okuduğum koleji 40 derece İzmir güneşinin altında hızlıca özetledim. Adamcağızın bilinç tamamen gitmiş olacak ki, "Benimle tavla oynar mısın?" diye sordu. "Elbette efendim" dedim, ama şaşkınlığımı da gizleyemedim doğrusu. Cehaletin verdiği cesaretle, "İngilizler tavla oynamasını bilir mi ki?" diye sordum. Eşinin havuz başında kaza geçirdiği haberini alarak merak içerisinde yanımıza koşup gelen hanımefendi, "Evet, genç adam! İngilizler tavla oynamasını çok iyi bilir. Kocam, Cambridge turnuvalarında yıllarca üst üste kupa kazandı" diye gururla ağzımın payını verdi.

Sadece 3 el oynayabildik. 2 mars 1 oyundan sonra beyefendi pes edip kıpkırmızı yanaklarla masadan kalktı, "İyi oynuyormuşsun, kutlarım! Bu yaşta kimden öğrendin tavla oynamayı?" diye sordu. Ben de gururla, "Önce babamdan, sonra da Sinclair ZX Spectrum’umda oynadığım Psion firmasının ürünü olan Backgammon isimli oyundan" diyerek, pek okkalı bir yanıt yapıştırdım. Adamcağızın yüzü bir anda değişti, "Firebird oyunlarını da oynuyor musun?" diye sordu. Biraz düşündükten sonra, "Öyle bir firma ya da oyun ismi bilmiyorum efendim" dedim. Tatlı tatlı gülümseyerek, "Yakında duyacaksın!" dedi.

O akşam yemeğini, havuz kazasını hafif atlatmasına rağmen tavla hezimetini içine sindiremeyen Bay Edward Charles Carter ve eşleri ilkokul öğretmeni Catherine hanımefendi ile birlikte yedik. Annem ve babamla tanıştıktan sonra, beyefendi uzun uzun kendisinden ve mesleğinden bahsetti. Meğer havuz kenarında çırpınıp duran bu tatlı İngiliz amca, British Telecom’un Genel Müdürüymüş. (O yıllarda "telekom" kelimesine henüz aşina olmadığımız için ailece birbirimize boş boş bakmıştık, o ayrı mesele.) Bay Carter’ın anlattığına göre, çok büyük bir firma olan British Telecom o sene Telecomsoft markası altında Firebird diye bir firma kurmuş, bundan böyle 8-bit bilgisayarlar için oyun geliştirip satacakmış! Şaşkınlıkla izin isteyip, bir koşu gittim bizim kamaraya, kapıp getirdim tüm Sinclair dergilerimi. Bu sefer ben başladım anlatmaya, "O firma bunu yapmış, şu firma şunu yapmış" diye. Bir süre sonra baktı ki susmuyorum, "Hepsi iyi güzel de, peki sen ne yaptın genç adam?" diye sordu Catherine hanımefendi. Ben de büyük bir heyecanla, Necati Ağabey ve Mahir Bey’le birlikte yazdığımız Kartoteks uygulamasını anlattım, "Kaset routine’lerini Assembly ile yazdım. İleride de oyunlar yazmak istiyorum!" diye gururla ekledim.

Günler hızla akıp gitti. Seyahatimizin son gününde, artık kendisini kısaca "Uncle Ted" diye çağırdığım İngiliz amca, Carter Ailesi olarak bizi evimizde ziyaret etmek istediklerini söyledi. Centilmen bir tavırla, bu isteklerinin bizim açımızdan bir sakıncası olup olmayacağını da eklemeyi ihmal etmedi. Babam, Börü Ailesi olarak onları evimizde akşam yemeğinde ağırlamaktan büyük bir onur duyacağımızı belirtti. Tek kelime İngilizce bilmeyen annem de, gülümseyerek "Ben onlara dolma sararım" dedi. Bastık kahkahayı!

Tatil bitmiş, okullar açılalı bir hafta olmuştu. Carter Ailesi, uzun bir Türkiye turunun ardından Cumartesi akşamı bizim fakirhaneye teşrif etti. Daha içeri girer girmez, Ted amcam bana dönüp "Aç bakalım bilgisayarını, göster bana yazdıklarını!" dedi. Ben de büyük bir heyecanla kasetten 7 KB uzunluğundaki HiSoft Devpac Assembler’ı (GENS2) yükledim, ardından da yazdığım low-level routine’leri. Elimdeki tüm Sinclair dergilerini ve Z80 Assembly kitaplarını gösterip, "Hepsini bunlardan öğreniyorum" dedim. Bilgisayar başında yaptığımız derin ve bir o kadar da teknik sohbetin sonunda, "Her şey iyi güzel de, yazdığın kodda bug çıkıp crash olunca ne yapıyorsun? Yine kasetten mi yüklüyorsun? Çok zaman almıyor mu?" diye sordu. Dergilerden birindeki ilanı göstererek, "Başka yolu yok, ancak microdrive ile hızlanabilir bu süreç" dedim. Hafifçe başını salladı, "Doğru söylüyorsun" dedi. Sofraya oturduk...

Çevrimdışı matahari

  • RAAT
  • Retro Meraklısı
  • *
  • İleti: 209
    • The Blog of Mert Börü
Ynt: Retrospektif: Speedlock
« Yanıtla #2 : 22 Nisan 2022, 01:04:54 »
Bölüm 2
"Match Day"

Nisan, 1985.

Babam o akşam gecikti. Anneme sorduğumda, "Postaneye gitti, gümrükte biraz işi varmış" dedi. Nihayet saat dokuz sularında, kucağında gazete kağıtlarına sarılı koca bir paketle eve geldi. "Aç bakalım, beğenecek misin?" dedi. Heyecanla gazete kağıtlarını araladım. İçinden gıcır gıcır ZX Spectrum Expansion System ile üzerine bantla tutturulmuş British Telecom logolu bir not çıktı; "Artık kodlarını daha hızlı yükleyebileceksin!"

Meğer babam, bize yemeğe geldikleri akşam bana hissettirmeden Carter Ailesine zarf içerisinde 100 GBP takdim etmiş, "Eğer mümkünse, bu ücret karşılığında Mert’in işine yarayacak şu ürünü bize gönderebilir misiniz?" diye rica etmiş, onlar da memnuniyetle kabul etmişler. Ancak, ürünün piyasaya çıkması gecikince, iki ay sonra Ted amcam babama mektup yazıp, "Merak etmeyiniz, ricanızı unutmadık. Sinclair firması teknik sorunlar sebebiyle ürünü piyasaya sürmekte gecikti. Çıkar çıkmaz göndereceğiz." diyerek bilgi vermiş, bu yüzden ürünün elime geçmesi yaklaşık 6 ay sürmüş!

O gece uyuyamadım… Yeni oyuncağımı yatağımın başucuna koyup, kutusu içinde parlayan Interface 1, Microdrive sürücü ve içinde 4 adet kartuş barındıran plastik cüzdana saatlerce bakıp durdum. Kullanma kılavuzunu da bir çırpıda yalayıp yuttum elbet. Bu kadar insanın mutluluğum için çırpınması, beni hem çok mutlu etmiş, hem de omuzlarımdaki sorumluluklara bir yenisini eklemişti. Tüm teknik sınırlar ve sorunlar aşıldığına göre, artık yavaş yavaş BASIC ile vedalaşıp bundan böyle tamamen Assembly ile yoluma devam edebilirdim.

Microdrive setim geldikten birkaç gün sonra ECOM’a gidip Mahir Bey’e her şeyi anlattım. Bir yandan lehim yapıp bir yandan da sabırla beni dinledikten sonra gözlüklerinin üstünden bakıp, "Hayırlı olsun! Madem artık microdrive’ın var, git kır bakalım şu oyunu" diyerek üzerinde Match Day yazan kaseti elime tutuşturdu. Koşarak eve gittim, hemen oyunu denedim.

Oyunun yükleme aşamaları sırasıyla,
  • Standart Header (Program: Match Day)
  • Standart Block (turbo loader kodu içeren bölüm)
  • Turbo Header
  • Turbo Block - (loading screen)
  • Turbo Headerless Block #1 - (kod + data)
  • Turbo Headerless Block #2 - (kod + data)
şeklindeydi.

İlk iş olarak, her ne kadar turbo loader’ı içeren standart block’un tamamen BASIC ile yazılmış olmasına ihtimal vermesem de, aklımda soru işareti kalmaması için MERGE komutuyla yüklemeyi denedim. İşlem sonunda Spectrum siyah ekrana düşerek crash etti! Açıkçası bunu beklemiyordum. Bari bir hata mesajı verseydi…

Turbo loader’ın içeriğini görebilmek amacıyla önce HiSoft Devpac Disassembler’ımı (MONS2), ardından da ilk block’u yükledim. Disassemble işlemine başladığım anda Spectrum reset attı. "Sanırım bir şeyi yanlış yapıyorum!" diyerek, aynı işlemi birkaç kez tekrar ettim. Kod üzerinde tek byte değiştirmesem bile, disassemble işlemine başlar başlamaz her defasında bilgisayar reset atıyordu. İlk block olması sebebiyle, loader’ın BASIC interpreter’ının buffer olarak kullandığı alana yüklenmesinden şüphe duydum. Bu block, BASIC block gibi yüklenip CODE block gibi davranıyor olabilirdi.

O günkü sınırlı/eksik bilgilerim ışığında BASIC dosyalarının &5CCB adresine yüklendiğini (!) kabul ederek, dosyayı doğrudan bu adrese yerleştirmek yerine MONS2 yardımıyla ileri bir yere (tam olarak &8CCB adresine) yüklemeye karar verdim. Amacım, aradaki &3000 byte farkı gözardı etmeden, kodu BASIC ortamının dışına alarak daha rahat disassemble edebileceğim güvenli bir yere taşımak, geçici olarak tüm işlemleri burada yapmaktı. İlk denememde başarılı oldum. Tam olarak 1.439 byte uzunluğunda olan ilk bloğu hiç çalıştırmadan (ham haliyle) microdrive’a kaydettim. Böylece her crash sonrası tekrar kasetten yüklememe gerek kalmayacaktı.

Bilgisayarı reset’ledikten sonra, kaydettiğim dosyayı BASIC interpreter ve MONS2 ile çakışmayacak şekilde &8CCB adresine geri yükleyip disassemble ettim. &8xxx ile başlayan her adresin aslında &5xxx civarında bir yere denk geldiğini varsayarak kodu okumaya başladım. Kısa sürede o güne dek okuduğum en karmaşık kod olduğunu fark ettim. "Bu iş böyle olmayacak!" diyerek, ilk block’un &5CCB adresine yüklenen orijinal hali ile &8CCB adresine taşıdığım binary imajı karşılaştırmaya karar verdim. Doğru okuma yapabilmek için bir referans noktasına ihtiyacım vardı. Orijinalde &6140 adresinde bulunan ASCII karakterlerle yazılı "G.WALLY" ibaresine odaklandım. Kaydettiğim binary dosyadaki "G.WALLY"nin tam &3000 byte öteye denk gelmesinden emin olmalıydım. Bu koşulu sağladıktan sonra, kodu tekrar okumaya başladım. En azından, kaydettiğim dosyanın orijinal adrese "align" olduğundan emindim.

Kısa sürede, kaydettiğim dosya ile orijinal arasında tutarsızlıklar olduğunu fark ettim! &5E00 sonrasındaki orijinal byte’lar, &8E00 sonrasına kaydettiklerimle uyuşmuyordu. Belli ki dosyayı MONS2 yardımıyla orijinalinden farklı bir adrese yüklemem işe yaramamıştı. Yükleme işlemi sırasında MONS2’nin bir şeyleri bozduğuna emindim. İtiraf etmem gerekirse, en başa dönmüştüm. Daha ilk block’u eksiksiz olarak hafızanın farklı bir bölgesine yüklemeyi bile başaramamıştım. Microdrive’daki tüm imajları silip, sorunu sil baştan ele almaya karar verdim!

"Acaba ilk bloğu, MONS2 kullanmadan orijinalden farklı bir adrese nasıl yükleyebilirim?" diye kara kara düşünürken, birden aklıma ECOM için Kartoteks programını yazarken çağırdığım ROM routine’leri geldi. İlk bloğu, sanki headerless bir dosyaymış gibi yüklemeye karar verdim. Bu doğrultuda, ROM’dan LD-BYTES (&0556) subroutine’ini çağıracak minik bir kod yazdım.

Kod: [Seç]
org &8000

ld ix,&8ccb
ld de,4096
ld a,255
scf
call &0556
ret

Her ne kadar 1.439 byte’lık dosya uzunluğundan emin olsam da, en azından bu konuda hataya yer bırakmamak için net bir sayı girmek yerine fazla fazla 4096 byte tanımladım. Kaseti, en baştaki pilot sinyali ve header’ı geçecek şekilde biraz ileri aldım. Match Day header’ının hemen ardındaki ilk bloğu (sanki headerless bir dosyaymış gibi) daha önce güvenilirliğini test ettiğim &8CCB adresine yükledim. İşlem sonunda, tek bir byte bile değiştirmeden &8CCB’den itibaren toplam 4096 byte’ı microdrive’a dump ettim. Artık içim rahattı. Bu kez, en azından dosyayı doğru şekilde okuyabilmiş ve kaydedebilmiş olmayı ümit ediyordum.

Orijinal adrese yüklenen block ile microdrive’daki dump’ı karşılaştırdım. Tüm byte’lar birbirinin aynısıydı. Tam olarak &3000 byte ileriye yüklemem sebebiyle, orijinalde &6140 adresinde bulunan "G.WALLY" metni de olması gerektiği gibi &9140 adresine align etmişti. Nihayet ilk block’u doğru olarak yükleyebilmiştim!

İlk incelememde, bu block’un
  • LIST komutu ile listelenememesi için şifrelendiğini,
  • Başı BASIC, sonrası makine kodundan oluşan "hybrid" bir yapısı olduğunu,
fark ettim.

Birkaç gün boyunca, The Complete Spectrum ROM Disassembly kitabımın 84. sayfasındaki "BASIC Line and Command Interpretation" başlığı altındaki listeyi referans alarak, block içindeki tüm byte’ları büyük bir sabırla tek tek okuyarak hangi byte’ın hangi BASIC komutuna (ve parametrelerine) denk geldiğini kağıda döktüm. Bir dizi PEEK ve POKE komutundan sonrası tamamen makine koduydu. Sonuçta bu PEEK/POKE komutlarının ardından mutlaka bir adrese sıçranması (jump) gerekiyordu, ancak ortada bir RANDOMIZE USR komutu yoktu. Açıkçası, görmeye (ve çözmeye) alışkın olduğum bir kopya koruma yöntemiydi bu; ECOM’a gelen kırık Kokotoni Wilf kopyasının ilk block’undaki BASIC bölüm, RANDOMIZE USR komutu içermeksizin sadece PEEK/POKE kullanarak aynı blok içindeki makine kodu bölüme sıçrıyordu. Bunu yapabilmek için, BASIC’te ON_ERROR_GOTO pointer’ları olarak kullanılan sistem değişkenlerinden ERR-NR (&5C3A) ve ERR-SP (&5C3D) içerisine sıçranacak adresi POKE’luyordu. Bu adres de, tahmin edileceği üzere, BASIC kodun hemen ardında sinsice gizlenen makine kodu içerisinde bir yer olmak zorundaydı. Böylece BASIC interpeter, BASIC olmayan ilk satırı gördüğünde hata olduğunu varsayarak sistem değişkenlerinde belirtilen bu adrese sıçrıyordu. Match Day’in ilk block’unda kullanılan yöntem de buydu.

Çok sabır isteyen bu işlemin sonunda, nihayet BASIC interpreter’ın hangi adrese sıçradığını bulmuştum: &6100. Artık bu dosyanın MERGE ile yüklendiğinde neden bilgisayarı crash ettirdiğini anlayabiliyordum. BASIC dosyasının içine gömülü (embedded) olan CODE block, MERGE komutu sonrasında BASIC interpreter’ın çökmesine neden oluyordu. Öte yanda, MONS2’nin hangi sebeple çöktüğünü ve dosyayı neden doğru yükleyemediğini henüz çözememiştim. Bu problemin nedenini Mahir Bey’e sorduğumda, üzerimde Sokratik yöntem uyguladığını yıllar sonra anladığım üzere, bana bir dizi sorular sorup yanıtı yine bana buldurmaya çalışmıştı:

— BASIC interpreter, ROM routine’lerini çağırır mı?
— Evet efendim.
— Devpac MONS2 Disassembler, hem BASIC üzerinden hem de kendi içinden ROM routine’lerini çağırır mı?
— Evet efendim.
— Kodun içinde IX ve IY register’ları kullanılıyor mu?
— Evet efendim.
— Peki, ROM routine’leri IX ve IY register’larını kullanır mı?
— Melbourne House’un kitabına göre, evet.
— Bu durumda, hem Match Day loader hem de BASIC interpreter aynı anda IX ve IY register’larını kullanabilir mi?
— Elbette hayır. İyi de, ben BASIC kullanmıyorum ki, sadece MONS2 Disassembler…


dediğim an, yaptığım hatayı anladım. Sustum…

Sorunun birden fazla sebebi vardı:
  • Match Day’e ait ilk bloğun, sistem değişkenlerinin ve BASIC interpreter buffer’ının olduğu alana yüklenmesi,
  • Devpac’ın hem ROM’dan hem de BASIC’ten IX ve IY register’larını kullanan subroutine’leri çağırması,
  • Devpac’ın menü ekranındayken interrupt’ları kullanması,
  • Devpac’ın disassemble işlemi sırasında geçici olarak interrupt’ları kapatması ve işlem sonunda tekrar açması.
Bu durumda, eğer her işlem sonrasında Devpac ya da BASIC’e geri döneceksem, ya yazacağım/çağıracağım her kod için

Kod: [Seç]
di
push ix
push iy
...
...
pop iy
pop ix
ei

benzeri bir template kullanıp noktalı yerlere kendi kodumu ekleyecektim, ya da interrupt ve ROM çağrısı "içermeyen" Devpac’sız/BASIC’siz bir çözüm bulacaktım. Zor olsa da, ikinci seçenek daha mantıklıydı… ROM çağrısı içeren koduma geri dönerek, yeni eklemeler yaptım.

Kod: [Seç]
org &8000

ld ix,&8ccb
ld de,4096
ld a,255
scf
call &0556
di
ld hl,&8ccb
ld de,&5ccb
ld bc,4096
ldir
jp &6100

Sırasıyla incelersek; ilk block’un headerless kısmını hafızanın ileri bir bölgesine yüklüyor, yüklediğim kodu orijinal adrese (aynı zamanda BASIC interpreter’ın da kullandığı adrese) kopyalamadan önce tüm interrupt’ları kapatıyor, yüklenen kısmı orijinal adrese kopyalıyor, ardından da kodun çalışacağı adrese sıçrıyordum.

Maalesef evdeki hesap çarşıya uymadı; Spectrum yine crash oldu! JP komutuna kadar yazdığım her şey doğru ve mantıklıydı. Bundan çok emindim. Bu yüzden &6100 adresinden başlayarak kodu incelemeye karar verdim. Acaba nasıl bir koda sıçrıyordum?

Disassemble edilmiş, toplam 1.439 byte’lık kodu günlerce okudum. Notlar aldım. Tekrar tekrar okudum.

Kod: [Seç]
6100: ld l,l
6101: ld b,l
6102: ld b,b
6103: ld a,c
6104: sub d
6105: ld a,i
6107: ld ixh,d
6109: ld h,h
610a: ld d,e
610b: ret po
610c: dec d
610d: dec d
610e: ld d,d
610f: exx
6110: ld ixl,b
6112: xor d
6113: sbc hl,hl
6115: xor e
6116: di
6117: ld l,l
6118: ld (hl),a
6119: ld (hl),a
611a: add a,iyh
611c: ...
      ..
      .

Kodun devamında 3-4 farklı yerde DI komutu olduğunu fark ettim. IX ve IY register’larının kullanıldığı her yeri işaretledim. Önceki notlarımla karşılaştırdım, ama maalesef işin içinden çıkamadım. Neyin gerçekten kod, neyin data olduğunu ayrıştıramıyordum. Data olması gereken kısımlar bile kod gibi duruyordu. LD B,B benzeri anlamsız (ve hiçbir flag’i etkilemeyen) komutların data olduğundan şüpheleniyor, ama neyin ne olduğunu kavramakta zorlanıyordum. O dönemde hakkında hiçbir şey bilmediğim I ve R register’larının kod içerisinde kullanılıyor olması kafamı iyice karıştırıyor, Match Day loader’ının sonuna ASCII karakterlerle iliştirilen ve hafızada &6225 adresine yüklenen "Attempting to crack SPEEDLOCK can damage your sanity!" ibaresi de canımı sıkıyordu... Bir bilene danışmakta fayda vardı. Kodun &6100’den itibaren kısa bir bölümünü defterime yazıp, Mahir Bey’e göstermeye karar verdim.

— Kodun bu adresten çalışmaya başladığına emin misin?!
— Kesinlikle evet, efendim.
— LD B,B türü komutlar anlamsız. Muhtemelen ya cycle kaybettirmek ya da okuyan kişinin kafasını karıştırmak için kullanmışlar… Madem bu kodun çalıştığından eminiz, o vakit şu soruyu sormalıyız: "Kodun en başında kullanılan L, B ve C gibi register’ların ilk değerleri nereden geliyor?"
— … (sessizlik)
— Soruyu başka türlü sorayım: &6100’den önce ne çalıştı?
— Benim minik loader.
— Peki ondan önce?
— Minik loader’ımı hafızaya POKE’lamamı sağlayan READ/DATA kombinasyonlu BASIC programım.
— Ondan önce?
— Hiçbir şey.
— Şimdi tersten düşünelim… Normal koşullarda Match Day loader nasıl çalışıyor?
— Spectrum’u reset’liyoruz. LOAD "" yazıp, enter’a basıyoruz. Bilgisayar ilk bloğu yüklüyor, ardından da &6100 adresine sıçrıyor.
— Harika! İşte ilk değerler bu işlem zincirinin sonunda elde ediliyor. Kod &6100’e sıçramadan önce, tüm register’ların o anki değerlerini bulmalısın. Kopya korumasının bir parçası olabilir bu!!!
— Tüm register’ların &6100’e sıçramadan önceki değerleri mi?
— Evet.
— I ve R register’larını da mı?
— Elbette.
— Ya F register’ı?
— Bilhassa onu… Flag’lerin o anki state’leri çok önemli.
— Peki, &6100 öncesinde neler yaptığını nasıl trace edebilirim?
— &6100’ü kim çağırıyor?
— Hybrid blok içinde BASIC olarak çalıştırılan son satır.
— Öyleyse?
— Öyleyse… ROM’a gidip en son çağırılan BASIC komutun (POKE) çalıştığı yeri bulup, takibe oradan başlamalıyım. Evet, anladım… ANLADIM!


Sevinçle eve döndüm... Tüm register’ların &6100 sıçrama öncesi son hallerini bulabilmek için, bir elim Melbourne House’un ROM kitabında öteki elim klavyede olmak üzere deliler gibi çalıştım. O günlerde henüz Multiface One gibi bir donanım icat edilmediği için, anlık register değerlerini takip edebilmek maksadıyla kod yazmak dışında bir seçeneğim yoktu! Onlarca routine yazdım. Her defasında çuvalladım. Pes etmedim. Tekrar tekrar denedim. Yine çuvalladım. Hep çuvalladım… Birkaç hafta içinde moralim bozuldu. Becerememiştim. Kodlamaya son verdim! Utanıp sıkıldığım için artık Mahir Bey’e de bir şey soramazdım. Kendim çözmeliydim bu sorunu. Evde, serviste, okulda, her yerde bunu düşünüp duruyordum…

Çevrimdışı matahari

  • RAAT
  • Retro Meraklısı
  • *
  • İleti: 209
    • The Blog of Mert Börü
Ynt: Retrospektif: Speedlock
« Yanıtla #3 : 22 Nisan 2022, 02:14:07 »
Bölüm 3
"Martı"

Mayıs, 1985.

Karamsarlık denizinde boğulduğum karanlık günlerin birinde, okulun müdür yardımcısı beni odasına çağırdı.

— Bak evladım, sen burslu öğrencisin. Hem derslerindeki başarılarınla hem de olumlu davranışlarınla okuldaki diğer arkadaşlarına örnek olmak zorundasın. Ders sırasında kitaplarının üzerine anlamsız sayılar yazman, düşlere dalıp gitmen öğretmenlerinin dikkatini çekmiş. Bir derdin ya da psikolojik rahatsızlığın yok, değil mi evladım?
— Yok efendim. Sadece kodda bir yerde takıldım da…
— Ne kodu?
— Kırmaya çalıştığım oyunun kodu.
— Ne oyunu?
— Bilgisayar oyunu.
— Vakit kaybı o işler!!!… Bu konu kapanmıştır. Artık derslerine odaklanıyorsun!


Her ne kadar arkadaşlarıma örnek olmam konusunda haklı olsa da, müdür yardımcısının bilgisayar oyunları hakkındaki bağnaz tutumu beni tetiklemiş, "sürüden farklı olmamın" ayırdına varmamı sağlamıştı. Sevgili Edebiyat öğretmenimiz Ersin Bey’in bize o dönem okuttuğu Martı’nın ana kahramanı Jonathan Livingston kadar hür ve aykırı hissetmiştim kendimi. Korkularımın üzerine gitmeye karar verdim!

Eve gider gitmez ilk işim bilgisayarımı açıp kaldığım yerden kodlamaya devam etmek oldu. Sabırla, BASIC interpreter’ın CODE block’a sıçramadan önce çağırdığı en son komut olan POKE’un nasıl çalıştığını, ROM’dan hangi subroutine’leri çağırdığını deli pösteki sayar gibi tek tek takip ettim. Ayrıca, ROM çağrılarında sıkça kullanılan RST komutu, I ve R register’ları konusundaki eksiklerimi de giderdim, kendimi geliştirdim. Kodlamaya kısa bir süre ara vermiş olmam zihnimi dinlendirmiş, daha rahat çalışmamı sağlamıştı. Günler geceler süren incelemeler ve sayısız kez crash eden MONS2 oturumları sonucunda, tüm register’ların değerlerini buldum ve minik kodumu güncelledim.

Kod: [Seç]
org &8000

ld ix,&8ccb
ld de,4096
ld a,255
scf
call &0556
di
ld hl,&8ccb
ld de,&5ccb
ld bc,4096
ldir
ld a,&3f
ld i,a
exx
ex af,af’
ld hl,&7e6d
push hl
pop af
ld bc,&b8e0
ld de,&369b
ld hl,&ffff
ex af,af’
exx
ld hl,&8090
push hl
pop af
ld bc,&5c70
ld de,&6270
ld hl,&5efc
ld ix,&626a
ld iy,&5c3a
jp &6100

"Çalışmasa da sorun yok. En azından denedim, elimden gelen her şeyi yaptım" diyerek, kodu çağırdım. Elbette çalışmadı! Ancak bu kez farklı bir şey oldu; daha önceki denemelerimde anında crash olan Spectrum, bu kez yaklaşık 1 saniye düşündükten sonra crash oldu. Demek ki crash öncesinde bir şeyler çalışmıştı! Girdiğim ilk değerler işe yaramış olmalıydı. O an gerçekten çok mutlu olmuştum. Kodu çalıştıramasam da, en azından bir adım ilerleyebilmiştim.

Kendimden (ve register’lar için girdiğim ilk değerlerden) emin olarak, &6100’deki "anlamsız, ama execute edebilen" koda geri döndüm. İlk bloğun içerisine paketlenmiş olan bir grup data okunup, yine aynı bölgeye geri açılıyordu. Bir tür "decode" işlemiydi bu. Tüm decode işlemini instruction bazında dikkatle takip ettikten sonra, crash eden yere sıçramadan önce hafızanın o bölümünü microdrive’a dump ettim. Bu kez elimde artık sadece ilk block değil, bu block içerisine decode edilen ("turbo loader" olduğunu umduğum) kod parçası vardı. Bir noktadan sonra crash ediyordu, o ayrı mesele!

Dump ettiğim dosyayı incelemeye başladım. Match Day loader’ının decode ettiği kod, tıpkı BASIC koduymuşcasına sistem değişkenleri ve BASIC interpreter buffer için ayrılan &5C00 sonrasına yerleşiyordu. Hafızanın bu bölümü, öncelik ULA’da olmak kaydıyla, ULA ve CPU arasında paylaşımlı olarak kullanılan "contended" olarak bilinen lanetli bölgeydi. Decode edilen kodun hem bu yavaş alana yerleşiyor olması hem de Z80’in en hantal registerları olan IX ve IY’yi kullanıyor olması, açıkcası "turbo" olmakla uzaktan yakından ilgili olamazdı. Eğer turbo yükleme kodunun yüksek baud rate elde etmek için çok hızlı ve cycle bazında tutarlı çalışması gerekiyorsa, bu durumda bellekte &8000’den sonra bir adrese yerleşmesi gerekiyordu. Demek ki turbo yükleme kodu, contended bölgeden öteye "taşınmalı" ya da orada "oluşturulmalıydı".

Hemen test ettim. Decode edilen (alttaki) koda hiç sıçranmıyordu.

Kod: [Seç]
5f04: dec sp
5f05: dec sp
5f06: ld iyh,&ec
5f09: ld iyl,&04
5f0c: ex (sp),iy
5f0e: ld bc,&002e
5f11: add iy,bc
5f13: ld e,iyl
5f15: ld d,iyh
5f17: ld l,e
5f18: ld h,d
5f19: ld bc,&01d5
5f1c: ld a,i
5f1e: call po,&3008
5f21: ld a,r
5f23: xor (hl)
5f24: ld (hl),a
5f25: ldi
5f27: ret po
5f28: dec sp
5f29: dec sp
5f2a: ret pe
5f2b: ...
      ..
      .

Artık emindim. Decode edilen kod (ya da kod içerisinden bir bölüm), kesinlikle hafızanın başka bir bölümüne taşınıyor ve orada çalıştırılıyordu. Ancak hâlâ bir sorun vardı! Taşıma işlemi sırasında bir şeyler yanlış gidiyor, kod crash ediyordu. "Neyi atlıyorum? Neyi eksik yapıyorum? Acaba bir şey mi unuttum?" diye günlerce düşündüğümü, bugün bile çok net hatırlıyorum. Yorgundum, ama yılmamıştım. Mutlaka bir şeyi yanlış ya da eksik yapıyordum. LOAD "" ile normal yükleme işleminin neredeyse birebir aynısını uygulamama ve tüm register’ların &6100’e sıçramadan önceki değerlerini korumama rağmen, hâlâ bir şeyler eksikti.

O akşam televizyona boş boş bakıyordum. Annem de yanımda örgü örüyordu. Anneme dönüp "Örgü örerken ilmek kaçırdığında ne yapıyorsun?" diye sordum. "O satırın tamamını söküp, baştan örüyorum" dedi. Gerçekten de öyle yapardı. Bir çok kez şahit olmuştum bu olaya. Sabırla söker, tekrar örerdi… Bu soruyu sormamın bir sebebi vardı elbet. Aradığım cesaret, annemin yanıtı ile tescillenmişti. Her ne kadar çok yol katetmiş olsam da, hatamı/eksiğimi bulamamam sebebiyle sil baştan yapmaya karar vermiştim!

Mahir Bey’e gidip, "İzin verirseniz, ben yeni bir yöntem denemek istiyorum" dedim. Memnuniyetle karşıladı. Cracker/Hacker gibi düşünmeyi bir kenara bırakıp, "Acaba bu işi kitabına göre nasıl yapabilirim?" diye düşünmeye başladım. LOAD "" komutunun yapıp da benim yapamadığım acaba ne olabilirdi? Belki bu şekilde hatamı/eksiğimi bulabilirdim.

Bir süre bilgisayarımı hiç açmadım. Oyun bile oynamadım. Melbourne House’un kitabına geri döndüm. Günler geceler boyunca LOAD "" komutunun arka planını satır satır okudum. &FE port üzerinden yapılan çağrıları, IN ve OUT komutları sonucunda elde edilen bit’lerin ne anlama geldiğini, klavyede hangi tuşa basıldığını porttan nasıl okuyacağımı, border’daki çizgilerin renginin nasıl değiştiğini, kasetten okuma işlemi sırasında çağırılan tüm low-level subroutine’lerin ne iş yaptığını tek tek okuyup öğrendim. Kitaptaki bilgilerle yetinmeyerek, &FE port hakkında daha teknik bilgi edinmek için Mahir Bey’e danışıp, portun ULA’nın 28 numaralı SOUND bacağına bağlı olduğunu, bu bacağın tüm analog I/O işlemleri "aynı anda" kontrol ettiğini, dolayısıyla bu porttan yapılan herhangi bir işlemin bacağa bağlı olan tüm giriş/çıkışları (MIC, EAR, BEEPER) paralel olarak tetiklediğini öğrendim. Bu bilgiler ışığında Melbourne House’un kitabına yeniden (!) geri döndüm. &FE port erişimi yapan ROM routine’lerinin neden sürekli olarak SPACE tuşunu kontrol ettiğini, kaset okuma/yazma işlemleri sırasında neden klavyede bir tuşa basılıp basılmadığını kontrol etmemiz gerektiğini, eğer basıldıysa bu bit’leri neden mask’lamamız gerektiğini iyice kavradım.

Artık tam anlamıyla "Spectrum canavarı" olmuştum!

Çevrimdışı matahari

  • RAAT
  • Retro Meraklısı
  • *
  • İleti: 209
    • The Blog of Mert Börü
Ynt: Retrospektif: Speedlock
« Yanıtla #4 : 22 Nisan 2022, 03:03:50 »
Bölüm 4
"Beach Head"

Haziran, 1985.

Karne almamıza birkaç hafta kala havalar güzelleşmiş, kravatlar iyice gevşemişti. Öğle tatilinde arkadaşlarım tribünde oturup okulumuzda düzenlenen liseler arası hentbol turnuva maçlarını keyifle izlerken, ben de kucağıma Melbourne House’un kitabını alıp bir yandan güneşlenir bir yandan da dikkatle okurdum. O güzel günlerden biriydi… Evde test etmek üzere, İngilizce gramer kitabımın kenarına minik bir kod yazdım. Tamamen ROM çağrıları kullanan, "her işi kitabına göre yapan" kısacık bir routine’di bu.

Kod: [Seç]
org &8000

ld ix,&4000
ld de,17
xor a
scf
call &0556
ld a,255
ld (&400e),a
ld ix,&4000
ld hl,(&5c53)
jp &0873

İlk iş olarak 17 byte uzunluğundaki header’ı ekran hafızasının en başına (&4000 adresine) sanki headerless bir dosyaymış gibi yüklüyor, ardından header’ın 13. ve 14. byte’larında belirtilen BASIC’te sıçranacak olan satır sayısının sadece ikinci byte’ını header’ın içinden siliyor, bir sonraki block’u yükleyebilmek için header’ın bulunduğu adresi ve block’un nereye yükleneceğini gösteren pointer’ı sistem değişkeni PROG (&5C53) ile belirtiyor, son olarak da ROM’dan LD-PROG (&0873) subroutine’ini çağırarak ilk bloğu yüklüyordum. Teoride, bu block yüklenecek ama auto-run etmeyecekti, OK diyerek BASIC’e geri dönecekti.

Öyle de oldu!

RANDOMIZE USR 32768 komutuyla yazdığım kodu çağırdım. Teybe Match Day kasetini koyup, Play’e bastım. Önce header yüklendi, ardından ilk block… Sonra da ekrana OK yazısı çıkıp BASIC’e geri döndü. Yazdığım kod çalışmıştı! BASIC ve ULA’nın kullandığı "paylaşımlı" alanda olduğumu bildiğim için RANDOMIZE USR 24832 komutuyla &6100 adresine sıçramayı aklımdan bile geçirmedim. Kodun crash edeceğinden adım gibi emindim. Zira, BASIC’e geri döndüğüm için BASIC buffer değerlerinin yüklediğim kodun üzerine yerleştiğini artık bilecek kadar tecrübeliydim.

Auto-run’ı kontrol etmek amacıyla BASIC satır sayısını hacklediğim bölümü kodun içerisinden sildim. Eğer her şey yolunda giderse, işlevsel olarak ZX Spectrum’un LOAD "" komutuna denk bir kod yazmış olacaktım.

Kod: [Seç]
org &8000

ld ix,&4000
ld de,17
xor a
scf
call &0556
ld ix,&4000
ld hl,(&5c53)
jp &0873

Kaseti başa sarıp, RANDOMIZE USR 32768 komutuyla yazdığım kodu çağırdım. İlk header ve block yüklendi. Ardından border yanıp sönmeye başladı. Turbo loader çalışmıştı! Yüklemek için kasetten sinyal bekliyordu…

Müjdeyi vermek için hemen ECOM’a koştum. Mahir Bey yerinde yoktu. Ben de müjdemi Necati Ağabey ile paylaştım. "Kırdın yani oyunu!" dedi. Ben de "Yok, henüz o aşamaya gelemedim. Sadece turbo loader’ı kırdım" dedim. Yaptıklarımı dükkanda kurulu olan Spectrum üzerinde çalıştırarak tüm detaylarıyla anlattım. Necati Ağabey büyük bir keyifle, "Darısı oyunun başına!" dedi. Gülüştük.

Bu macera sonucunda, Spectrum’un tüm I/O işlemlerini ve BASIC komutlarının ROM tarafından nasıl interpret edildiğini yalayıp yutmuştum. BASIC’in auto-run özelliğinin nasıl açıp kapanacağından tutun da, header’ın hangi adrese nasıl yükleneceğine varana kadar epey tecrübe edinmiştim. Hepsinden daha önemlisi, bir önceki yöntemde neyi eksik yaptığımı anlamıştım! Çok basit ve bir o kadar da can alıcı noktayı gözden kaçırmış, ilk bloğu headerless olarak yükleyebilmek için asıl header’ı atlamıştım! Match Day loader &6100’e sıçradıktan sonra sadece register’ların o anki değerlerine bakmakla kalmıyor, header ile birlikte yüklenen dosya tipi (1 byte), dosya adı (10 byte), block uzunluğu (2 byte), BASIC başlangıç satırı (2 byte) gibi verileri de kontrol ediyordu. Bir önceki yöntemde gözardı ettiğim 17 byte (header) bana pahalıya mal olmuştu. İşi kitabına göre yapıp, tüm yükleme işlemlerini ROM üzerinden doğru sırayla çağırmam ise bu sorunu doğal olarak ortadan kaldırmıştı.

Artık bir sonraki aşamaya geçip, &5C00 adresine decode edilen kodu kaldığım yerden incelemeye devam edebilirdim. İlk dikkatimi çeken şey, stack pointer orijinal değerinin değiştirilerek &5C00 öncesi bir adrese çekiliyor olmasıydı. Dikkatimi çeken ikinci şey ise, contended alandan daha ileriye taşınacak olan kodun oldukça karmaşık olmasıydı. Acaba taşıma sırasında yeni bir decoding mi yapılıyordu? Uzun süre kodun içinde çırpındıktan sonra, hem müjdemi vermek hem de geldiğim yeni noktayla ilgili görüşlerini almak için Mahir Bey’e danışmaya karar verdim. Takıldığım yerleri kendisine gösterince, "Haklısın, oldukça karışık" dedi. Ve, o ana kadar duyduğum en mükemmel fikri ortaya attı:

— Madem o kodun içinden çıkamıyorsun, ona benzer başka bir kod bulup karşılaştırma imkanın var mı? Aralarındaki ortak ve farklı yerlere bakıp belki bir şeyler sezebilirsin.

Harika bir tavsiyeydi bu! Hemen eve gidip Match Day’in loader’ına benzeyen, pilot sinyal sırasında "dıt-dıt-dıt" diye kesik kesik ton üreten Daley Thompson’s Decathlon’u denedim. Her ne kadar pilot sinyal benzese de, loading screen bitiminde sinyal kesilmiyor, oyun tek parça halinde yüklemeye devam ediyordu. Belli ki bu oyunu kırmak Match Day’den çok daha zordu. Bunun üzerine elimdeki diğer oyunları tek tek incelemeye başladım. Maalesef elimdeki oyunların pilot sinyallerinde o kesik tonlama yoktu.

Mahir Bey’e durumu anlattığımda, "Öyleyse sana bol miktarda turbo loader’lı oyun bulmak lazım. Ama crack versiyon olmamalı, orijinal kopya olmalı" dedi. Haklıydı. Günlerce piyasayı araştırdım. Gitmediğim yer, girmediğim dükkan kalmadı. Sonunda Elmadağ’da, Şan Tiyatrosu’nu biraz geçtikten sonra solda, çok şık bir mağaza içinde bende olmayan bir sürü Spectrum oyunu buldum. Mağazanın satış görevlisi, büyük bir gururla, "Biz bunları yurtdışından orijinal getirip kendi sistemlerimizle burada çoğaltıyoruz" dedi. Birkaç hafta boyunca tüm harçlığımı bu mağazadaki Spectrum oyunlarına yatırdım dersem, yanlış olmaz. Yol masrafı da cabası.

Uzun arayışlar sonucu, duymak istediğim pilot sinyalinin benzerini nihayet üzerinde Beach Head yazan kasette duydum. Kesinlikle aynı tondu bu! Hemen loader’ı disassemble ettim. Farklı adreste yine aynı "Attempting to crack SPEEDLOCK…" mesajını görünce, çok sevindim. Match Day için yaptığım tüm işlemleri ona da uyguladım. Daha sonra her iki kodun yazıcı çıktısını almak üzere ECOM’a gittim. Necati Ağabey’den ücreti karşılığında elimdeki iki kodu yazdırmasını rica ettim. Gülümseyerek kodları özenle bastı, "Doğru yoldasın. Sen şimdi eve git, işine odaklan. Sonra ödersin." dedi. Çok mutlu oldum, biraz da utandım doğrusu.

İki loader’ın çıktısını yan yana koyunca, benzer noktalar hemen ortaya çıktı. Neyin data, neyin kod olduğu artık biraz daha netti. Hâlâ anlayamadığım yerler vardı, ama ben anladığım yerlere odaklanmayı tercih ettim.

Öncelikle, elimde olan verileri not aldım:
  • Her iki loader da kesinlikle ROM kullanmıyor, tüm interruptları kapatıyor ve kasetten okuma işlemleri için portlara erişerek kendine ait “custom” yükleme routine’lerini kullanıyordu.
  • Her header yükleme öncesi dıt-dıt-dıt şeklinde gelen pilot sinyal aralıkları, büyük olasılıkla okuma hızıyla ilgili aralıkları ölçmek için kullanılıyordu. Bir bakıma, kasetin devir hızına göre kod kendi içinde küçük bir kalibrasyon yapmaya çalışıyor olabilirdi.
  • Duyabildiğim kadarıyla, oyunların kasetten okuma hızı Spectrum standardı olan (ortalama) 1.365 baud’dan çok daha fazlaydı. Bu da, her dıt aralığı Spectrum’un ROM’unda yer alan yükleme kodundaki 358T state bekleme süresinden çok daha az olması anlamına geliyordu. Daha az bekleme, daha yüksek okuma hızı… Ancak bundan emin olabilmek için custom yükleme koduna erişebilmem gerekiyordu.
  • Loader içerisine paketlenmiş olan asıl yükleme routine’i, henüz anlayamadığım bir şekilde encrypt edilmişti. Ya sıkıştırılmış, ya encode edilmiş, ya da her ikisi birden uygulanmıştı. Üstelik, bu işlem dizisi birden fazla kez uygulanıyor olabilirdi.
Bunları bilerek, kendime bir yol haritası çıkarttım:
  • Her iki loader’ın ortak noktaları nelerdir?
  • Encrypt edilmiş datayı nasıl decrypt edebilirim?
  • Custom loader hangi adreste duruyor?
  • Custom loader nasıl çalışıyor?
  • Custom loader’ın içine, oyunu standart hızda kaydetmemi sağlayacak şekilde kendi kodumu nasıl ekleyebilirim?
Hem Match Day hem de Beach Head loader’larında ortak olan, taşıma işlemini gerçekleştirdiğinden ya da taşınan kod olduğundan şüphelendiğim yerden yola çıktım.

Kod: [Seç]
    - Match Day -    |    - Beach Head -
                     |
5f04: dec sp         |  5feb: xor iyl
5f05: dec sp         |  5fed: ld iyh,&c8
5f06: ld iyh,&ec     |  5ff0: ld iyl,&20
5f09: ld iyl,&04     |  5ff3: dec sp
5f0c: ex (sp),iy     |  5ff4: dec sp
5f0e: ld bc,&002e    |  5ff5: ld bc,&fe42
5f11: add iy,bc      |  5ff8: ex (sp),iy
5f13: ld e,iyl       |  5ffa: ld hl,&c6aa
5f15: ld d,iyh       |  5ffd: add iy,bc
5f17: ld l,e         |  5fff: ld bc,&01be
5f18: ld h,d         |  6002: ld e,iyl
5f19: ld bc,&01d5    |  6004: ld d,iyh
5f1c: ld a,i         |  6006: ex de, hl
5f1e: call po,&3008  |  6007: xor (hl)
5f21: ld a,r         |  6008: ld (de),a
5f23: xor (hl)       |  6009: ld a,(hl)
5f24: ld (hl),a      |  600a: inc hl
5f25: ldi            |  600b: inc de
5f27: ret po         |  600c: dec bc
5f28: dec sp         |  600d: ld iyl,a
5f29: dec sp         |  600f: ld a,b
5f2a: ret pe         |  6010: or c
5f2b: ...            |  6011: ld a,iyl
      ..             |  6013: jr nz,&6007
      .              |  6015: ld iy,&5c3a
                     |  6019: ret

Adres olabilecek değerleri tek tek hafızada takip etmeye başladım. Kısa süre içinde Match Day’in loader kodunun &EC04 adresine, Beach Head’inkinin ise &C820 adresine sıçradığını fark ettim.

Kod: [Seç]
    - Match Day -    |    - Beach Head -
                     |
ec04: ld sp,&5bff    |  c820: ld sp,&609e
ec07: ld ix,&8000    |  c823: ld ix,&8000
ec0b: ld de,&0014    |  c827: ld de,&0014
ec0e: call &eb92     |  c82a: call &c7ae
ec11: call &ebc0     |  c82d: call &c7dc
ec14: ld ix,&4000    |  c830: ld ix,&4000
ec18: ld de,&1b00    |  c834: ld de,&1b00
ec1b: call &eb92     |  c837: call &c7ae
ec1e: call &ebc0     |  c83a: call &c7dc
ec21: ld ix,&5dc0    |  c83d: ld ix,&60a0
ec25: ld de,&8ca0    |  c841: ld de,&6609
ec28: call &eaa9     |  c844: call &c6c5
ec2b: ld ix,&ec86    |  c847: ld ix,&c8aa
ec2f: ld de,&1379    |  c84b: ld de,&3750
ec32: call &eaa9     |  c84e: call &c6c5
ec35: ld a,(&ec03)   |  c851: ld a,(&c81f)
ec38: cp &00         |  c854: cp &00
ec3a: jp nz,&0000    |  c856: jp nz,&0000
ec3d: ld hl,&ec4b    |  c859: ld de,&c6aa
ec40: ld de,&5b00    |  c85c: ld bc,&0176
ec43: ld bc,&0018    |  c85f: ld hl,&053f
ec46: ldir           |  c862: ldir
ec48: jp &5b00       |  c864: ei
ec4b: ld hl,&5dc0    |  c865: jp &8000
ec4e: ld de,&ea60    |
ec51: ld bc,&0226    |
ec54: ldir           |
ec56: ld sp,&60ff    |
ec59: ld iy,&5c3a    |
ec5d: im 1           |
ec5f: ei             |
ec60: jp &ffbc       |

Artık Speedlock’ın custom yükleme routine’lerine yapılan tüm CALL’lar karşımda apaçık duruyordu. Header ve Loading Screen için aynı 2 adres çağırılırken, data block’lar için farklı adresler çağırılıyordu. Tüm işlemler bittikten sonra da, son satırdaki JP komutuyla oyun başlatılıyordu. Bu noktadan sonra oyunu kırmak artık çocuk oyuncağıydı!

Hemen minik bir headerless dosya kaydetme routine’i yazdım, hafızanın kullanılmayan bir köşesine yerleştirdim. Sondaki JP komutu yerine yazdığım bu routine’i çağırarak, önce belleği 16K’lık parçalar halinde kasete dump ettim, ardından da hepsini microdrive’a aktardım. Dump ettiğim dosyaları temizleme ve kısaltma işlemlerinin ardından, oyunun ilk bloğu kasetten yüklendikten sonra ekrana "cracked by matahari" yazacak minik bir loader kodladım. Ertesi gün hem Match Day’i hem de Beach Head’i kırık halde Necati Ağabey’e teslim ettim, sonra da Mahir Bey’in yanına koştum.

— Şimdi ne yapacaksın Mert?
— Turbo loader kodunu incelemeye devam edeceğim, efendim. Custom loader’ı en son bit’ine kadar takip edeceğim. Hepsini okuyup anlayacağım. Belki bir gün ben de kendi turbo loader’ımı yazarım!
— Aferin! Ben de senden bunu beklerdim. Kodu incelemeye, öğrenmeye devam et. Asıl bilgi orada…


Doğru yolda olduğumun onayını almanın mutluluğu ile hemen eve gittim, turbo loader kodlarını okumaya devam ettim. Artık tüm okuma işlemlerini "karşılaştırmalı" olarak yürütüyordum.

Kod: [Seç]
    - Match Day -    |    - Beach Head -
                     |
ec04: ld sp,&5bff    |  c820: ld sp,&609e
ec07: ld ix,&8000    |  c823: ld ix,&8000
ec0b: ld de,&0014    |  c827: ld de,&0014
ec0e: call &eb92     |  c82a: call &c7ae
ec11: call &ebc0     |  c82d: call &c7dc
ec14: ...            |  c830: ...
      ..                      ..
      .                       .

Speedlock’ın kullandığı header yapısı, Spectrum’un klasik "marker byte + 17 byte + checksum byte" formatından farklıydı. Her iki oyun da ekran bloğu öncesi toplam 20 (&14) byte header yüklüyordu. İlginç olan, bu uzunluğun kasetteki uzunlukla uyuşmamasıydı. Beach Head kasetinde loading screen header’ının uzunluğu 22 byte iken, Match Day kasetindeki 21 byte uzunluğundaydı. Bir diğer deyişle, her iki oyun aynı miktarda (20 byte) header datasını kasetten yüklese de, kasette kayıtlı olan header uzunlukları talep edilenden biraz daha fazlaydı. Elbette bu da kafa karıştırmak için konulmuş bir tuzaktı!

Keyifle kod okuma işlemine devam ettim... Header ve Loading Screen için çağrılan komutlardan ilkini seçtim: Match Day için call &EB92, Beach Head için call &C7AE. İki farklı oyun iki farklı adres olmasına karşın, çağrılan subroutine’ler instruction bazında birebir aynıydı!

Kod: [Seç]
    - Match Day -    |    - Beach Head -
                     |
eb92: call &eaa9     |  c7ae: call &c6c5
eb95: ld hl,&8000    |  c7b1: ld hl,&8000
eb98: ld b,&ff       |  c7b4: ld b,&ff
eb9a: push bc        |  c7b6: push bc
eb9b: call &eba4     |  c7b7: call &c7c0
eb9e: ld (hl),e      |  c7ba: ld (hl),e
eb9f: inc hl         |  c7bb: inc hl
eba0: pop bc         |  c7bc: pop bc
eba1: djnz &eb9a     |  c7bd: djnz &c7b6
eba3: ret            |  c7bf: ret
eba4: ...            |  c7c0: ...
      ..             |        ..
      .              |        .

Bu subroutine’ler, hemen başka bir subroutine’i çağırarak kod içerisinde dallanmaya başlıyordu.

Kod: [Seç]
    - Match Day -    |    - Beach Head -
                     |
eaa9: di             |  c6c5: di
eaaa: inc d          |  c6c6: inc d
eaab: dec d          |  c6c7: dec d
eaac: ld a,&0f       |  c6c8: ld a,&0f
eaae: out (&fe),a    |  c6ca: out (&fe),a
eab0: ld hl,&eb84    |  c6cc: ld hl,&c7a0
eab3: push hl        |  c6cf: push hl
eab4: in a,(&fe)     |  c6d0: in a,(&fe)
eab6: rra            |  c6d2: rra
eab7: and &20        |  c6d3: and &20
eab9: or &02         |  c6d5: or &02
eabb: ld c,a         |  c6d7: ld c,a
eabc: cp a           |  c6d8: cp a
eabd: call &ea8e     |  c6d9: call &c6aa
eac0: jr nc,&eabd    |  c6dc: jr nc,&c6d9
eac2: ...            |  c6de: ...
      ..             |        ..
      .              |        .

Son geldiğim nokta, &FE port’undan low-level yükleme işlemlerini gerçekleştiren subroutine’lerdi.

Kod: [Seç]
    - Match Day -    |    - Beach Head -
                     |
ea8e: dec a          |  c6aa: dec a
ea8f: jr nz,&ea8e.   |  c6ab: jr nz,&c6aa
ea91: and a          |  c6ad: and a
ea92: inc b          |  c6ae: inc b
ea93: ret z          |  c6af: ret z
ea94: ld a,&7f       |  c6b0: ld a,&7f
ea96: in a,(&fe)     |  c6b2: in a,(&fe)
ea98: rra            |  c6b4: rra
ea99: xor c          |  c6b5: xor c
ea9a: and &20        |  c6b6: and &20
ea9c: jr z,&ea92     |  c6b8: jr z,&ea92
ea9e: ld a,c         |  c6ba: ld a,c
ea9f: cpl            |  c6bb: cpl
eaa0: ld c,a         |  c6bc: ld c,a
eaa1: and &07        |  c6bd: and &07
eaa3: or &08         |  c6bf: or &08
eaa5: out (&fe),a    |  c6c1: out (&fe),a
eaa7: scf            |  c6c3: scf
eaa8: ret            |  c6c4: ret

Bu kodları gördüğüm an, "Aaaaa, ben bunları bir yerden tanıyorum!" dedim. Hemen Melbourne House’un ROM kitabının 20. sayfasını açıp baktım. Yanılmamıştım, bildiğimiz LD-EDGE-1 (&05E7) subroutine’in kopyasıydı bu! Tek fark, LD-EDGE-2 (&05E3) subroutine’indeki gibi ezbere harcanan 358T state yoktu. Kasetteki sinyal aralığı örneklenerek elde edilen kalibrasyon değeri Accumulator içerisine yükleniyor, bu "dinamik" değer sıfırlanana kadar bekleniyordu. Ardından port I/O işlemine geçiliyor, işlem sonunda elde edilen polariteye göre border rengi belirlenip aynı port üzerinden ekrana gönderiliyordu. İşlem sırası ve ardarda gelen 19 adet instruction, (burada kullanılmayan RET NC komutu dışında) ZX Spectrum’un ROM’undaki LD-DELAY (&05E9) subroutine’iyle birebir aynıydı!

Uzun uğraşlar, uzun günler, uzun geceler sonunda vardığım yer, Spectrum’un ROM’undaki kasetten yükleme routine’lerinden fazlasıyla esinlenerek (!) yazılan "basit" bir turbo loader’dı. Onca şifreleme çabası ve kafa karıştırıcı kod okuma yolculuğundan sonra, dönüp dolaşıp yine Spectrum’un ROM’undaki standart port okuma ve bit ayıklama işlemlerine geri gelmiştim. Aradaki tek fark, 14 yaşında başlayıp bir sene içinde tamamladığım bu sıradışı yolculuk sırasında edindiğim bilgi ve tecrübeydi. Bundan böyle; problem çözme, bilimsel yöntem, eleştirel düşünme, karar verme, sorgulama, karşılaştırmalı düşünme, vb. önemli kavramlar hayatımın ayrılmaz bir parçası olacaktı. Bu değerler ile tanışmama yardımcı olan, iyi bir yazılımcı olabilmem için usta-çırak ilişkisiyle bilgilendiren, "yapamazsın, kıramazsın, seni aşar" diyenlerin aksine cesaretlendiren, hem güzel ahlakı hem de üst düzey mühendislik bilgisiyle aydınlık saçan rahmetli Mahir Bey’in anısı önünde saygıyla eğiliyor, benim için adeta bir okul olan ECOM Mühendislik bünyesinde -başta Necati Ağabey ve Suna Abla olmak üzere- üzerimde emeği bulunan herkese şükranlarımı sunuyor, artık aramızda olamasalar da farklı bir boyutta ısrarla karşılıklı tavla oynamayı sürdürdüklerini düşündüğüm Ted amcamın ve sevgili babamın ışıklar içinde uyumasını diliyorum.

Sinclair ZX Spectrum’da Match Day ile başlayıp Glass ile tamamlanan oyun kırma (cracking) serüvenim, bu iki oyun arasındaki sayısız turbo loader ve oyun boyunca sürdü. O dönemde elde ettiğim kodlama bilgisi ve tecrübesi, 1985 yılından itibaren dönemin en iyi İngiliz ve Fransız oyun firmalarına freelance olarak hizmet vermemin kapılarını açtı. O günden beri aynı tutku, azim ve disiplinle çalışarak küresel oyun sektörüne profesyonel olarak hizmet vermeyi sürdürüyor, soluklanmaksızın yeni bilgilere yelken açabilmek amacıyla ısrarla oyun kırmaya ve reverse engineering yapmaya devam ediyorum.

Doğumunun 40. yılında, ufkumu açarak bugünlere gelebilmemi sağlayan Sinclair ZX Spectrum’u sevgi ve özlemle anıyorum.

* Ekli Dosyalar:



Çevrimdışı Skate

  • RAAT
  • Retro Meraklısı
  • *
  • İleti: 172
Ynt: Retrospektif: Speedlock
« Yanıtla #5 : 22 Nisan 2022, 06:14:38 »
Her zamanki gibi harika bir retro teknoloji anı derlemesi olmuş. Genellikle sona bırakılır, ben mesajımın başında peşinen saygılarımı sunuyorum.

İnsan yazıyı okurken "bunca kod örneği ve uyguladığı adımları zamanında not mu almıştı, yoksa yıllar sonra teknik materyali oyunların orijinalleri üzerinden tekrar aynı adımları takip ederek mi oluşturdu?" gibi sorular sormadan edemiyor. Sorunun cevabı da o kadar önemli değil, önemli olan okurken bu tür şeyleri düşündürmesi, merak uyandırması.

Programcı olanlarımızdan çoğumuz farklı platformlarda da olsa benzer yollardan geçmiş olduğumuz için insanın kendi yaşadıklarından bir şeyler bularak okuması daha da keyifli oluyor. Zamanında böyle bir akıl hocası bulabilmiş olman büyük şans elbette ki. Ben de 10-12 yaşlarımda bana destek olan, kod disketlerini paylaşıp, gerek yüz yüze, gerek telefonda bitmek tükenmek bilmeyen sorumlarıma sabırla cevap veren, kurduğum gruba Commodore 64'deki ilk intromuzu kodlayan ve bize "intro nasıl kodlanır?"ı öğreten Mert Hekimci'yi senin vesilenle tekrar anmış oldum @matahari, sağol, varol. :) Mert en son bir konunun beni aşacağını düşünerek "daha yaşın küçük, bunu anlatsam da anlaman zor" gibi bir laf etmişti. O anda gelecekteki mesleğimi belirlemiş oldu sağ olsun.

Bu arada daha önce Amstrad CPC için Z80 kodu yazmış olsam da bunca yıldır ilk kez geçtiğimiz 24 saat içinde ZX Spectrum için kod yazmaya başlamamın ardından bu yazı daha da bir anlamlı oldu.

Çevrimdışı matahari

  • RAAT
  • Retro Meraklısı
  • *
  • İleti: 209
    • The Blog of Mert Börü
Ynt: Retrospektif: Speedlock
« Yanıtla #6 : 22 Nisan 2022, 07:36:58 »
Her zamanki gibi harika bir retro teknoloji anı derlemesi olmuş. Genellikle sona bırakılır, ben mesajımın başında peşinen saygılarımı sunuyorum.

Çok naziksin @Skate, teşekkür ederim. Saygı ve sevgimiz karşılıklı.

İnsan yazıyı okurken "bunca kod örneği ve uyguladığı adımları zamanında not mu almıştı, yoksa yıllar sonra teknik materyali oyunların orijinalleri üzerinden tekrar aynı adımları takip ederek mi oluşturdu?" gibi sorular sormadan edemiyor.

Her ikisi de. 8) Kendimi bildim bileli defter/kalem delisiyim! Sürekli yazıp çizmem, not almam sebebiyle eskiye dönük olayları "restore" etmem kolay oluyor. (Keşke kaset/disket için de aynısını söyleyebilseydim.) Bu çalışma için sadece eski notlarımdan değil, modern emülatör teknolojisinden de çok faydalandım. Notlarımdaki her adresi titizlikte test ettim, 38 sene sonra tüm süreci emülatör üzerinde bir kez daha yaşadım. Amacım; hem yazıyı birebir takip ederek crack işlemini kendi başına gerçekleştirecek macera tutkunları için bir kılavuz oluşturmak, hem de bugüne dek hiç değinilmemiş/eksik/yanlış bilinen bazı teknik konuları aydınlatmaktı. Üzerimde emeği olan o güzel insanları tarihe not düşerek kayıt altına almak ise görevimdi.

Bu arada daha önce Amstrad CPC için Z80 kodu yazmış olsam da bunca yıldır ilk kez geçtiğimiz 24 saat içinde ZX Spectrum için kod yazmaya başlamamın ardından bu yazı daha da bir anlamlı oldu.

Bak bu şimdi benim için de çok anlamlı oldu. Mütevazi Z80 ekosistemine tekrar hoşgeldin!

Çevrimdışı hades

  • RAAT
  • Retro Meraklısı
  • *
  • İleti: 179
Ynt: Retrospektif: Speedlock
« Yanıtla #7 : 22 Nisan 2022, 10:20:01 »
@matahari üstad yazdıklarını büyük bir ilgiyle ve dikkatle okudum. Kısa bir süreliğine z80 ile ilk ilgilenmeye başladığım yıllara döndüm. Zamanında Mahir Çelikkanat'a mektup yazmıştım. Sorularımdan biri "Zx Spectrumda printer buffera program yazıp çalıştırabilir miyim?" gibi bir soruydu. Sene muhtemelen 1986 olmalı.
Headerless save rutinini keşfetmiştim ve devamında bir oyunu o zamanlar kullanılan Ultrafile copy programının kopyalayamayacağı uzunlukta olacak şekilde save etmiştim. Hatırladığım kadarıyla kod printer bufferda veya hafızanın son adreslerinde çalışıyordu ve oyunun yükleme ekranını ve datasını yükledikten sonra $4000'den itibaren headerless save ediyordu.

Çevrimdışı matahari

  • RAAT
  • Retro Meraklısı
  • *
  • İleti: 209
    • The Blog of Mert Börü
Ynt: Retrospektif: Speedlock
« Yanıtla #8 : 22 Nisan 2022, 10:38:44 »
Sevgili @hades hocam, ne kadar iyi ettiniz bu paylaşımı yapmakla! Teşekkür ederim.

Anılarımızın Mahir Bey ekseninde kesişmesi gayet doğal. Zira, döneminin en aktif ve yetkin isimlerinden birisi olması sebebiyle, birçoğumuzun hayatına nazikçe dokunmuş kendisi. Geride bıraktığı kitapları ve yetiştirdiği öğrencileriyle hâlâ aramızda...

Çevrimdışı Attilan

  • RAAT
  • Retro Meraklısı
  • *
  • İleti: 132
Ynt: Retrospektif: Speedlock
« Yanıtla #9 : 22 Nisan 2022, 15:17:43 »
Sevgili @matahari , çok fazla anlamadığım teknik detaylar bir kenara, son dönemde özellikle dijital yayın platformlarının başı çektiği "80'lerde çocuk olmak" temalı bir çok yapımdan çok daha fazla haz aldım yazdıklarınızı okurken.
Garip tesadüfler, uluslararası dostluklar, değerli mentorlar, çok güzel bir anne/baba oğul ilişkisi, hepsi bir çeşit dijital dedektiflik hikâyesine sıkıştırılmış harika bir aile filmi tadı verdi.
Hatta okurken bir an istemsiz bir şekilde "hah şu John Candy, şu Chevy Chase, şu Bill Murray" diye kafamda karakterleri yerleştirirken yakaladım kendimi 🙂
Elinize kaleminize sağlık, tüm bu sıcak anıları paylaştığınız için ayrıca teşekkürler, sayenizde artık bunlar bizim de anılarımız oldu.

Bu değerler ile tanışmama yardımcı olan, iyi bir yazılımcı olabilmem için usta-çırak ilişkisiyle bilgilendiren, "yapamazsın, kıramazsın, seni aşar" diyenlerin aksine cesaretlendiren, hem güzel ahlakı hem de üst düzey mühendislik bilgisiyle aydınlık saçan rahmetli Mahir Bey’in anısı önünde saygıyla eğiliyor, benim için adeta bir okul olan ECOM Mühendislik bünyesinde -başta Necati Ağabey ve Suna Abla olmak üzere- üzerimde emeği bulunan herkese şükranlarımı sunuyor, artık aramızda olamasalar da farklı bir boyutta ısrarla karşılıklı tavla oynamayı sürdürdüklerini düşündüğüm Ted amcamın ve sevgili babamın ışıklar içinde uyumasını diliyorum.

Emeği geçenlerle ilgili yazdıklarınıza da en içten dileklerimle katılıyorum, her çocuğun böyle insanlarla karşılaşmasını ve hem o çocukların hem bizlerin gelecekte böyle insanlara dönüşebilmesini diliyorum. Saygılar sevgiler.

Çevrimdışı matahari

  • RAAT
  • Retro Meraklısı
  • *
  • İleti: 209
    • The Blog of Mert Börü
Ynt: Retrospektif: Speedlock
« Yanıtla #10 : 22 Nisan 2022, 16:38:48 »
... son dönemde özellikle dijital yayın platformlarının başı çektiği "80'lerde çocuk olmak" temalı bir çok yapımdan çok daha fazla haz aldım yazdıklarınızı okurken. Elinize kaleminize sağlık, tüm bu sıcak anıları paylaştığınız için ayrıca teşekkürler...

Sevgili @Attilan, nazik yorumlarınız için çok teşekkür ederim. Metnin tüm teknik ağırlığına rağmen size keyif vermesi, beni gerçekten çok mutlu etti. Elimden geldiğince işin teknik kısmını törpülemeye, herkes okuyup keyif alabilsin diye metni "daha anlaşılır" kılmaya çalışıyorum. Geribildiriminiz benim içim çok faydalı oldu. Teşekkür ederim!

... sayenizde artık bunlar bizim de anılarımız oldu.

Sahiplenmenize çok sevindim! Böylece aramızdaki saygı ve sevgi çok daha derinlere kök salıyor. 8)

... her çocuğun böyle insanlarla karşılaşmasını ve hem o çocukların hem bizlerin gelecekte böyle insanlara dönüşebilmesini diliyorum.

Ooooo, bu harika dileğe şapka çıkartıyor, içtenlikle katılıyorum! Bayrak yarışı devam ediyor...

Çevrimdışı metaone

  • Retromanik
  • *****
  • İleti: 8
Ynt: Retrospektif: Speedlock
« Yanıtla #11 : 22 Nisan 2022, 17:16:52 »
Z80 assembler bilmesem de (ki azıcık 6510 assembler biliyorum, kodun bir kısmının ne yaptığını tahmin edebildim); yazım dili, tarihsel içeriği ve de her yerde bulunmayacak bilgiler ihtiva etmesinden dolayı son derece güzel bir yazı olmuş, okumaya doyamadım. Elinize sağlık @matahari

Çevrimdışı matahari

  • RAAT
  • Retro Meraklısı
  • *
  • İleti: 209
    • The Blog of Mert Börü
Ynt: Retrospektif: Speedlock
« Yanıtla #12 : 22 Nisan 2022, 17:28:25 »
yazım dili, tarihsel içeriği ve de her yerde bulunmayacak bilgiler ihtiva etmesinden dolayı son derece güzel bir yazı olmuş, okumaya doyamadım. Elinize sağlık

Nazik geribildiriminiz için çok teşekkür ederim, @metaone. Faydalanmanıza gerçekten çok sevindim.

... kodun bir kısmının ne yaptığını tahmin edebildim.

Harika! Yolun yarısını geçtiniz demektir. Yeni şeyler öğrenirken "tahmin edebilme heyecanını" sürekli yaşadığım için, sizi çok iyi anlıyorum. Assembly literatürü okumayı sürdürürseniz, birkaç ay sonra bu sayfaya geri döndüğünüzde çok daha fazlasını anlayabildiğinizi görecek, bu hızlı gelişime siz de şaşıracaksınız. Özellikle 4. bölümdekine benzer teknik metinleri okumaya devam ediniz lütfen. 8)

Çevrimdışı Ref

  • Yönetici
  • Özgür Retrocu
  • *
  • İleti: 2881
  • Advanced User Simulator
    • ae unutmadan
Ynt: Retrospektif: Speedlock
« Yanıtla #13 : 22 Nisan 2022, 22:46:21 »
Her şeyin başında, okurken çok duygulandığımı söylemeliyim. Hem ailenin, hem çevrendeki o değerli insanların sana yardımcı olmak için gösterdikleri çabayı o kadar iyi kavramışsın ve cümlelerine o kadar iyi aktarmışsın ki, güleceksiniz ama okurken gözlerim yaşardı :D Ne kadar şanslısın ve onlar da çok değerli bir çocukla karşılaştıklarını anlayıp ne kadar da duyarlı ve sorumlu davranmışlar. Herkes bir romandan alınma karakter gibi, yapılması gerekeni yapıyor ve dünya bu insanlar sayesinde dönüyor.

Bu hikayedeki yaşananların ancak küçük parçalarına çok daha geç sahip olabildiğim için (bana daha çok okul müdür yardımcısı benzeri kısımları denk geldi), tüm hikayenin değerini daha iyi kavradığımı düşünüyorum.  Burada anlattığın konuları çok çok yıllar sonra, değil multiface, emülatörler ve modern geliştirme araçlarının çıkışıyla ancak kavrayabildiğim halde, yine de hikayeyi getirip sürpriz sonlu şekilde, saf rom rutinlerine bağladığında, hala bir çıraktan ibaret olduğumu görüyorum.   

Ama bu hikayenin ders alınması gereken noktası bir programın disassemble edilmesi değil, bir hayatı nasıl yaşamayı seçtiğinle ilgili olan kısmıdır. Dediğin gibi bayrak yarışı sürüyor, bu sebeple ilk yaptığım iş, kuzey'i kucağıma oturtup (evet 11 yaşında koca bir adam oldu ama olsun), bu yazıyı birlikte baştan okumaktı. Burada hem onun hem de benim için dersler var çünkü.

Eline klavyene sağlık, zx spectrum'un 40'ıncı yılında bize de güzel bir hediye oldu bu hikaye.

Çevrimdışı Shax

  • Yönetici
  • Normalleşmiş Retroman
  • *
  • İleti: 1207
Ynt: Retrospektif: Speedlock
« Yanıtla #14 : 23 Nisan 2022, 01:34:46 »
Bu, açık ara rrj üzerinde okuduğum en harika şey. Teknik kısımları beni aşsa da yüksek bir empati durumu yaratıyor hikayenin akışı. Çırağan yoluyla alakalı hiçbir fikrim olmasa bile, o kırtasiyeden kutuyla çıkan bendim de tadı hala damağımda kalmış gibi hissettim. Vakit ayırıp bizimle paylaşman harika, kendi adıma teşekkür ederim.
Sahip oldukların zamanla sana sahip olur.