commodore.gen.tr

Commodore => Commodore Yazılım => Konuyu başlatan: i_r_on üzerinde Ocak 02, 2019, 01:18:13 ÖÖ



Konu Başlığı: Bir basic sorusu
Gönderen: i_r_on üzerinde Ocak 02, 2019, 01:18:13 ÖÖ
Aşağıdaki program ne yapar?

1 t=828:p=56320:for x = 0 to 7:for addr = t to t+63
2 y = peek(p) and 16 : if y>0 goto 2
3 bit = peek(p) and 1 : poke addr,  (peek(addr) and 255-2^x) or (bit * 2^x)
4 next : next : sys t


Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: wizofwor üzerinde Ocak 02, 2019, 08:25:38 ÖÖ
Bu toplantıda bahsettiğin program değil mi? Joystickten girilen 64 baytlık kodu 828 adresinden başlayarak belleğe alıp çalıştırıyor. 512 bit tek tek girilmesi lazım. Datayı elle mi giriyorsun, yoksa ardunio'dan falan mi girilecek?


Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: blackturk üzerinde Ocak 02, 2019, 11:53:29 ÖÖ
Joy port üzerinden bit bit data alınıp,belleke yerleştiktikten sonra çalıştırdığını görüyoruz. wiz of wor 'un  dediği gibi.


Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: i_r_on üzerinde Ocak 02, 2019, 12:20:58 ÖS
Bravo, doğru tahmin  :)

Toplantıda bahsetmedim sanıyorum. Öncesi de var gerçi muhtemelen forumda
bahsetmişimdir anca olay tamamen toplantıda bana pas edilen kontorland marka çakma famicom gamepad'ler üstünden şekillendi. Önce dedim bunları C64'e uyarlayayım bir işe yarasınlar. O noktada da cerrahi müdahaleden ziyade arabirim tadında bir şey yapayım dedim arduino ile.

Olay zaten basit, aşağıdaki linkte koduna kadar var,

https://www.allaboutcircuits.com/projects/nes-controller-interface-with-an-arduino-uno/ (https://www.allaboutcircuits.com/projects/nes-controller-interface-with-an-arduino-uno/)

Bunu mini proje şeklinde forumda ayrı bir başlıkta açıklayacağım.

Bunu yapınca sıra esas emelime geldi, tahmin ettiğiniz gibi o basic program joystick'ten gelen sinyallere göre hafızaya program yükleyip çalıştırıyor. Sadece ateş tuşuna kısaca basıldığında 1, Yukarı tuşu ile beraber ateş tuşuna basıldığında da 0 bit'ini en anlamsız bitten en anlamlı bit'e doğru tüm transfer edilecek byte'lara diziyor.

Bu 64 byte'lık kısım önyükleyici gibi bir şey olacak, 64 byte'lık assembly kodu çalıştığında daha büyük bir alana daha hızlı (fire yine senkronizasyon için kullanılıp 4 yön tuşu data transferi için kullanılacak) veri transferi yapacak. Kod sığmazsa (sığacağını düşünüyorum) bir stage daha ekleyebilirim, 64 byte'lık olan 256 byte yükler o da esas payload'ı yükler gibi... Tabii burada amaç basic'te olabildiğince az data yükleyip hızı arttırmak.

Esas niyetim de aslında basic ve/veya kernal'i exploit etmek. İlk mesajımdaki basic programın çok çok daha azını yazıp kullanıcının yükleme yapabilmesi. Aklımda bir iki fikir var, birincisi klavye buffer'ını kullanarak diğeri de bir bellek alanı düzenli bir şekilde spam ederek nihayetinde belirli bir byte dizisine ulaşmak şeklinde (ikisi de henüz fikir düzeyinde)  İkincisi Z80 boot etmek için kullanılan sistematiğe benzer bir şey olacak. (http://www.z80.info/jmz8boot.htm (http://www.z80.info/jmz8boot.htm))


Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: cdemir üzerinde Ocak 02, 2019, 14:19:00 ÖS
@i_r_on.
Tüm yazdıklarını okudum, anlamadım. Ama okumak hoşuma gitti :D

Her ne yapıyorsan kolay gelsin :)


Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: Skate üzerinde Ocak 02, 2019, 14:20:29 ÖS
Soru:

- Neden basic?

:)


Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: i_r_on üzerinde Ocak 02, 2019, 14:34:13 ÖS
Soru:

- Neden basic?

:)

Bu bir nevi chain loader gibi bir şey olacak, basic sadece ilk yükleyiciyi yükleyecek, o belki diğer yükleyiciyi falan gibi..

Kafamda düşündüm, DATA statement'ları ile falan assembly'i basic'e gömsem yine aşağı yukarı aynı sayıda girdi gereksinimi olur dedim. Tabii pratiğe döküldüğünde daha az olabilir, denemedim. İlk mesajdaki basic kodu da muhtemelen daha çok optimize edilir.

Ama benim derdim daha çok exploit etme yönünde... daha kısa bir statement yazdırayım kullanıcıya, arkada olaylar gelişsin şeklinde. dediğim gibi düşünce seviyesinde ancak kafamda ilerleyebileceğim bir kaç baz nokta var.

Tabii olay fantazi tamamen, son kullanıcıya esprisi olan bir ürün falan çıkmayacak muhtemelen buradan.


Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: Oğuzhan üzerinde Ocak 02, 2019, 14:49:26 ÖS
son kullanıcıya esprisi olan bir ürün falan çıkmayacak muhtemelen buradan.

1 adet lehimli 1 adet lehimsiz alabilir miyim.

Pardon ya alışkanlık oldu :)


Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: Skate üzerinde Ocak 02, 2019, 15:20:42 ÖS
Neden basic dememin nedeni şu.

Kod:
0 a=53265:d=128:v=53280
1 wait a,d:pokev,9:pokev,8:pokev,7:pokev,5:pokev,4:pokev,3:goto 1

Tek karakterlik parametreleri olan bir poke komutu CPU'nun yaklaşık %14.5'unu yiyor. :D Assembly karşılığı ise %0.03 yani on binde üç yiyor. Arada 500 kat falan hız farkı var. Projenin amacını ben de tam anlayamadım ama işin içinde "veri transferi" lafı geçiyorsa basic o konuya helper tool olarak bile yaklaşmamalı. Basic'in tek görevi bir adet SYS ile sınırlı kalmalı. :)


Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: i_r_on üzerinde Ocak 02, 2019, 16:25:28 ÖS
Burada amacım aslında bu üçkağıdı çevirebilmek için kullanıcının girdiği karakter miktarını mümkün olan en kısa hale getirmek.

Basic'teki zaman açısından oluşan overhead'e tabii bakmak lazım... Şimdiye kadar hiç performans ölçümü yapmadım ancak çok yavaşmış yahu... integer değişken kullanırsak bir miktar hızlanır. Örnek kodumu yazarken de çok önemsemedim, hatta testini vice'ta numpad'i joystick olarak kullanıp 3 byte göndererek yaptığım için tam tersi bir handikapım oldu, kod hızlı olunca tek basışta iki bit transferi söz konusu olduğu için yavaş çalışıyor olması tercih sebebi oldu.

Akşam assembly'de yazayım bakayım, belleğe basic ile girildiğinde daha kısa çıkıyor mu.


Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: wizofwor üzerinde Ocak 02, 2019, 16:38:45 ÖS
Program elle girilecekse BASIC'in yavaşlığının bir önemi yok. Hızlandırmak için 4 yönü de kullanabilirsin. Yönler ilgili biti açar, ateş'le bir sonraki nibble'a geçersin.

ilk nibble: yukarı 0, aşağı 1, sol 2,  sağ 3, ateş ok.
ikinci nibble: yukarı 4, aşağı 5, sol 6,  sağ 7, ateş ok.

gibi.


Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: i_r_on üzerinde Ocak 02, 2019, 16:54:37 ÖS
Program elle girilecekse BASIC'in yavaşlığının bir önemi yok. Hızlandırmak için 4 yönü de kullanabilirsin. Yönler ilgili biti açar, ateş'le bir sonraki nibble'a geçersin.

ilk nibble: yukarı 0, aşağı 1, sol 2,  sağ 3, ateş ok.
ikinci nibble: yukarı 4, aşağı 5, sol 6,  sağ 7, ateş ok.

gibi.

Elle girilirse MDE'ye bile alternatif olmaz  ;D
NES joystick adaptörü üzerindeki arduino pro mini yapacak aktarımı.

Bu arada vice'ın klavyeden joystick emülasyonu sıkıntılı. Hem yukarı hem de aşağı tuşuna aynı anda basmayı algılamıyor meret.


Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: ilkerficicilar üzerinde Ocak 02, 2019, 17:47:29 ÖS
Aslında josytick port 1'de ilgili bitleri yukarı çekince, kernal klavye taraması yaparken shift-run/stop basılıymış gibi okuma yapabiliyor. Eğer o sırada datasette portuna bağlı bir Arduino ile ilgili kodun .wav dosyası çalınırsa istenen boot işlemi gerçekleştirilebilir.


Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: cdemir üzerinde Ocak 02, 2019, 17:54:30 ÖS
@i_r_on

Ben de; configdeki South west, South east vb. gibi ara yönleri niye koymuşlar ?
Zaten iki tuşa aynı anda basınca olmuyor mu diyordum.. Demek ki bazı durumlarda gerekliymiş :D

Ek: Pardon yukarı ve aşağı demişsin. Ben ya yanlış okudum, ya da yanlış algıladım yazdıklarını... :D

(http://resimag.com/p1/f80b02d0a74.png)


Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: i_r_on üzerinde Ocak 02, 2019, 18:03:17 ÖS
Aslında josytick port 1'de ilgili bitleri yukarı çekince, kernal klavye taraması yaparken shift-run/stop basılıymış gibi okuma yapabiliyor. Eğer o sırada datasette portuna bağlı bir Arduino ile ilgili kodun .wav dosyası çalınırsa istenen boot işlemi gerçekleştirilebilir.

Kaset portundan proper yükleme yapabilen cihazlar var (tapecart, tapuino vesaire)
Benim amacım sadece joy portu kullanmak ama yükleme için kullanıcıya minimum kod yazdırmak.


Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: blackturk üzerinde Ocak 02, 2019, 18:25:13 ÖS
   Hades 'in joy port üzerinde çalışan , cf card projesi vardı.Bir türlü linki bulamadım. Commodore gen tr 'de paylaşmıştı diye hatırlıyorum.Bunu görünce onun projesi aklıma geldi.Bence bu konuda iyi yorumu olurdu.


Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: Skate üzerinde Ocak 02, 2019, 19:07:34 ÖS
Şu anda Mac OS üzerinde olduğumdan deneyemedim (3.1'e kadar binary üretilmiş) ama Vice 3.3'de joysticklerin karşı yönlere çekilip çekilememesi checkbox olarak var diye aklımda kalmış.

Bu arada neden joystick ile input yapıldığını hala anlamış değilim. Klavyeden bir şeyler girsek, sonra bunu istediğimiz gibi out etsek olmuyor mu? Niye uğraşıyoruz joystick ile tek tek?


Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: i_r_on üzerinde Ocak 02, 2019, 19:52:50 ÖS
Gerçek hayattaki karşılığını açıklayayım anlaşılsın. Yaptığım NES/PS1->C64 kontrolcü adaptöründe bir microcontroller kullanma durumundayım ya da sallıyorum hali hazırda var olan Nunchuk64 projesini geliştirme derdindeyim ek özellik katacağım.

Mevcuttaki adaptör vazifesinin yanısıra bu donanıma üstündeki flash'tan yahut bağlı flash'tan yükleme yapma yan özelliğini getireceğim.

Joystick adaptörünü takacaksın, bir - iki satır basic kodunu yazıp programı çalıştıracaksın, joystick'te bir tuşa basacaksın. 6-7 saniye içinde adaptördeki içerik yüklenecek.

İşin zor kısmı kullanıcıya yazdırılması gereken basic önyükleyicisini mümkün olduğunca küçük yazabilme.

Bu noktada da kernal ve veya basic'i exploit eden bir şey yazmak gerekiyor. Doğrudan amaca yönelik bir program ilk mesajımda yazdığım gibi oldukça uzun. Boyut için optimize edilebilir ancak yine de hedeflediğimden uzun. Tabii ki tüm yüklemeyi basic ile bir iki satırda kotarılması gereken exploit yapmayacak. Amaç esas yüklemeyi yapacak kadar makine kodu yükleyebilmeyi sağlamak. Bu arada WAIT komutu yeterince hassas ise asenkron yerine senkron haberleşme de yapılabilir ve exploit'e gerek kalmadan program önemli ölçüde kısaltılabilir.


@Skate : Basic'den assembly girmek için şimdiye kadar gördüğüm tek yöntem for döngüsü ile belleğe data statement'ları ile girilmiş kodu aktarmak ve çalıştırmak şeklinde. Bellekte sallıyorum 64 byte ile sunulan bir şey girişin ondalık olarak yapılmak zorunda olmasından dolayı kafadan 120-180 karakter aralığında olması demek. Benim yazdığım basic program toplam 189 karakter. 64 byte farazi, assembly'de kodu yazıp optimize etmedim. 30-32 byte yapılırsa basic'e göre avantajlı olabilir size açısından.

   Hades 'in joy port üzerinde çalışan , cf card projesi vardı.Bir türlü linki bulamadım. Commodore gen tr 'de paylaşmıştı diye hatırlıyorum.Bunu görünce onun projesi aklıma geldi.Bence bu konuda iyi yorumu olurdu.

Aşağıdaki başlıktaymış,
http://www.commodore.gen.tr/forum/index.php?topic=15975.0 (http://www.commodore.gen.tr/forum/index.php?topic=15975.0)

Benim niyetim proper bir interface yapmak değil aslında. Joystick adaptörünün içine sürpriz yumurta kondurmak :)

Bu arada proje ikinizin projesi değil miydi? Ne ara sadece Hades'in projesi oldu?  ;D ;D


Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: i_r_on üzerinde Ocak 03, 2019, 01:14:24 ÖÖ
Öncelikle assembly ile yazıldığında aşağı yukarı kaç byte oluyor buna baktım, 25 byte ile Fire + Up butonu aynı anda switch edilme durumunda çalışacak kod yazılabiliyor. Bug'lı da olabilir, denemedim. (Muhtemelen öyledir, zaten arduino tarafında iki pin'i birden aynı anda sürme, CIA çipinin ikisini aynı anda okuması falan şans biraz)

Kod:
; Loader for Joy zımbırtısı
; Alternative to basic
JOY2 = $DC00
TAPEBUFFER = $033c
*=$62C
LDY #8
NEXTBITS
LDX #0
-
LDA JOY2
AND #$11
BEQ -
CMP #$01 ;If Up not pressed than carry will be set
ROL TAPEBUFFER, X
INX
BNE -
DEY
BNE NEXTBITS
JMP TAPEBUFFER

Basic'e data statement'ları ile yedirildiğinde muhtemelen ilk basic versiyonundan daha kısa olur.

Bu kodu doğrudan denemedim, basic kodu ile deneme yapayım dedim önce. Fire kodu ile senkronizasyon beklediğim kadar kolay olmadı (düzgün transfer yapılamadı yani :) ) Basic kodunun hızı değişken olduğu için Fire'a basılı olmadığı sürece dön, bit transfer işlemi ve tekrar başa dönme arasında microcontroller'ın fire'dan elini çekmesi gerekiyor. Interrupt'lardan dolayı süre değişken. Sabit olsaydı bile ölçüp arduino tarafına uygun bekleme süreleri eklemek gerekiyordu.

Basic ile çalışma süresi de hakikaten oldukça uzun... Bakalım, ilk etapta herhangi bir şeyi, herhangi bir sürede yükleyebilirsek optimize etmesi de çok zor olmaz.


Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: i_r_on üzerinde Ocak 04, 2019, 02:18:17 ÖÖ
Proje olarak muhtemelen başka bir başlığa geçeceğim ama şimdilik buradan devam edeyim.

Hummalı debug sekansları sonrasında büyükçe bir ana loader kodu ile yükleme yapabildim. Toplantıda sunumda anlattığım gibi, başta çözmüş olman gereken sorunlar hep insanın sonradan aklına geliyor. Tabii ki yine aynısı oldu. Timing fix yapmak için ince ayar peşinde koşarken badline'ların yine peşimizi bırakmadığını son anda farkettim  ;D ;D

Ana loader kodu içine koyduğum bir sürü angarya kod çöp oldu (makine dilinde 60 byte, gereksiz nop'lar var içinde)

Mevcut kodla senkronizasyon sağlayabilmek için badline'lardan kurtulma yani ekranı kapatmayı tercih ettim.

Videoda şunlar oluyor,
1. Oturup baştan yazmamak için ana loader'ı kartuştan açıyorum. Loader ekran hafızasında ortalarda çalışıyor (1580 adresinde)
2. Loader ekranı kapatıyor ve joystick'ten input beklemeye başlıyor.
3. Arduino pro mini içindeki ikincil yükleyicinin yüklenebilmesi için çakma nes controller'ı üstündeki start tuşuna basıyorum.
4. Kısa bir süre içinde 256 byte'lık aktarım tamamlanıyor ve ikincil loader çalışıyor. Şimdilik ekrana yazı basıp arkaplan rengini cycle eden 69 byte'lık bir program koydum. Bir sonraki aşamada bu loader'ın görevi esas oyun/program vesaireyi joystick portuna bağlı arduino pro mini'den yüklemek olacak.

İkincil loader'da ekran hafızasına yükleniyor (videonun sonunda en altta gözüken kısım)

SyubTjSd6Os

Şimdi hedef ana loader'ı olabildiğince kısaltmak

ps: Neden ekrana kod atıyorum? Görsel olarak transferi doğru yapıp yapmadığımı kontrol etmek için böyle bir yöntem tercih ettim, her iki loader'ı da aslında ekranı kirletmeden istediğim yerde çalıştırabilirim.


Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: ilkerficicilar üzerinde Ocak 04, 2019, 07:49:18 ÖÖ

Basic'e data statement'ları ile yedirildiğinde muhtemelen ilk basic versiyonundan daha kısa olur.

Ben data satırlarına on altılık sayı sisteminde string koyup virgül ve yüzdelik basamağından kurtuluyordum.

Örnek:

10 DEFFNA(X)=X-(48-7*(X>64)):READA$:FORI=.TO24
20 POKE1550+I,FNA(ASC(MID$(A$,I*2+1,1)))*16+FNA(ASC(MID$(A$,I*2+2,1))):NEXT
30 DATAA008A200AD00DC2911F0F9C9013E3C03E8D0F188D0EC4C3C03

not: Örnek kodu denemedim, elimin altında Vice yok, ama çalışması lazım.


Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: i_r_on üzerinde Ocak 04, 2019, 12:31:05 ÖS

Basic'e data statement'ları ile yedirildiğinde muhtemelen ilk basic versiyonundan daha kısa olur.

Ben data satırlarına on altılık sayı sisteminde string koyup virgül ve yüzdelik basamağından kurtuluyordum.

Örnek:

10 DEFFNA(X)=X-(48-7*(X>64)):READA$:FORI=.TO24
20 POKE1550+I,FNA(ASC(MID$(A$,I*2+1,1)))*16+FNA(ASC(MID$(A$,I*2+2,1))):NEXT
30 DATAA008A200AD00DC2911F0F9C9013E3C03E8D0F188D0EC4C3C03

not: Örnek kodu denemedim, elimin altında Vice yok, ama çalışması lazım.


Uzun makine dili programların basic ile saklanması için güzel yöntem :) Benim için overhead'i çok fazla.

Finalde kullanamam çünkü niyetim/hedefim toplamda 70-80 karakter girişiyle kullanıcının loader'ın girişini tamamlayıp çalıştırması. Burada örneğin 178 tuş vuruşu ile 25 byte'lık bir program girişi yapılıyor.


Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: ilkerficicilar üzerinde Ocak 04, 2019, 13:33:10 ÖS
Çok kısa bir base64 çözücü yazarsak, senin 25 byte'lık MD kod 36 byte'a sığıyor:

oAiiAK0A3CkR8PnJAT48A+jQ8YjQ7Ew8Aw==



Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: i_r_on üzerinde Ocak 04, 2019, 13:55:47 ÖS
Çok kısa bir base64 çözücü yazarsak, senin 25 byte'lık MD kod 36 byte'a sığıyor:

oAiiAK0A3CkR8PnJAT48A+jQ8YjQ7Ew8Aw==

Astarı yüzünden pahalıya çıkar :) Kodu yazarken kullanılan opcode'lar ve data dikkat edilip seçilirse print edilebilen karakterlere çevirecek basit bir function üretilebilir belki. Böyle olunca her bir karakter bir byte'ı ifade edecek şekilde saklanabilir. Tabii bu noktada 6502'nin tasarımı bizi vuruyor, opcode'lar tasarlanırken bit bit değerlendirildiği için 0-255 kod aralığının her tarafına denk gelen opcode var. undocumented opcode'lar bu işi biraz rahatlatabilir.

Çalışan, minimize edilmiş bir loader kodu üstünden buna biraz kafa yorayım ben.


Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: i_r_on üzerinde Ocak 05, 2019, 00:53:21 ÖÖ
Bu arada aklıma bir veri transfer yöntemi daha geldi. Arduino tarafında biraz işi var ama kodu kısaltır mı diye kontrol edeceğim.

Şöyle,
Malum Joy port 1'e bir lightpen bağlanabiliyor. Arduino pro mini bir lightpen gibi davranacak, şöyle,

1. Program 255'den büyük belli bir raster satırında arduino'ya başla diyecek
2. Arduino bu sinyali alır almaz satırları saymaya başlayacak, bir sonraki ekran taramasında hangi byte'ı göndermek istiyorsa tam o satırın ortalarında bir yerlerde Fire/Lightpen sinyalini low'a çekecek. VIC her frame bu sinyali gördüğünde butona basıldığı an bulunan satır numarasını $D014'deki register'a yazıyor.
3. Programımız 255'den büyük satıra gelindiğinde bu register'dan değeri okuyup programı sakladığı yere yazacak.

Böylece her ekran taramasında arduino programımıza 1 byte aktarabilir.
Bu yöntemde ekran kapama ihtiyacımız yok, bit bit transfer olmadığı için register'lardan biri de boşa çıkıyor. Şöyle bir sıkıntı var, joystick port'undaki bir hattı c64'ün çıkış olarak kullanması lazım. DDR register'ını iki defa ayarlama ihtiyacı söz konusu ise program yine uzuyor.

ps: benzer şekilde arduino potansiyometreymişçesine de 8 bit transfer yapılabilir sanırım. tabii arduino'nun analog çıkışı olmadığı için direnç merdiveni tarzı bir şey yapmak lazım, yaş iş.


Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: wizofwor üzerinde Ocak 05, 2019, 10:46:00 ÖÖ
Analog yok ama PWM var. PWM kullansak yemez mi?


Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: i_r_on üzerinde Ocak 05, 2019, 14:26:08 ÖS
Analog yok ama PWM var. PWM kullansak yemez mi?

Mouse projelerine baktım da, ne analog'a ne de pwm'ye falan ihtiyaç yokmuş. Küçük bir direnç üstünden ilgili pot'un doğru zamanda high'a çekilmesi yeterliymiş. Tabii 0..255 arası hassasiyeti yakalamak mümkün müdür bakmak lazım.


Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: i_r_on üzerinde Ocak 07, 2019, 02:16:05 ÖÖ
Son yazdığıma istinaden.. herhangi bir deneme yapmadım ama 0-255 arası hassasiyeti yakalamak zor gözüküyor. Çünkü sid 512 cycle'lık pot ölçme zamanının ilk 256 cycle'ını kapasitörü dejarj etmek için kullanıyor. Kalan 256 cycle'ı da 0-255 arası değeri belirlemek için kullanıyor. Bağlantı yapılırken zaten akım sınırlansın diye 5-10K'lık bir direnç bağlanıyor, ilaveten bağlı microcontroller'ın cycle hassasiyetinde response vermesi lazım, bu da mümkün değil. Zaten 1351 mouse için de hassasiyet için 6 bit gibi rakamlar telaffuz ediliyor.

Daha önce paylaştığım assembly kodu bug'lıymış bu arada :) 0 harici bitlerin transferi mümkün değil zira 1 gönderildiğinde ilk loop'ta takılı kalıyor program :)

Son pratik denememde 35 byte'a kadar çıkmıştı kodun uzunluğu malum badline'lardan ötürü... Epey bir kastım kısaltmak için ancak çok da fazla kısaltamadım. 23 byte'a indirebildim. (Y'ye bağlı decrement ve init ihtiyacı olmasa 3 byte daha kısalıyor aslında)

Kodda şu trick'ler var,

1. Basic programda CIA interrupt'ları kapatılıyor. (Yer kurtarmak için vektörlerin olduğu yeri kullandık, interrupt'lar açık olursa ortalık karışır. )
2. X ve Y'yi initialize etmek için SYS komutunun hali hazırda sunduğu imkanı kullanıyoruz, LDX#0, LDY#8 yerine 0 ve 8 değerlerini SYS komutunun alıp kullandığı $30D ve $30E adreslerine denk getiriyoruz. $30F adresine de status register olarak LDA komutunun opcode değeri olan $A9 geliyor. Böyle olunca decimal flag açılmış oluyor ama bunun bize bir etkisi olmuyor çünkü kodda bu flag'in etkilediği bir işlem yok. Sadece SBC ve ADC etkileniyor decimal flag'den.

3. Önceki kodda yüklediğimiz koda jump vardı, ikincil loader'ı basic'ten çalıştırılanın sonuna koyarak jump'tan kurtulduk. Transfer bitince program doğrudan ikincil loader'ı çalıştırmaya devam ediyor.

4. Kodunu paylaşmadığım videodaki versiyonda zamanlamayı tutturmak için ekran kapatılıyordu. SYS komutunun A için default değer atadığı yere $0B koysak ve programın başında STA $D011 desek 4 byte ile kurtaracağız. Bunun yerine sistemde hali hazırda varolan 1ms bekleme rutinini çağırıyorum her bit transferinden sonra. Microcontroller tarafından buton basma işi badline'a denk gelse bile micro bir badline'ın çaldığı süreden fazla bekliyor bastığı butonu bırakmak için, kayıp yaşanmıyor.

Kozmetik sebeplerle Fire + Up kombinasyonundan vazgeçip Down + Up kombinasyonuna geçtim.

Kod:
; Loader for Joy zımbırtısı
; Alternative to basic
JOY2 = $DC00
DELAY_1MS = $EEB3

*=$030D
.BYTE 0
.BYTE 8
NEXTBITS
-
LDA JOY2 ;3
CMP #$7F ;2
BEQ - ;2
CMP #$7D ;2 ;If Up not pressed than carry will be set
ROL PRGLOAD, X ;3
JSR DELAY_1MS ;3 ;doesn't affect carry
INX ;1 ;INX doesn't affect carry..
BNE - ;2
DEY
BNE NEXTBITS ;2
; Aligning the second stage loader at the end of initial loader, hence we save 3 bytes
; getting rid of jumping...
; This area is actually used by kernal vectors but it's easy to restore them later from rom.
PRGLOAD

Basic'e çevrilmiş hali de şöyle,

Kod:
1 poke56334,0:fori=0to22:read a:poke781+i,a:next:sys783
2 data 0,8,173,0,220,201,127,240,249,201,125,62,36,3,32,179,238,232,208,238
3 data 136,208,235

Muhtemelen optimizasyonu bir kenara bırakıp bambaşka bir yöntemle daha kısa bir loader yazılabilir mi onu araştıracağım devamında.




Konu Başlığı: Ynt: Bir basic sorusu
Gönderen: i_r_on üzerinde Ocak 09, 2019, 00:28:18 ÖÖ
Optimizasyona bir başladı mı bırakamıyor insan :)

Yöntemde ciddi bir değişikliğe gitmeden 23 byte'tan 17 byte'a inerek 6 byte daha kurtardık. Programın basic'ten kodlanan hali aşağıdaki gibi oldu,

Kod:
1 poke56334,0:fori=0to16:reada:poke780+i,a:next:sys780
2 data 173,0,220,74,176,250,74,62,29,3,232,74,32,179,238,176,239

Assembly kodu şu şekilde,

Kod:
; Loader for Joy zımbırtısı
; Alternative to basic
DELAY_1MS = $EEB3
JOY2 = $DC00
;XXXFRLDU
;-----|||
;-----||*--- Up - Indicates if there is ongoing transfer
;-----|*------ Down - Transferred bit
;-----*--------- Left - Flags end of transmission (1=continue, 0=stop)

*=$030C
NEXTBITS
-
;Low byte of JOY2 (DC00) also used to initialize X register to 0 by SYS command
LDA JOY2 ;3
;State of up button flags the transfer
;1=Not pressed,no transfer; 0=Pressed, transfer started
LSR
;
BCS - ;2
;Shifting the least significant bit into carry we get
;transferred bit (Down not pressed = 1, Down pressed = 0)
LSR ;1
;We put the transferred bit into the respective byte
ROL PRGLOAD, X ;3
;Next bit transfer for next byte, incrementing X
INX ;1 ;INX doesn't affect carry..
;Shift redundant stop bit into Carry
;1 means go on, also satisfies CMP#$7F
;0 means stop transmission.. no need to use another register
LSR ;1
;To prevent badlines interfering with the synchronization,
;we wait >40 cycles... an existing rom routine preserves the
;X register and takes approx. 1ms. Luckily, it doesn't touch carry.
;It destroys A register but we already shifted the redundant bit into carry
JSR DELAY_1MS ;3
;Use Left button press decide ending/continuing transfer
BCS NEXTBITS ;2
; Aligning the second stage loader at the end of initial loader, hence we save 3 bytes
; getting rid of jumping...
; This area is actually used by kernal vectors but it's easy to restore them later from rom.
PRGLOAD

Daha önceki kodda ikişer byte'lık CMP instruction'ı bizi optimize et dercesine sırıtıyordu. O sırada aklıma redundancy kavramı geldi. Sonuçta burada iletişim protokolünü ben belirliyorum, loader kodunu küçültme üzerine optimizasyon yapıyorum. Redundancy / Redundant kelimelerini sistemci arkadaşlar bilirler, gerekmediği halde bir şeyden bir kaç tane daha kullanırsınız, bunun size başka avantajları olur falan filan.

Başta trick sayılmayacak şu optimizasyon var, CMP #$7F yerine artık yüklediğim değeri tek byte'lık LSR instruction'ı ile sağa kaydırıyorum, böylece transfer başladı mı başlamadı mı anlayabiliyorum.

Trick'ler şunlar,

1. Redundancy demiştik... Şöyle, sadece 1 bit transferi yapmamıza rağmen arduino artık kod idare edilsin diye 3 buton state'i yani 3 bit gönderiyor. Bit'lerin sıralaması da kodda geçtiği sıraya göre... Yukarı tuşu ilk kaydırılan bit olduğu için transferin başlayıp başlamadığını, Aşağı tuşu transfer edilecek bit'i ve son olarak da Sola tuşu daha öncekki kodda Y register'ı ve bir branch ile idare edilen bitiş kontrolü görevini üstleniyor.

Eskisine nazaran arduino'daki kod biraz daha kompleks oldu, (eskisini paylaşmadım ancak, eskisi bunun yarısı, öyle düşünün)

Kod:
void SendBitSlow(uint8_t bitValue) {
  if (bitValue == 0) {
      BIT_CLEAR(PORTD, TRANSFERRED_BIT);     
      BIT_CLEAR(PORTD, TRANSMISSION_CONTROL_BIT);
      delayMicroseconds(100); //Keep it low more than duration of badlines
      BIT_SET_VAL(PORTD, _BV(TRANSFERRED_BIT) + _BV(TRANSMISSION_CONTROL_BIT) );     
  } else {
      BIT_CLEAR(PORTD, TRANSMISSION_CONTROL_BIT);
      delayMicroseconds(100);
      BIT_SET(PORTD, TRANSMISSION_CONTROL_BIT);
  }
 
  delayMicroseconds(1000); //C64 side waits for at least 1ms between each bit
}

void SendFinalBitSlow(uint8_t bitValue) {
  if (bitValue == 0) {
      BIT_CLEAR(PORTD, STOP_BIT);
      BIT_CLEAR(PORTD, TRANSFERRED_BIT);
      BIT_CLEAR(PORTD, TRANSMISSION_CONTROL_BIT);
      delayMicroseconds(100); //Keep it low more than duration of badlines
      BIT_SET_VAL(PORTD, _BV(STOP_BIT) + _BV(TRANSFERRED_BIT) + _BV(TRANSMISSION_CONTROL_BIT) );     
  } else {
      BIT_CLEAR(PORTD, STOP_BIT);
      BIT_CLEAR(PORTD, TRANSMISSION_CONTROL_BIT);
      delayMicroseconds(100);
      BIT_SET_VAL(PORTD, _BV(STOP_BIT) + _BV(TRANSMISSION_CONTROL_BIT) );
  }
 
  delayMicroseconds(1000); //C64 side waits for at least 1ms between each bit
}

void SendSecondStageLoader() {
  for (uint8_t mask = 128;mask>=1;mask=mask>>1) {
    for (int i = 0;i<stub_len;i++) { 
      uint8_t current = pgm_read_byte(stubData + i);
      SendBitSlow(current & mask);
    }   
   
    for (int i = stub_len;i<255;i++) { 
      SendBitSlow(0);
    }       
   
    if (mask == 1) {
      SendFinalBitSlow(0); //The value doesn't matter... commences transfer
    } else {
      SendBitSlow(0);
    }
  }
}

Transferin bitişini artık arduino kontrol ettiği için arduino tarafında&nbsp; iç içe iki for ile ifade edilen döngü, c64 tarafında tek döngüye dönüşmüş oldu. Artık kod X'in durumu ile de ilgilenmiyor. Ne de olsa o 0-256 arasında 8 kez sayıp duruyor.

2. Bunu zaten daha önce kullanmıştım ancak üstteki trick'i daha önce çeviremediğim için bırakmıştım. Önceki programa bakarsanız programın tepesinde iki adet byte deklarasyonu var. Bu programda buna gerek kalmadı çünkü ilk komutun (LDA JOY2) JOY2 operand'ı yani $DC00'ın düşük anlamlı byte'ı 00 değeri X register'ının başlangıç değeri olarak kullanılıyor. Y, A ve hatta processor status register'ının başlangıç değerlerinin kodun çalışması anlamında bir etkisi bulunmuyor.

Bu arada program hala gözüme büyük gözüküyor. Neredeyse yazdığım assembly kodu kadar bunu hafızaya girmek için basic kodu var. Daha da kısalır mı, bakalım göreceğiz.

Video demonstrasyonu, kartuştan yükleme aradan çıktığı için belki daha anlaşılır olur yaptığım kafanızda,

uCOyWWKs2yM