Aktualności: C64 Power - online od stycznia 2000 !

Autor Wątek: Koduj w Atalanie - Lekcja 1b - krolikbest edition  (Przeczytany 1052 razy)

0 użytkowników i 2 Gości przegląda ten wątek.

Offline qus

  • Level 3
  • ***
  • Wiadomości: 201
Koduj w Atalanie - Lekcja 1b - krolikbest edition
« dnia: 12 Lutego 2018, 10:03 »
Lekcja 1b

Strzałka ina Irku

Post krolikbesta w innym wątku (program w BASICu ruszający duszkiem pod wpływem joysticka) zainspirował mnie do tej małej wprowadzającej lekcji, która pomoże pokazać w jaki sposób możemy w Atalanie wykorzystać zmienne przyczepione do adresu oraz specjalne procedury do obsługi przerwań. A po ludzku – spróbujemy zrobić strzałkę, która poruszana joystickiem nie blokuje systemu operacyjnego, więc możecie sobie odpalić jakiś program w BASICu, a strzałka będzie sobie nadal hulała, niezależnie od niego. Normalny multitasking!

Oczywiście zamiast programu w BASICu V2 polecam napisanie go w Atalanie…

Etap pierwszy – zamiast PEEK i POKE

Piszący w assemblerze często śmieją się z BASICa, że w nim wszystko robi się przez PEEK i POKE, choć jest dokładnie odwrotnie – to w assemblerze wszystko robi się przez LDA/STA, a zupełnie nie ma w nim IF, THEN, FOR, NEXT, zmiennych, obiektów, funkcji, procedur i tak dalej…

W Atalanie nie ma nawet PEEK i POKE, za to mamy coś dużo lepszego. Zmienne osadzone bezpośrednio w pewnym adresie pamięci. Jak wygląda taka zmienna?
kolorRamki @53280: byte
kolorTla @53281: byte
Powyższe znaczy: „kolorRamki to zmienna o wielkości bajtu znajdująca się pod adresem 53280” i tak dalej. Zmiana koloru ramki jest więc banalna, w naszym programie piszemy po prostu:
kolorRamki = 0
A Atalan skompiluje to do:
LDA #0
STA 53280
No dobrze. To teraz mała zagadka. Co się stanie jeśli napiszemy takie trzy linijki:
kolorRamki = 0
kolorRamki = 0
kolorRamki = 0
Bardzo kiepski kompilator (pewnie zrobiłby tak kompilator BASICa na C64) wyprodukuje taki kod:
LDA #0
STA 53280
LDA #0
STA 53280
LDA #0
STA 53280
Trochę lepszy kompilator zrobi tak:
LDA #0
STA 53280
STA 53280
STA 53280
A co zrobi Atalan? Zrobi to…
LDA #0
STA 53280
Hmmm… Co poszło nie tak? Ano nic. Kompilator Atalana jest na tyle sprytny, że dokładnie wie, że w 53280 jest już wartość 0, więc wpisywanie jej tam ponownie nie ma absolutnie żadnego sensu. Tyle tylko, że tu pojawia się pewien problem, o ile znacie się trochę na programowaniu C64 i jego różnych obszarów I/O… Są bowiem takie komórki w pamięci VICa lub CIA, które służą do sterowania pewnymi funkcjami i robią coś za każdym razem, kiedy wpisujemy do nich jakąś wartość. Nie szkodzi, że ciągle jest to ta sama wartość! Tak więc w Atalanie po pierwszym zapisie takiej komórki, próba wpisania w nią identycznej wartości zostanie najnormalniej w świecie olana! Gdyby nie dało się z tym nic zrobić, byłoby kiepsko, nie? Na szczęście – da się. Trzeba oznaczyć zmienną w specjalny sposób:
out rejestrKontroliPrzerwan@$dc0d:bytePowyższy zapis oznacza: „jeśli wpiszę coś do rejestruKontroliPrzerwań, to masz tam wpisać tę wartość nawet, jeśli jesteś pewien, że jest w nim już identyczna”.

Jest też odwrotna sytuacja – rejestry, w których wartość zmienia się „magicznie” sama za każdym lub prawie każdym razem, kiedy je odczytujemy. Na przykład rejestr joysitcka!
Jeśli zrobilibyśmy więc coś takiego:
Joy1@$dc01 ; adres portu joya
while Joy1 = 0 ; czekamy aż ktoś zrobi coś z joystickiem
To wpadniemy w nieskończoną pętlę, bo Atalan zrobi:
LDA $dc01
loop:
BEQ loop
No bo jest na tyle sprytny, żeby ponownie nie ładować do akumulatora zawartości $dc01! Tyle, że nie o to nam chodziło!
Aby to naprawić, musimy poinformować kompilator, że wartość w danym rejestrze może być zmieniona przez jakieś zewnętrzne działania. Robi się to w ten sposób:
in Joy1@$dc01 ; adres portu joya
Wtedy poprzedni kod skompiluje się do:
loop:
LDA $dc01
BEQ loop
Mam nadzieję, że to jasne? Dla podsumowania:
1)   Dla naszych zmiennych, które zdefiniujemy w programie i które nie są podpięte do żadnych adresów z „mapy pamięci C64” na 99% nie potrzebujemy ani „in” ani „out”.
2)   Dla zmiennych, które są podpięte pod adresy, pod którymi jest jakaś zmieniana przez kernal lub urządzenia zewnętrzne wartość (zegar? porty I/O?) potrzebujemy adnotacji „in”
3)   Dla zmiennych, które są podpięte pod adresy, które są wejściem dla jakichś funkcji hardware’owych potrzebujemy adnotacji out
4)   Możemy i musimy używać adnotacji „in out” dla zmiennych, które robią 2) i 3), jak na przykład $dc0d – komórka do kontroli przerwań (zobaczcie jej opis na mapie pamięci, zrozumiecie, czemu)
5)   Dla adresów hardware’owych, które same są jakby zmiennymi i nic innego poza naszym programem nie będzie do nich pisać, np. pozycje duszków, nie potrzebujemy „in” ani „out”
« Ostatnia zmiana: 12 Lutego 2018, 10:18 wysłana przez Vato74 »



Offline qus

  • Level 3
  • ***
  • Wiadomości: 201
Re: Koduj w Atalanie - Lekcja 1b - krolikbest edition
« Odpowiedź #1 dnia: 12 Lutego 2018, 10:08 »
Etap 2: uroki języka wysokiego poziomu

kolorRamki = 0
to całkiem fajny sposób na zmianę koloru, ale czy każdy z Was pamięta, pod jakim numerkiem jest purpura, a pod jakim cyjanowy? (Wiem, że jest ich tylko 16, ale czy koniecznie muszę znać ich numerki na pamięć?!) Utwórzmy sobie więc nowy typ zmiennej: Kolor
type Color: enum
 black
 white
 red
 cyan
 purple
 green
 blue
 yellow
 orange
 brown
 lightred
 darkgrey
 grey
 lightgreen
 lightblue
 lightgrey
A definicje zmiennych przepiszmy tak:
borderColor @$d020:Color
backgroundColor @$d021:Color
Teraz w naszym programie możemy napisać:
borderColor = Color.lightgreen
backgroundColor = Color.brown
Czytelniej niż cyferki! A o czytelność nam chodzi, gdyby nie czytelność, programowalibyśmy w assemblerze, prawda? Enumy mogą mieć też dowolne wartości, niekoniecznie od 0 do x:
Joystick: enum
 up : 1
 down : 2
 left : 4
 right : 8
 fire : 16
Aby potem móc na przykład:
If Joy1 = Joystick.fire then otworzRamke
Tu od razu nadmienię, że nie musicie powyższych pisać w swoich programach, bo są już częścią biblioteki C64, która znajduje się w pliku platform/c64/c64.atl. Zachęcam do jego rozwijania o przydatne adresy i funkcje!

W tymże pliku są na przykład napoczęte implementacje funkcji do robienia rzeczy z duszkami. Jest tam zdefiniowany pojemniczek („scope”) o nazwie vic, który grupuje różne funkcje układu graficznego. Jest tam na przykład makro setSpriteX numerSpirte’a pozycjaX. Więc w Waszym kodzie, aby ustawić gdzieś duszka wystarczy zrobić:
vic.setSpriteX 0 300
a macro setSpriteX zajmie się już ustawieniem właściwej wartości w bajcie i bicie, które są do tego potrzebne. Nie mówię, że zrobi to w optymalny sposób, ale nic nie stoi na przeszkodzie, aby napisać bardziej wydajne funkcje. Obecna wygląda tak:
setSpriteX:macro sprite:Sprite,x:int =
if x > 255 then spritesHX$sprite = 1 else spritesXH$sprite = 0
ind = sprite*2  
vic.spritePos#ind = lo x
linia „if” ustawia najstarszy bit pozycji, jeśli x jest większe od 255 (zapis zmienna$n oznacza „n-ty bit zmiennej, spritesHX to $d010)

ostatnia linia ustawia odpowiednią komórkę z pozycją na młodszy bajt wartości x (zapis tablica#n oznacza „odwołaj się to n-tego elementu tablicy”, ponieważ zmienna spritePos zdefiniowana jest po prostu jako tablica 16 wartości byte pod adresem $D000, tak więc pozycja X drugiego duszka to vic.spritePos#4, a pozycja Y trzeciego - vic.spritePos#7)

Jeśli ktoś uważa, że kod mnożący zmienną ind przez dwa jest za wolny, nic nie stoi na przeszkodzie, aby w scope vic zdefiniować sobie oddzielne funkcje dla każdego duszka, wstawiające wartości bezpośrednio w ich adresy, bez żadnych przeliczeń. Oczywiście, jeśli operujemy duszkiem 0, żadne mnożenia nie pojawią się w wynikowym assemblerze, nawet przy obecnym kodzie!

W VIC-u zdefiniowałem też parę funkcji do przesuwania duchów o piksel:
spriteRight:macro sprite:Sprite =
ind = sprite*2
inc vic.spritePos#ind
Przydadzą się nam do właściwego kodu, w którym duszek reaguje na joystick!

(ciąg dalszy w trakcie tworzenia)
« Ostatnia zmiana: 12 Lutego 2018, 10:21 wysłana przez qus »

Offline qus

  • Level 3
  • ***
  • Wiadomości: 201
Re: Koduj w Atalanie - Lekcja 1b - krolikbest edition
« Odpowiedź #2 dnia: 12 Lutego 2018, 10:15 »
Moderatora proszę o zmianę BNE na BEQ w pierwszym poście!

Done

Przy okazji - w makro spriteRight jest oczywiście błąd, bo duszek nie pójdzie dalej niż 255! Proponuję jako ćwiczenie - poprawić to makro samodzielnie.
« Ostatnia zmiana: 12 Lutego 2018, 10:27 wysłana przez qus »

Offline qus

  • Level 3
  • ***
  • Wiadomości: 201
Re: Koduj w Atalanie - Lekcja 1b - krolikbest edition
« Odpowiedź #3 dnia: 12 Lutego 2018, 10:42 »
A mały disklajmer – ponieważ obecnie nie jest łatwo zrobić działający PRG dla C64, jeśli trochę nie znacie się na assemblowaniu, linkowaniu i dodawaniu nagłówków, postaram się w pierwszej kolejności usprawnić cały proces kompilacji programu w Atalanie tak, aby było to zupełnie bezbolesne. Rach – ciach i macie PRG, który można przerzucić na kompa albo emulator i odpalić.

Offline qus

  • Level 3
  • ***
  • Wiadomości: 201
Re: Koduj w Atalanie - Lekcja 1b - krolikbest edition
« Odpowiedź #4 dnia: 12 Lutego 2018, 11:14 »
Etap trzeci – zróbmy se multitasking

Mamy teraz wielordzeniowe procesory, więc nikogo raczej nie dziwi, że możemy na raz ściągać torrenta, oglądać RedTube i kopać bitcoiny. To łatwe! Przecież każdy rdzeń może robić coś innego. Ale czy ktoś pamięta jeszcze, że nawet jednordzeniowe komputery to potrafiły? Jak to robiły?

Oczywiście – oszukiwały. Na tym samym procku małą chwilkę ściągały torrenta, potem małą chwilkę RedTube, potem małą chwilkę bitcoiny i małą chwilkę poświęcały na system operacyjny. C64 oczywiście też tak potrafi, taki na przykład pico]OS (https://github.com/AriZuu/picoos ) może wykonywać 64 taski na raz na 6510! Myślicie, że to trudne? Nie za bardzo, jeśli tylko wiecie, jak zmusić właśnie wykonywany program to tego, żeby oddał procesor kolejnemu programowi! Tylko jak, u licha, przerwać właśnie wykonywany program?

No właśnie – przerwaniem!

Nogi 6510 przywiązane są do różnych innych układów (VIC, CIA itd.), jeśli taki układ pociągnie 6510 za nogę, następuje PRZERWANIE, to znaczy, że MOS (o ile nie nakazaliśmy mu olewać nadchodzących przerwań, podnosząc specjalną flagę) musi przestać robić cokolwiek, co w tej chwili robił i skoczyć do procedury obsługi przerwania. Jeśli więc znaleźlibyśmy układ, który ciągnie 6510 za nogę x razy na sekundę, moglibyśmy tyleż razy na sekundę wtrącać się w cokolwiek, co właśnie się dzieje i robić po kawałeczku innego programu! Ot, cały multitasking! I tak się szczęśliwie składa, że jeden z zegarów w CIA w regularnych odstępach wywołuje przerwanie, o ile go o to poprosimy. Zdaje się, że jest to 50 razy na sekundę, ale nie mam pewności, pytajcie sajmosi, jest ekspertem od timingów!

No i gdybyśmy programowali w assemblerze, tu by następowała cała masa nudnych szczegółów, takich jak wyłączanie przerwań na czas przesuwania wektorów, wyłączanie tego, włączanie śmiego, jakieś tam zapisywanie kontekstów, żeby je potem odczytać – jednym słowem cała masa zbędnej wiedzy, która nas zupełnie nie interesuje, ponieważ w pliku c64.atl stworzyłem już dla Was nowy typ funkcji, który całą tę ohydę w Atalanie chowa przed Waszymi oczami (ale w assemblerze robi co trzeba). Jedyne, co musicie zrobić, to napisać zamiast „procedury” i „irqProcedurę” i aktywować ją poleceniem, mniej więcej tak:

enableIrqProc przesuwanieStrzalkiJoystickiem
Co spowoduje, że utworzy się niejako drugi wątek Waszego programu, wykonujący się x razy na sekundę. Tu od razu uwaga – cokolwiek umieścicie w procedurze przesuwanieStrzalki musi oczywiście jak najszybciej się wykonać i zakończyć, bo inaczej nasz multitasking będzie bardziej przypominał Windows niż Amigę! A jeśli przyjdzie Wam do głowy zrobić w irqProcedurze nieskończoną pętlę, to niestety już po multitaskingu, ponieważ w trakcie wykonywania procedury obsługi przerwania nie otrzymamy nowych przerwań, więc pozostaniemy w niej na zawsze!

W kolejnym etapie postaramy się zebrać to wszystko do kupy, pisząc program, który pozwala poruszać strzałką za pomocą joysticka, niezależnie od programu w BASICu (albo Atalanie…)
« Ostatnia zmiana: 12 Lutego 2018, 11:17 wysłana przez qus »

Offline qus

  • Level 3
  • ***
  • Wiadomości: 201
Re: Koduj w Atalanie - Lekcja 1b - krolikbest edition
« Odpowiedź #5 dnia: 12 Lutego 2018, 18:40 »
W katalogu examples na atalonowym gicie jest przykład do dzisiejszej lekcji - do przetestowania dla zaawansowanych. Póki co nie działa tworzenie duszka za pomocą tablicy.

I mała korekta - trzeba jednak dodawać in/out do wszystkich adresów, które coś robią, takich jak np. pozycje X i Y duszków. Z resztą zobaczcie w źródłach.

Offline qus

  • Level 3
  • ***
  • Wiadomości: 201
Re: Koduj w Atalanie - Lekcja 1b - krolikbest edition
« Odpowiedź #6 dnia: 13 Lutego 2018, 10:40 »
Poniżej kod na suwanie duszkiem na przerwaniach. Aby działał na 100% trzeba jeszcze w bibliotece c64.atl poprawić makra do poruszania w poziomie.

Ponieważ Atalan jest językiem niedokończonym, dość często trzeba rzucać okiem na wynikowy Assembler i patrzeć, czy za bardzo nie nakombinował. Poniższy kod jest efektem takiego patrzenia - daje dość ładny program w assemblerze. Niestety, póki co nie da się osiągnąć takiego efektu pisząc byle co.

Aby uzyskać gotowy prg umieśćcie w katalogu, w którym będziecie kompilować plik c64.cfg (konfiguracja linkera) i odpalcie kompiltor atalana tak:

atalan -p c64 nazwa_źródła.atl
Możecie dorzucić opcję -v aby zobaczyć, co się tam dokładnie dzieje.

Jeśli wynikowy prg nie będzie działał, to trzeba by zobaczyć, co jest nie tak w konfiguracji linkera, bo to ona przysparza mi najwięcej kłopotów.

A i sorry, że funkcje nazywają się już inaczej niż w tutorialu powyżej, ale stale mi się nie podobają ich nazwy, więc są dość płynne...

A i jeszcze - nie pamiętam, czy sprawdzałem, czy obsłużenie przerwania jest potwierdzone pod koniec procedury. Jeśli nie - naprawię to wkrótce.

; przykladowy duszek to tablica 63 wartosci pod adresem 2049
const exampleGhost:array =
%10000000,%00000000,%00000000,
%11000000,%00000000,%00000000,
%11100000,%00000000,%00000000,
%11110000,%00000000,%00000000,
%11111000,%00000000,%00000000,
%11111100,%00000000,%00000000,
%00111000,%00000000,%00000000,
%00111000,%00000000,%00000000,
%00011100,%00000000,%00000000,
%00011100,%00000000,%00000000,
%00000000,%00000000,%00000000,
%00000000,%00000000,%00000000,
%00000000,%00000000,%00000000,
%00000000,%00000000,%00000000,
%00000000,%00000000,%00000000,
%00000000,%00000000,%00000000,
%00000000,%00000000,%00000000,
%00000000,%00000000,%00000000,
%00000000,%00000000,%00000000,
%00000000,%00000000,%00000000,
%00000000,%00000000,%00000000,

; wkazniki duszkow przy ekranie domyslnym sa pod adresem 2040
in out spritePtr@2040:array(8) of byte

; duszek 0 jest pod adresem 2049, ustawmy jego wskaznik na ten adres
spritePtr#0 = 2049/64

; ustawiamy wspolrzedne poczatkowe
;Vic.setSprite0X 100
Vic.setSprite0Y 100

; wlaczamy go
Vic.setSpriteVisible 0 true

; procedura typu IrqProc, jedyny typ procedury wspolpracujacy z makrem onIrqDo
ruchacz : IrqProc =
; w gore i w dol raczej na raz sie nie da! Przesunmy duszka w gore lub w dol
; sprawdzamy po prostu, czy bit odpowiadajacy wychyleniom jest zapalony
if Cia1.portB$0 = 1 then Vic.sprite1Y = Vic.sprite1Y - 1
else if Cia1.portB$1 =1 then Vic.sprite1Y = Vic.sprite1Y + 1

; w prawo i lewo tez...
if Cia1.portB$2 = 1then Vic.sprite1X = Vic.sprite1X -1
else if Cia1.portB$3 = 1 then Vic.sprite1X = Vic.sprite1X + 1
return

; odpalamy nasz multitasking
onIrqDo ruchacz
« Ostatnia zmiana: 13 Lutego 2018, 10:50 wysłana przez qus »

Offline hobocti77x

  • Level 5
  • *****
  • Wiadomości: 731
Re: Koduj w Atalanie - Lekcja 1b - krolikbest edition
« Odpowiedź #7 dnia: 14 Lutego 2018, 14:51 »
Skompilowalem pod minGW. Probuje z pomoca atalana skompilowac plik przyklad.atl i i po chwili  otrzymuje komunikat: No target platform defined.

Offline qus

  • Level 3
  • ***
  • Wiadomości: 201
Re: Koduj w Atalanie - Lekcja 1b - krolikbest edition
« Odpowiedź #8 dnia: 14 Lutego 2018, 15:23 »
a dałeś "-t c64"? I masz gdzieś w ścieżce platform/c64.*?

Offline hobocti77x

  • Level 5
  • *****
  • Wiadomości: 731
Re: Koduj w Atalanie - Lekcja 1b - krolikbest edition
« Odpowiedź #9 dnia: 14 Lutego 2018, 15:34 »
a dałeś "-t c64"? I masz gdzieś w ścieżce platform/c64.*?
Chyba "-p 64"  ;)
Daje atalan -p c64 przyklad pliki c64.* z katalogu .../platform mam w  tym samym katalogu co atalan.exe wiec ma do nich dostep.

Offline qus

  • Level 3
  • ***
  • Wiadomości: 201
Re: Koduj w Atalanie - Lekcja 1b - krolikbest edition
« Odpowiedź #10 dnia: 14 Lutego 2018, 16:20 »
Aj, no słusznie!

Na początku programu musi być

use c64

Offline hobocti77x

  • Level 5
  • *****
  • Wiadomości: 731
Re: Koduj w Atalanie - Lekcja 1b - krolikbest edition
« Odpowiedź #11 dnia: 14 Lutego 2018, 16:52 »
Dodalem na poczatku pliku use c64 , ale to niczego nie zmienilo.
Napisalem tez taki plik, efekt jest ten sam.
Co ciekawe uzylem tez programu skompilowanego przez urzytkownika malik_cjm atalan_32bit.exe i efekt jest ten sam.  >:(
No moze z wyjatkiem ze u mnie komunikat o bledzie jest w kolorze czerwonym.  :o
i generuje sie plik bledu
« Ostatnia zmiana: 14 Lutego 2018, 16:56 wysłana przez hobocti77x »

Offline qus

  • Level 3
  • ***
  • Wiadomości: 201
Re: Koduj w Atalanie - Lekcja 1b - krolikbest edition
« Odpowiedź #12 dnia: 14 Lutego 2018, 19:26 »
OK, -p c64 zastęuje "use c64", więc to nie rzutuje... Co nie znaczy, że wiem, na czym polega problem. Naprawdę nie masz jakiegoś linucha pod ręka?

Offline hobocti77x

  • Level 5
  • *****
  • Wiadomości: 731
Re: Koduj w Atalanie - Lekcja 1b - krolikbest edition
« Odpowiedź #13 dnia: 14 Lutego 2018, 20:04 »
OK, -p c64 zastęuje "use c64", więc to nie rzutuje... Co nie znaczy, że wiem, na czym polega problem. Naprawdę nie masz jakiegoś linucha pod ręka?
Problem w tym ze aktualnie nie mam. Ale mysle ze problem jest gdzies w kodzie ustawienia opcji dla kompilatora windows.
Jesli  program mialby byc urzywany przez innych ( a mysle ze warto ) to jednak wersja windows powinna dzialac, bylo nie bylo jest to chyba najpopularniejszy system wsrod tutejszych urzytkownikow.
Przeslij mi moze liste plikow ktore powinny powstac po kompilacji, moze nie wszystko sie kompiluje pod windows ?
No i podpowiadam ze powinien byc przynajmniej opis sposobu kompilacji, w koncu nie wszyscy sa informatykami, a juz najlepiej jakby byla gdzies dzialajaca i przetestowana wersja skompilowana.
Moze zamiesc jakis plik atl o ktorym bedzie wiadomo ze dziala aby sprawdzic kompilator atalana ?


Offline KB777

  • Level 6
  • ******
  • Wiadomości: 2430
  • -profil nieaktywny-
Re: Koduj w Atalanie - Lekcja 1b - krolikbest edition
« Odpowiedź #14 dnia: 14 Lutego 2018, 20:14 »
 Urzytkownicy nie umiom urzywac linuxa,
Sodomia i gomoria.

VirtualBox lub VMware Player - i można pod Windą mieć dowolną dystrybucję. Ubuntu jest tak cukierkowe, że Windziarze będą się czuli jak w domu.
-profil nieaktywny-