Notery cz. 2

Jak wspominałem w części poprzedniej aby było możliwe odczytanie notatki, potrzebny jest program (który jest integralną częścią każdej gotowej notki) który wyświetli ją w odpowiedni sposób na ekranie. Poniżej prezentuję asemblerowy kod takiego programu (otrzymuje się go przez komendę d810 w monitorze – czyli desasembluj kod od adresu – w tym przypadku – $0810). Zakładam też znajomość podstawowych komend asemblera – jeśli ich nie znasz, to polecam odpowiednie artykuły na C64 Power.

Co jeszcze jest ważne?

– muzyka znajduje się w bloku $1000 – $2000 ($1000 INIT, $1003 PLAY)

– tekst notatki znajduje się w pamięci począwszy od $2800; jedna strona to $1e0 znaków czyli w dziesiętnym 480 znaków, adres początku kolejnej strony to $2800 + (n-1)*$1e0 (n-numer strony).

Od $0a0c zapisane są kolory dla efektu znikania tekstu, od $0a1d kolory dla efektu pojawiania się tekstu

Jeśli nie wierzysz, sprawdź!

2. Kod.

(komentarze odnoszą się do bloku kodu powyżej)

 

.C:0810   20 81 FF   JSR $FF81
.C:0813 20 8A FF JSR $FF8A
.C:0816 20 84 FF JSR $FF84

skok do funkcji kernala – inicjacja urządzeń i wektorów

 

.C:0819   A9 2E      LDA #$2E
.C:081b 8D 18 03 STA $0318
.C:081e A9 0A LDA #$0A
.C:0820 8D 19 03 STA $0319

ustawiany jest wektor dla przerwania niemaskowalnego na adres $0A2E
$0A i $2E w komórkach $0319 (starszy) i $0318 (mlodszy) bajt

 

.C:0823   A9 18      LDA #$18
.C:0825 8D 18 D0 STA $D018

ustawiany rejestr VIC (układ odpowiadający za grafikę)

 

.C:0828   A9 00      LDA #$00
.C:082a 8D 30 0A STA $0A30

do komórki pamięci $0a30 wpisywana jest wartość $00

 

.C:082d   A9 00      LDA #$00
.C:082f 85 04 STA $04
.C:0831 A9 28 LDA #$28
.C:0833 85 05 STA $05

w komórkach $05, $04 ustawiany jest adres $2800 – czyli pierwszej strony z tekstem!

 

.C:0835   A2 00      LDX #$00
.C:0837 8E 20 D0 STX $D020
.C:083a 8E 21 D0 STX $D021

czarny kolor tła i ramki ekranu

 

.C:083d   8A         TXA
.C:083e 9D 00 D8 STA $D800,X
.C:0841 9D 00 D9 STA $D900,X
.C:0844 9D 00 DA STA $DA00,X
.C:0847 9D 00 DB STA $DB00,X
.C:084a E8 INX
.C:084b D0 F1 BNE $083E

pętla wypełniająca pamięć kolorów od $d800 do $dbff

 

.C:084d   20 DC 09   JSR $09DC

skok do podprogramu

 

.C:0850   78         SEI
.C:0851 A2 00 LDX #$00
.C:0853 8E 0E DC STX $DC0E

ustawienie rejestru CIA

 

.C:0856   86 C6      STX $C6
.C:0858 E8 INX
.C:0859 8E 32 0A STX $0A32
.C:085c 8E 1A D0 STX $D01A

.C:085f A9 1B LDA #$1B
.C:0861 8D 12 D0 STA $D012
.C:0864 8D 11 D0 STA $D011

ustawienie rejestrów VIC

 

.C:0867   A9 7E      LDA #$7E
.C:0869 8D 14 03 STA $0314
.C:086c A9 09 LDA #$09
.C:086e 8D 15 03 STA $0315

ustawienie wektora dla procedury przerwań IRQ na adres $097E – to główna „pętla” programu odpowiadająca za odtwarzanie muzyki, oczekiwanie na naciśnięcie klawisza

 

.C:0871   58         CLI
.C:0872 20 26 09 JSR $0926
.C:0875 20 C5 08 JSR $08C5

skoki do podprogramów

 

->.C:0878   AD 01 DC   LDA $DC01
.C:087b C9 7F CMP #$7F
.C:087d D0 03 BNE $0882

skok niżej, jeżeli zmiana strony

 

.C:087f   4C D1 09   JMP $09D1

skok do podprogramu – tam krótkie działanie i powrót do $0878

 

.C:0882   29 10      AND #$10
.C:0884 D0 F2 BNE $0878

.C:0886 20 92 08 JSR $0892
.C:0889 20 F8 08 JSR $08F8
.C:088c 20 C5 08 JSR $08C5
.C:088f 4C 78 08 JMP $0878

tu program się zapętla – wszędzie odbywają się skoki do $0878

*** podprogram ***
tu realizowany jest efekt znikania tekstu

 

.C:0892   A2 00      LDX #$00
.C:0894 A9 F8 LDA #$F8
.C:0896 CD 12 D0 CMP $D012
.C:0899 D0 FB BNE $0896

oczekuj, aż równe

 

.C:089b   BD 0C 0A   LDA $0A0C,X
.C:089e 30 24 BMI $08C4

powrót z podprogramu

 

.C:08a0   8D 21 D0   STA $D021
.C:08a3 8D 27 D0 STA $D027
.C:08a6 8D 28 D0 STA $D028
.C:08a9 8D 29 D0 STA $D029
.C:08ac 8D 2A D0 STA $D02A
.C:08af 8D 2B D0 STA $D02B
.C:08b2 8D 2C D0 STA $D02C
.C:08b5 8D 2D D0 STA $D02D
.C:08b8 8D 2E D0 STA $D02E

zmiana kolorów sprite’ów

 

.C:08bb   A0 32      LDY #$32
.C:08bd 88 DEY
.C:08be D0 FD BNE $08BD
.C:08c0 E8 INX
.C:08c1 4C 94 08 JMP $0894

tu podprogram się zapętla

 

.C:08c4   60         RTS

*** koniec podprogramu ***

*** podprogram ***
tu realizowany jest efekt pojawiania sie tekstu

 

.C:08c5   A2 00      LDX #$00
.C:08c7 A9 F8 LDA #$F8
.C:08c9 CD 12 D0 CMP $D012
.C:08cc D0 FB BNE $08C9

skok do $08c9 jezeli nie równe – czekaj, aż równe

 

.C:08ce   BD 1D 0A   LDA $0A1D,X
.C:08d1 30 24 BMI $08F7

skocz na koniec podprogramu

 

.C:08d3   8D 21 D0   STA $D021
.C:08d6 8D 27 D0 STA $D027
.C:08d9 8D 28 D0 STA $D028
.C:08dc 8D 29 D0 STA $D029
.C:08df 8D 2A D0 STA $D02A
.C:08e2 8D 2B D0 STA $D02B
.C:08e5 8D 2C D0 STA $D02C
.C:08e8 8D 2D D0 STA $D02D
.C:08eb 8D 2E D0 STA $D02E

ustawia kolory 8 sprite’ów w VIC

 

.C:08ee   A0 32      LDY #$32
.C:08f0 88 DEY
.C:08f1 D0 FD BNE $08F0

oczekuj, az równe

 

.C:08f3   E8         INX
.C:08f4 4C C7 08 JMP $08C7

zapętla podprogram – jedyne wyjście w $08d1

 

.C:08f7   60         RTS

*** koniec podprogramu ***

*** podprogram ***
zmiana wyswietlanej strony

 

.C:08f8   AD 30 0A   LDA $0A30
.C:08fb 18 CLC
.C:08fc 69 01 ADC #$01
.C:08fe 8D 30 0A STA $0A30
.C:0901 CD 2F 0A CMP $0A2F
.C:0904 D0 10 BNE $0916

jesli nie równe, skok niżej

 

.C:0906   A9 00      LDA #$00
.C:0908 85 04 STA $04
.C:090a A9 28 LDA #$28
.C:090c 85 05 STA $05

do $04 – $05 wpisany adres $2800

 

.C:090e   A9 00      LDA #$00
.C:0910 8D 30 0A STA $0A30
.C:0913 4C 26 09 JMP $0926

skok do podprogramu wyświetlającego tekst

 

.C:0916   A5 04      LDA $04
.C:0918 18 CLC
.C:0919 69 E0 ADC #$E0
.C:091b 85 04 STA $04
.C:091d A5 05 LDA $05
.C:091f 69 01 ADC #$01
.C:0921 85 05 STA $05

jeżeli ma wyświetlić kolejną stronę – zwiększa odpowiednio adresy, skąd pobierany jest tekst i niżej skok do procedury wyświetlania

 

.C:0923   4C 26 09   JMP $0926

*** koniec podprogramu ***

*** podprogram ***
wyświetlanie tekstu

 

.C:0926   A9 00      LDA #$00
.C:0928 85 02 STA $02
.C:092a A9 04 LDA #$04
.C:092c 85 03 STA $03
.C:092e A9 28 LDA #$28
.C:0930 85 06 STA $06
.C:0932 A9 04 LDA #$04
.C:0934 85 07 STA $07

w $02 – $03 zapisany zostaje adres $0400 (początek pamięci ekranu) w $06 – $07 zapisany zostaje adres $0428 (początek pamięci ekranu + $28 czyli 40 dziesiętnie, czyli jedna linia tekstu na ekranie 🙂

 

.C:0936   A5 04      LDA $04
.C:0938 48 PHA
.C:0939 A5 05 LDA $05
.C:093b 48 PHA

adres z $04 – $05 zostaje zapisany na stos

 

   .C:093c   A2 00      LDX #$00
|->.C:093e A0 00 LDY #$00
|
| zerowanie rejestrów x i y
|
| |->.C:0940 B1 04 LDA ($04),Y
| | .C:0942 91 02 STA ($02),Y
| | .C:0944 09 80 ORA #$80
| | .C:0946 91 06 STA ($06),Y
| | .C:0948 C8 INY
| | .C:0949 C0 28 CPY #$28
| |->.C:094b D0 F3 BNE $0940

pętla, wczytywanie znaków z pierwszej strony notki

 

   .C:094d   A5 04      LDA $04
.C:094f 18 CLC
.C:0950 69 28 ADC #$28
.C:0952 85 04 STA $04
.C:0954 A5 05 LDA $05
.C:0956 69 00 ADC #$00
.C:0958 85 05 STA $05
.C:095a A5 02 LDA $02
.C:095c 69 50 ADC #$50
.C:095e 85 02 STA $02
.C:0960 A5 03 LDA $03
.C:0962 69 00 ADC #$00
.C:0964 85 03 STA $03
.C:0966 A5 06 LDA $06
.C:0968 69 50 ADC #$50
.C:096a 85 06 STA $06
.C:096c A5 07 LDA $07
.C:096e 69 00 ADC #$00
| .C:0970 85 07 STA $07
| .C:0972 E8 INX
| .C:0973 E0 0C CPX #$0C
|->.C:0975 D0 C7 BNE $093E

kolejna pętla, kolejne operacje na ekranie..

 

.C:0977   68         PLA
.C:0978 85 05 STA $05
.C:097a 68 PLA
.C:097b 85 04 STA $04

przywrócenie poprzednich wartości do $04 – $05 (ze stosu)

 

.C:097d   60         RTS

*** koniec podprogramu ***

*** obsługa przerwania ***

 

.C:097e   A9 18      LDA #$18
.C:0980 8D 18 D0 STA $D018

ustawienie rejestru VIC

 

.C:0983   AD 32 0A   LDA $0A32
.C:0986 F0 43 BEQ $09CB

 

.C:0988   A5 FB      LDA $FB
.C:098a 48 PHA
.C:098b A5 FC LDA $FC
.C:098d 48 PHA
.C:098e A5 FD LDA $FD
.C:0990 48 PHA
.C:0991 A5 FE LDA $FE
.C:0993 48 PHA

zapis wartości powyższych komórek pamięci na stos

 

.C:0994   AD 34 0A   LDA $0A34
.C:0997 85 FB STA $FB
.C:0999 AD 33 0A LDA $0A33
.C:099c 85 FC STA $FC
.C:099e AD 35 0A LDA $0A35
.C:09a1 85 FD STA $FD
.C:09a3 AD 36 0A LDA $0A36
.C:09a6 85 FE STA $FE

wpisanie nowych wartości z pamięci

 

.C:09a8   20 03 10   JSR $1003

odgrywaj muzykę

 

.C:09ab   A5 FB      LDA $FB
.C:09ad 8D 34 0A STA $0A34
.C:09b0 A5 FC LDA $FC
.C:09b2 8D 33 0A STA $0A33
.C:09b5 A5 FD LDA $FD
.C:09b7 8D 35 0A STA $0A35
.C:09ba A5 FE LDA $FE
.C:09bc 8D 36 0A STA $0A36

zapis do pamięci (to, co wyżej, tylko w drugą stronę)

 

.C:09bf   68         PLA
.C:09c0 85 FE STA $FE
.C:09c2 68 PLA
.C:09c3 85 FD STA $FD
.C:09c5 68 PLA
.C:09c6 85 FC STA $FC
.C:09c8 68 PLA
.C:09c9 85 FB STA $FB

przywrócenie poprzednich wartości komórek ze stosu

 

.C:09cb   EE 19 D0   INC $D019

.C:09ce 4C 31 EA JMP $EA31

standardowa obsługa przerwania

*** koniec obsługi przerwania ***

*** podprogram ***

 

.C:09d1   AD 31 0A   LDA $0A31
.C:09d4 D0 03 BNE $09D9
.C:09d6 4C 00 8D JMP $8D00

.C:09d9 4C 78 08 JMP $0878

*** koniec podprogramu ***

*** podprogram ***
ustawienia muzyki

 

.C:09dc   78         SEI
.C:09dd A9 00 LDA #$00
.C:09df 8D 32 0A STA $0A32

wstawia $00 do $0a32

 

.C:09e2   AD 39 0A   LDA $0A39
.C:09e5 8D A9 09 STA $09A9
.C:09e8 8D 10 9C STA $9C10
.C:09eb AD 3A 0A LDA $0A3A
.C:09ee 8D AA 09 STA $09AA
.C:09f1 8D 11 9C STA $9C11

.C:09f4 AD 37 0A LDA $0A37
.C:09f7 8D 03 0A STA $0A03
.C:09fa AD 38 0A LDA $0A38
.C:09fd 8D 04 0A STA $0A04
.C:0a00 A9 00 LDA #$00

Ustawia w programie adresy Init i Play dla muzyki – te adresy mogą być zmieniane i w notce są zapisane w komórkach pamięci:
$0a37 – $0a38 Init
$0a39 – $0a3a Play
Adres w ponizszym rozkazie jest modyfikowany w poprzednich dwóch liniach właśnie na podstawie tych zapisanych danych.

 

.C:0a02   20 00 10   JSR $1000

inicjacja muzyki

 

.C:0a05   A9 01      LDA #$01
.C:0a07 8D 32 0A STA $0A32
.C:0a0a 58 CLI
.C:0a0b 60 RTS

** koniec podprogramu **

Jeżeli nie rozumiesz wszystkiego – eksperymentuj! Zachęcam do zmian – np. sprawdzenia, co się stanie (co przestanie działać 😉 po zastąpieniu skoku do jakiegoś podprogramu instrukcjami NOP (nie rób nic). Ten kod naprawdę nie jest taki trudny!

Notery cz. 1

1. Co to właściwie jest noter?
Mam nadzieję, że każdy choć raz zetknął się z takim programikiem (jeśli nie, można je ściągnąć z działu Download na C64 Power). Noter, to ogólnie rzecz biorąc program służący do zapisywania tekstów (notatek). To wersja minimum, ale każdy szanujący się noter zawiera ponadto: własną czcionkę (a nie standardowego fonta z Commodore), muzykę, która towarzyszy nam podczas pisania tekstu i jego odczytywaniu, różnego rodzaju efekty np. tekst na migającym tle lub wręcz sam migający tekst, efekty przejścia pomiędzy kolejnymi stronami, chociażby fade-in i fade-out. To wszystko zależało od inwencji i zdolności autora notera. Te bardziej rozbudowane posiadały funkcje ułatwiające edycję tekstu: justowanie, wyrównywanie, wstawianie dodatkowych linii, kasowanie całych linii, itp. Możliwa była też (prawie) dowolna konfiguracja sposobu wyświetlania finalnej notki: zmiana koloru tła, ramki, liter, efektów przejścia pomiędzy kolejnymi stronami, muzyki, czcionki (jest nawet taki noter, w którym tekst jest wyświetlany w pionie, a nie w poziomie 🙂 Oczywiście nie można zapomnieć o podstawowej opcji – a mianowicie o możliwości zapisania tekstu w postaci programu, którego uruchomienie pozwala przeczytać notkę. Polecam ściągnięcie kilku noterów i „pobawienie” się z nimi. Prawie każdy zawiera jakieś ciekawe rozwiązania. W tym arcie zajmiemy się jednym z nich – adv_bonzai_ntmkr.zip.

2. Jak to wygląda?
Ściągnij i odpal powyższy plik. Najpierw zobaczysz intro, a potem główne menu notera. Nie będę opisywał wszystkich jego opcji, ponieważ intuicyjnie można się domyślić, co one robią (np. EDIT NOTE – to chyba wiadomo 🙂 Polecam zapoznać się z instrukcjami. Znajdują się tam opisy przydatnych podczas edycji klawiszy. TEST NOTE – jak sama nazwa wskazuje – pozwala na przetestowanie notki przed jej zapisaniem, dokładnie tak będzie ona ostatecznie wyglądać.
Ten noter daje nam dwie możliwości ingerowania w sposób prezentacji tekstu. Pierwsza – zmiana muzyki. Jeśli mamy muzykę zapisaną na dyskietce commodorowskiej, to po prostu ją wczytujemy. Emulator daje nam drugą możliwość zmiany muzyki – jeśli zgramy ją z innego demka do pliku, to potem możemy wczytać zawartość tego pliku (w monitorze) do pamięci komendą load „filename” [adres_startowy]. INIT muzyki powinien być na $1000, PLAY na $1003. Drugą możliwością jest zmiana efektu przejścia (EDIT COLOURS). Zmiana strony wygląda następująco: litery są wygaszane do koloru tła (czarny) a następnie pojawiają się nowe – z charakterystycznym błyskiem. Cały pomysł polega na tym, że przy wygaszaniu litery kolejno (w bardzo krótkim czasie) zmieniają swój kolor aż do czarnego, przy pojawianiu się jest podobnie, tylko końcowym kolorem jest szary. Sprawdź jak to wygląda w zwolnionym tempie (w emulatorze Options / Maximum Speed ustaw na 10%.

3. Mam już notatkę, ale co dalej?
W takim razie najwyższy czas, żeby ją zapisać. Służy do tego (a jakżeby inaczej 🙂 pozycja w menu o nazwie SAVE FINAL NOTE. W emulatorze należy teraz umieścić pustą dyskietkę w wirtualnym napędzie nr 8. File / Attach disk image / Drive 8/, podać nową nazwę i wcisnąć przycisk Create image. Mamy już dyskietkę, teraz w noterze wystarczy podać nazwę pliku. Przed naciśnięciem entera upewnij się, że w emulatorze Options / True drive emulation jest zaznaczone. Gotowe.

4. Jak wygląda notka?
Odpal dopiero co stworzoną notatkę. I co? Nie uruchomiło się? Notka składa się z programu, który wyświetla tekst (umożliwia zobaczenie kolejnych stron, odtwarza muzykę) i bloku z danymi (wygląd czcionki, muzyka oraz sama treść notki). Aby ją zobaczyć, należy uruchomić ten program. W tym konkretnym noterze wystarczy polecenie g810 w monitorze, albo SYS 2064 z Basic’a.

 

Intro od środka cz.3

W poprzednich odcinkach mówiliśmy o tym, jakich zmian można dokonać w przykładowym intrze. Dziś o tym,  jak zapisać intro w formacie *.d64 (inaczej mówiąc – na dyskietce Commodore) – a w związku z tym o programach w Basicu i asemblerze, relokatorze i kilku innych rzeczach…

1. Niezbędne podstawy, czyli dla nie wtajemniczonych…
Wyobraź sobie, że nie masz przed sobą peceta. Jest tylko Commodore i podłączona do niego stacja dysków z czystą dyskietką. W pamięci znajduje się nasze zmienione intro. I to jest zadanie na dziś – zapisać intro na dyskietce w ten sposób, aby po załadowaniu samo się uruchamiało. Dygresja: oczywiście nadal korzystać będziemy z emulatora. Najpierw zrobimy sobie czystą dyskietkę. Wybieramy z menu File\Attach disk image\Drive 8. Wpisujemy nową nazwę pliku i wciskamy przycisk Create image, a następnie Attach. Na dysku twardym PC powstaje nowy plik z rozszerzeniem *.d64, ale emulator widzi to tak, jakby do stacji została włożona czysta dyskietka. BTW, z tego pliku (obrazu) można zrobić dyskietkę, która będzie czytana przez prawdziwe (nie emulowane) Commodore.

2. Od czego zacząć?
Jak sprawić, żeby intro uruchamiało się po załadowaniu? Zobaczmy, jak robią to inni. 🙂 Po załadowaniu dowolnej gry w Vice przez File\Autostart disk\tape image jest ona uruchamiana. Jak to się dzieje? Już wyjaśniam. Gry to w większości programy pisane w asemblerze. Uruchamiane są jednak przez rozkaz języka Basic. Zakładam, że masz jakieś pojęcie o Basicu. Każda gra zawiera więc linię języka Basic, powodującą uruchomienie programu w asemblerze, np.:

1 SYS 2064

Rozkaz Basica SYS to nic innego jak polecenie g [adres] monitora. Różnica jest taka, że adres startu w komendzie SYS musi być podany jako liczba dziesiętna, a nie jak przy g – szesnastkowa. Czyli powyższa przykładowa linia to rozkaz startu programu w asemblerze od adresu $810 = 2064 dziesiętnie. Aby nasze intro automatycznie się uruchamiało, musimy dodać na jego początku taką linię z odpowiednim adresem startowym w formie liczby dziesiętnej. Skoro intro odpalało się przez g 2c78, to linia ta powinna wyglądać tak:

1 SYS 11384

Wskazówka: użyj kalkulatora do zamiany liczb szesnastkowych na dziesiętne. Pomysł jest więc następujący – odpalić intro, zresetować (soft reset – Alt-R), wpisać powyższą linię, sprawdzić komendą LIST i uruchomić intro przez RUN. Proste? Właśnie, to byłoby zbyt proste. Wprawdzie intro się odpala (tak, jak zakładaliśmy), ale tekst scrolla wygląda trochę dziwnie… 🙁 Co się stało? Wprowadzony program Basica (w tym przypadku tylko jedna linia) też musi znaleźć się gdzieś w pamięci. W C64 jest tak, że kolejnym liniom przydzielana jest pamięć począwszy od $800 a tam, jak pamiętasz z pierwszego odcinka znajdują się informacje dotyczące czcionki w naszym intrze. I dlatego mamy krzaki.

3. Doktorze, czy mamy na to lekarstwo? 🙂
Oczywiście. Pomysł jest dość prosty. Cały kod intra przesuwamy w pamięci z $800 na $850 Uwaga! teraz nie będzie on działał prawidłowo, chociażby dlatego, że rozkazy JMP będą odnosić się do innych fragmentów programu; intro, aby działać MUSI ZNAJDOWAĆ SIĘ NA $800 ! Ale kod intra przesuwamy tylko tymczasowo. Pamięć od $800 do $850 mamy teraz wolną, więc ze spokojem może tam się znaleźć linia w języku Basic. Tylko teraz nie będzie ona uruchamiała samego intra, bo to musi zostać najpierw przeniesione do odpowiedniego obszaru pamięci. Tu potrzebny jest relokator – program asemblerowy, który przeniesie intro z $850 z  powrotem na $800 i je uruchomi. Powtórzmy – po załadowaniu jest uruchamiany program Basica (jedna linia z komendą SYS), który następnie uruchamia relokator, ten przenosi kod intra z $850 na $800 i uruchamia intro (rozkazem JMP $2c78 – bo taki jest adres startowy).

4. Relokator.
Oto kod relokatora (zmieniony na nasze potrzeby) zaczerpnięty z artykułu „Zostań crackerem” Tomasza ‚TSD’ Dzierkowskiego – jest dostępny na C64 Power. Najpierw przesuniemy kod intra z przestrzeni pamięci od $800 do $3600 na od $850 do #3650. Nic prostszego – korzystamy z rozkazu monitora move 800 3600 3650 – który właśnie do tego służy! Kod relokatora wpisujemy przy wykorzystaniu monitora wbudowanego w Vice. Gdzie umieścimy relokator? Proponuję od razu za intrem czyli od $3650. Tam na pewno nie ma już użytecznego kodu. Korzystamy ze znanego już polecenia monitora a 3650, przepisujemy kod relokatora, na końcu wciskając dwa razy enter. Teraz linia Basica, uruchamiająca nasze intro będzie miała postać:

1. SYS 13904

(bo $3650 = 13904 dziesiętnie – sprawdź!)

Tutaj pełen kod relokatora (po średnikach znajdują się komentarze – ich nie przepisuj! ). Pamięć jest przepisywana w blokach po 256 bajtów.

SEI 
LDA #$34 ;włącz tylko pamięć ram 
STA $01 

LDX #$2E ; ilość bloków do przepisania (1 blok = 256 bajtów – czyli $FF) 
; $3600 – $800 = $2E00 – wielkość intra 
; $2E00 / $FF = $2E – ilość bloków do przepisania 

LDA #$01 ; adres do którego należy przepisać – $801 
STA $FB 
LDA #$08 
STA $FC 

LDA #$51 ; adres skąd należy przepisać – $851 
STA $FD 
LDA #$08 
STA $FE 

LDY #$00 ; pętla realizująca przenoszenie (relokację) intra 
LDA ($FD),Y 
STA ($FB),Y 
INY 
BNE $3669 
INC $FC 
INC $FE 
DEX 
BNE $3669 ; koniec pętli 

LDA #$37 
STA $01 
JSR $E518 
JSR $FDA3 
JSR $FD15 
JSR $E3BF 
CLI 
LDA #$FF 
STA $0800 ; aby wszystko działało jak należy 🙂 

JMP $2C78 ; uruchomienie intra

5. To jak, zapiszemy w końcu to intro? 🙂
Już, już.. Można to zrobić na kilka sposobów, mój jest taki: wykorzystamy cartridge Action Replay 7. Mając wszystko przygotowane (intro + relokator + Basic) wybieramy z menu File\Attach cartridge image\CRT image i zaznaczamy plik z Action Replay 7. Alt-Z powoduje przejście do menu cartridge’a. Tam wciskamy M (monitor), który udostępnia takie polecenie jak: s”nazwa”,8,0800,3700 – powoduje to zapisanie na dyskietce (numer urządzenia 8) w pliku o podanej nazwie zawartości pamięci od $800 do $3700. To wystarczy, żeby zgrać nasze intro. Aha, warto ustawić wcześniej z menu Options\ True drive emulation.

Teraz wystarczy sprawdzić naszą wirtualną dyskietkę, przez Autostart disk\tape image. Jeśli wszystko poszło dobrze, to intro powinno po załadowaniu samo wystartować. Jeśli nie – spróbuj jeszcze raz, pokombinuj. Musi się udać – na dowód załączam zmienione przeze mnie intro. I to właściwie wszystko na temat zmian w intrze do gry 1st Division Manager.

6. Download
Intro – tutaj.
Action Replay 7 – tutaj.

Intro od środka cz.2

W poprzednim odcinku pisałem o tym, jak w przykładowym intrze zmienić parę rzeczy. Szukaliśmy adresu startowego i bloku, gdzie znajduje się tekst scrolla. Mam nadzieję, że mniej więcej załapałeś, o co w tym chodzi. Dziś ciąg dalszy – zmiana napisu i muzyki, oraz trochę o czcionce. Tak więc zaczynamy!

1. Napis
Odpal jeszcze raz intro. Możesz zmienić teraz tekst scrolla. Żeby zachować zmiany, które wprowadziłeś, możesz zrobić dwie rzeczy:

  • zapisać stan pamięci emulatora – w Vice w menu Snapshot\Save snapshot image, który potem odtwarzamy przez Snapshot\Load snapshot image.

  • zapisać dowolny obszar pamięci z linii poleceń monitora (mam nadzieję, że już nie mylisz tego narzędzia z TYM monitorem, który masz przed sobą :). Służy do tego komenda save [nazwa_pliku] [adres_startowy] [adres_końcowy], w naszym przypadku save „x:\intro” 800 3600. Potem do pamięci intro ładujemy komendą load „x:\intro” 800 (patrz poprzedni odcinek).

Już wiesz, jak zapisywać swoją pracę (nie jest to zapis w formacie *.d64 lub *.t64, które powinien obsługiwać każdy porządny emulator, ale tym zajmiemy się w następnym odcinku). Co widać? Napis na dole to pojawiające się na przemian: 1ST DIVISION MANAGER i RELEASED ON 23.02.93. Pamiętasz, co mówiliśmy o szukaniu tekstu? Ja spróbowałbym tak: hunt 800 ffff „23”. Dlaczego? Liczba 23 pojawia się w napisie i można ją znaleźć bezpośrednio w pamięci. Tam gdzie będzie ona, tam będzie napis. Aha, rozkaz hunt [adres_startowy] [adres_końcowy] [wartość] powoduje szukanie w podanym przedziale pamięci zadanej wartości i wypisuje adresy, pod którymi ją odnalazł. U mnie były dwie: 202c i c67b. Zobaczmy, co jest trochę wcześniej. Znana już komenda m 2000.

>C:2000 31 13 14 20 04 09 16 09 13 09 0f 0e 1.. ……..
>C:200c 20 0d 01 0e 01 07 05 12 00 00 00 00 …………
>C:2018 00 00 00 00 00 00 00 00 12 05 0c 05 …………
>C:2024 01 13 05 04 20 0f 0e 20 32 33 2e 30 …. .. 23.0
>C:2030 32 2e 39 33 00 00 00 00 00 00 00 00 2.93……..
>C:203c 00 00 00 00 ff ff ff 00 00 00 ff ff …………
>C:2048 ff aa aa aa ff ff ff aa aa aa aa aa …………
>C:2054 aa 55 55 55 aa aa aa 55 55 55 55 55 .UUU…UUUUU
>C:2060 55 55 55 55 55 55 55 55 55 55 55 55 UUUUUUUUUUUU
>C:206c 55 55 55 55 55 55 55 55 55 55 55 55 UUUUUUUUUUUU
>C:2078 55 55 55 55 55 55 55 00 00 00 00 00 UUUUUUU…..
>C:2084 00 00 00 00 00 00 00 00 00 00 00 00 …………
>C:2090 00 00 00 00 00 00 00 00 00 00 00 00 …………
(C:$209c)

Tego właśnie szukaliśmy. Treść napisu znajduje się w pamięci od adresu $2000 do $2033, czyli 51 znaków. Wystarczy zmodyfikować ten obszar pamięci (patrz poprzedni odcinek) i mamy już swój napis na dole. 🙂

2. Muzyka (czyli to, co w Commodore najlepsze)
Przyznam się od razu – to, co zawsze podobało mi się w C64 to właśnie muzyka. Takie moje małe skrzywienie :). W większości (dużej większości) przypadków muzyka zapisywana jest w obszarze pamięci od $1000 do $2000. Nie wdając się zbytnio w szczegóły techniczne, kod, który odpowiada za jej odtwarzanie, dzieli się na dwie części – inicjującą (init) i służącą do odgrywania (play). Przeważnie (ale nie zawsze – i tak jest w tym przypadku) pod adresem $1000 jest skok do sekcji inicjującej, a pod $1003 jest skok do części odpowiedzialnej za odgrywanie dźwięków. Mówiąc już generalnie o całym intrze – gdzieś na początku jest wykonywany skok do sekcji init (czyli w asemblerze JSR $1000), a potem co jakiś czas (co kilka milisekund) skok do sekcji play (asembler: JSR $1003). Taka jest filozofia odgrywania muzyki :). Jeżeli tak jest, to można z jednego intra zapisać obszar $1000 – $2000 i wstawić do drugiego intra. Jeżeli adresy init i play się zgadzają, to w drugim intrze będziemy mieli muzykę z pierwszego. Jasne? Tak właśnie możnaby podmienić muzykę w naszym przypadku (bo stworzenie własnej muzyki jest naprawdę trudne:) Są tylko dwie sprawy:

  • osobiście ta muzyczka bardzo mi się podoba, więc nie widzę sensu jej zmieniać :)) Co, tylko ja tak uważam? 🙂

  • akurat w kodzie tego demka do odgrywania muzyki jest wykonywany skok JSR $1006 (czyli play jest na $1006). Jeśli chciałbyś przenieść muzykę, która ma play na $1003, trzeba ingerować w kod intra. Jak to zrobić? Szukamy rozkazu JSR $1006 poleceniem hunt 0 ffff 20 06 10. ( 20 06 10 to nic innego jak szesnastkowy zapis rozkazu JSR $1006) Dostajemy adres 2d72. Zobaczmy ten fragment kodu rozkazem d 2d72. Oto, co widać:

(C:$2d9d) d 2d72
.C:2d72 20 06 10 JSR $1006
.C:2d75 A9 BA LDA #$BA
.C:2d77 CD 12 D0 CMP $D012
.C:2d7a D0 FB BNE $2D77
.C:2d7c A9 00 LDA #$00
.C:2d7e 8D 21 D0 STA $D021

Wystarczy zmienić zaznaczony fragment na JSR $1003 i to wszystko. Zrobimy to komendą a 2d72. Powoduje to edycję programu (możliwość wpisywania rozkazów asemblerowych) od adresu 2d72. Wpisujemy JSR $1003 i wciskamy dwa razy klawisz Enter. Powinno działać.

3. Czcionka
Nie będę tu opisywał, jak zmienić czcionkę. To bardzo żmudna praca, bo najpierw trzeba ja zaprojektować, potem dokonać wielu obliczeń, potem wpisać dane… brr.. :(. Poniżej tylko kilka uwag, jak to wygląda, może komuś się przyda :). Jedna litera (standardowa) to kwadrat 8×8 pikseli. Każdy rząd w tym kwadracie jest opisywany przez jedną liczbę (bajt). Bajt, jak wiadomo, to 8 bitów. Jeśli bit jest równy 1, to oznacza, że w tym miejscu matrycy 8×8 piksel jest zapalony. Rysunek ilustruje tą ideę.

 

Stąd wynika, że jedną literę opisuje 8 liczb. Cały alfabet jest zapisywany jako ciąg kolejnych liczb. W tym konkretnym intrze jest trudniej, bo litery są duże, większe niż standardowe 8×8 pikseli. Każda jedna jest opisywana przez 32 liczby. Litera składa się po prostu z czterech pojedynczych znaków 8×8. Jeszcze jedna podpowiedź – do tworzenia czcionek (ale też i muzyki) są specjalne programy. To wielkie ułatwienie. Szukaj ich w dziale Download na C64 Power.

4. Download
Zmieniona wersja intra – tutaj.

5. Podsumowanie
Tu krótka lista wykorzystywanych rozkazów monitora:
m [adres] – wyświetla zawartość pamięci od zaczynając od podanego adresu. Samo m bez adresu wyświetla dalszą zawartość pamięci.
d [adres] – wyświetla kod programu jako ciąg asemblerowych rozkazów poczynając od podanego adresu
save [nazwa_pliku] [adres_startowy] [adres_końcowy] – zapisuje zadany obszar pamięci w pliku na dysku komputera
hunt [adres_startowy] [adres_końcowy] [wartość] – szuka w określonym przedziale pamięci (pamięć w Commodore rozciąga się od $0 do $FFFF) zadanej wartości.
a [adres_startowy] – umożliwia wprowadzenie do pamięci programu w asemblerze rozpoczynając od danego adresu.

Intro od środka cz.1

Każdy użytkownik C64 widział kiedyś intro. To taka „wizytówka” pojawiająca się przed samą grą lub programem. Standardowo pojawiało się tam logo grupy, scroll z informacją o twórcy, kontakcie, podziękowaniami + dodatkowe efekty specjalne. Oczywiście do tego wszystkiego, w tle przygrywa nam muzyka. Często intro było o wiele lepsze (ładniejsze, ciekawsze) niż sama gra! W tym tekście pomówimy o tym, jak zmienić takie intro (tekst scrolla, muzykę, czcionkę… a czasem coś więcej!

Najlepiej uczyć się na przykładach, więc… dzisiejszym celem jest gierka First Division Manager. Co będzie nam potrzebne do pracy? Emulator C64 na PC wyposażony w monitor (czyli program umożliwiający dokonywanie zmian oraz przeglądanie pamięci Commodore). Ja korzystam z Vice – jest naprawdę dobry (wszystkie skróty klawiaturowe będą się do niego odnosić). Ponadto załączam programik mojego autorstwa, potrzebny do zmiany tekstu. Bez niego zmiana tekstu jest żmudna. Zakładam, że posiadasz pewną podstawową wiedzę na temat działania komputera Commodore, monitora, itp. Jeśli nie, to także przeczytaj poniższy tekst!

1. Zaczynamy!
Odpalamy Vice, z menu File wybieramy Autostart disk/tape image i uruchamiamy gierkę. Gra ładuje się, uruchamia, i mamy niebieski ekran z krótkim info, wciskamy spację… Wow! Świetne, tradycyjne commodorowskie intro! Zobaczmy, co my tu mamy: logo (to na górze z ruchomą obwódką), muzyka, scroll (środek ekranu) z pozdrowieniami oraz na dole zmieniający się napis. Co można by zmienić? Praktycznie wszystko – tekst scrolla, tekst na dole, muzykę, czcionkę oraz logo (lecz to już nie jest takie proste). Aby dokonać jakichkolwiek zmian, musimy użyć monitora. Nie mam na myśli tego monitora, na którym wyświetlany jest obraz! 🙂 Monitorem nazywane jest wbudowane narzędzie służące do edycji pamięci C64. W Vice wywołuje się go skrótem Alt-M. Listę jego komend wywołamy poleceniem help lub „?” (więcej informacji o poleceniach można znaleźć w dokumentacji).

Zmienianie intra zaczniemy od znalezienia adresu, spod którego się ono uruchamia. W jakim celu? Gdyż chcemy mieć możliwość uruchamiania naszego intra z naszymi zmianami, zapisania go w formacie akceptowanym przez emulator C64 (np. jako plik *.d64) i automatycznego uruchamiania – ale o tym później.

Znalezienie miejsca odpalenia nie jest łatwe: dobrym sposobem jest przejrzenie zawartości pamięci od adresu 0800 (początek pamięci Basica). Przejdźmy wiec do monitora Alt-M i zobaczmy, co widać, wpisując: m 0800…. Na pierwszy rzut oka – nic sensownego, masa powtarzających się znaczków… wpisując „m” [enter] widzimy dalszą część pamięci. No i skąd wiedzieć, gdzie jest początek programu? Właściwie potrzebne jest duże wyczucie i intuicja. Szukamy bloku danych występujących zaraz po ciągu zer, albo desasemblujemy pamięć (komenda „d” [adres startowy] wyświetla zawartość pamięci jako ciąg rozkazów asemblera poczynając od adresu startowego – tu trzeba wiedzieć, jak wyglądają rozkazy asemblera; więcej informacji znajdziesz w dziale Assembler naszego serwisu. Szukamy sensownego ciągu instrukcji pomiędzy ciągiem porozrzucanych krzaków i rozkazów typu brk (przerwij) i nop (nie rób nic). Wpisz np. d 0800 – tak właśnie wyglądają krzaki :). Znajdowanie startu programu odbywa się trochę w ciemno… Nie od razu to się udaje!

Są oczywiście też pewne ułatwienia. Aby nie szukać kompletnie po omacku, proponują zrobić tak: komenda step pokazuje, gdzie aktualnie (w którym miejscu pamięci) jest wykonywany program. Wpisz je kilka razy. Jak widać mamy do czynienia z pętlą od 2d4d do 2d50 – co to oznacza? Pętla sprawdza, czy jest naciśnieta spacja, jeśli nie – intro trwa dalej. Przeważnie jest tak, że przed pętlą znajduje się program odpowiedzialny za wyświetlenie (zainicjowanie) intra, a tego właśnie szukamy. Wpisz np. d 2c00, a potem kilka razy d Na początku zobaczysz krzaki, ale potem interesujące jest to, co dzieje się od 2c78 – dla mnie wygląda to na sensowny kod programu. Jeśli widzisz kod, który wykonuje operacja na rejestrach o adresach d000 i większych np. d011 (pamięć przeznaczona na grafikę), to jest to najprawdopodobniej to, czego szukamy!

Sprawdźmy tą teorię! Wychodzimy z monitora, restartujemy C64 wciskając Alt-R (ten reset nie kasuje zawartości pamięci), przechodzimy do monitora i wpisujemy g 2c78 (komenda g [adres] powoduje uruchomienie programu w asemblerze zaczynającego się w komórce pamięci o podanym adresie!). OK, intro się odpaliło, właściwie wszystko jest w porządku, ale na scrollu mamy lekkie krzaki. Nie martw się, to niestety skutek uboczny restartu. Po zrestartowaniu do adresów 0800 – 0803 wstawione zostały wartości 00 (sprawdź!), a wcześniej były tam wartości ff.

Wyjaśnienie i sposób naprawy: w 0800 zaczyna się blok informacji o czcionce (jeśli zmienimy te dane, to zmienią się również litery – wpisanie trzech zer spowodowało zmianę znaku pustego – aby temu zaradzić, należy zmienić wartość komórek pamięci o adresach od 0800 do 0803 na ff (tak, jak było przed restartem). Zrobi to komenda: fill 0800 0803 ff. Mamy już adres startowy, wiec połowa roboty za nami! Co dalej?

2. Zmiana tekstu.
To akurat nic trudnego – trzeba znaleźć blok pamięci, gdzie jest przechowywany tekst (jego adres startowy i końcowy) i wpisać tam nowe dane. Jak to zrobić? Zaczynamy od przeczytania tekstu z oryginalnego scrolla, zwracamy uwagę na pojawiające się tam cyfry, przecinki, wykrzykniki, spacje. To dość ważne, bo przeglądając pamięć nie zobaczymy wyrazów, tylko te znaki oraz cyfry, i prawdopodobnie dużą ilość wartości szesnastkowych 20 (co oznacza spację).

Blok pamięci zawierający tekst znajdujemy właśnie przez przeglądanie pamięci (czasem całej) w poszukiwaniu tych typowych znaków. W tym konkretnym przykładzie proponuje komendę m 3000. Już widzisz? Tak, to tutaj! Spróbuj zmienić kawałek tego obszaru pamięci np. wpisując tam wartość szesnastkową – 01 (litera „a„). Umieszczając tu swój napis spowodujemy jego wyświetlenie! Przestrzeń przeznaczona na tekst ciągnie się aż do bloku zer (czyli do 338a). Korzystając z kalkulatora Windows albo innego kalkulatora szesnastkowego obliczamy:

338a – 3000 = $038a (szesnastkowo)

…Czyli w systemie dziesiętnym 906 – to jest maksymalna liczba znaków możliwych do umieszczenia w naszym scrollu. Modyfikujemy wiec ten obszar wstawiając odpowiednie dane. Wstawianie nowego tekstu do scrolla ręcznie, znak po znaku jest na dłuższą metę żmudne i bezsensowne, dlatego polecam mały programik C64 Text Converter, który rozwiązuje ten problem. Jak go używać? Odpal programik, ustal ilość liter (tutaj 906), wpisz swój tekst (nie przekrocz ilości liter) wciśnij przycisk Convert and save! W katalogu z programem znajdziesz plik out.txt – to Twój napis odpowiednio skonwertowany. Teraz w monitorze wpisz load „sciezka_do_pliku_out.txt” [adres startowy], co spowoduje załadowanie tekstu do odpowiedniego miejsca w pamięci – w naszym przykładzie load „out.txt” 3000. Zresetuj jeszcze raz C64 przez Alt-R, przejdź do monitora Alt-M i wpisz g 2c78. Intro powinno się odpalić ze zmienionym tekstem!

Na dziś to wszystko, poniżej krótkie podsumowanie i lista plików do ściągnięcia. Ciąg dalszy już wkrótce! Uwagi, komentarze kieruj na mój adres.

3. Download
Oryginalna wersja intra – tutaj.
Zmieniona wersja intra – tutaj.
Programik do konwersji tekstu – tutaj.

4. Podsumowanie
Krótka lista wykorzystywanych rozkazów monitora:
m [adres] – wyświetla zawartość pamięci od zaczynając od podanego adresu. Samo m bez adresu wyświetla dalszą zawartość pamięci.
d [adres] – wyświetla kod programu jako ciąg asemblerowych rozkazów poczynając od podanego adresu
g [adres] – uruchamia program asemblera od podanego adresu
fill [start_adress] [end_adress] [value] – wypełnia pamięć od – do określoną wartością
load [filename] [startadress] – ładuje do pamięci C64 zawartość pliku, zaczynając od podanego adresu
step – wykonuje następny krok (rozkaz) programu.

Funkcje Basic’a

Format funkcji: W poniższych definicjach funkcji zastosowany jest następujący format: FUNKCJA (argument) gdzie argument może być wartością numeryczną, zmienną lub łańcuchem. Każdy opis funkcji uzupełniony jest przykładem.

ABS – Oblicza wartość absolutną.

ABS(X)
Funkcja wartości absolutnej zwraca pozbawioną znaku wartość argumentu X.

PRZYKŁAD:

PRINT ABS (7*(-5)) 
35

ASC – Zwraca kod CBM ASCII znaku.

ASC(X$)
Funkcja ta zwraca wartość kodu ASCII (wersja na COMMODORE) pierwszego znaku zawartego w X$. Musisz dodać CHR$(0) do ciągu pustego, W przeciwnym razie pojawi się błąd ILLEGAL QUANTITY ERROR (nieprawidłowa wartość).

PRZYKŁAD:
X$=”CBM”:PRINT ASC(X$)
67

ATN – Oblicza w radianach arcus tangens argumentu X.

ATN (X) Punkcja ta oblicza w radianach arcus tangens argumentu X
Otrzymywana wartość mieści się w przedziale od -pi/2 do +pi/2

PRZYKŁAD:
PRINT ATN (3)
1,24904577

CHR$(X) – Zwraca znak odpowiadający podanemu kodowi CBM ASCII.

CHR$(X)
Jest to funkcja przeciwna do ASC. Podaje ona pojedynczy znak odpowiadający kodowi X. X musi być z przedziału 0 do 255. Tabela kodów CHR$ podana jest w Dodatku D.

PRZYKŁADY:
PRINT CHR$ (65) drukuje znak A
A

PRINT CHR$(147) czyści ekran

COS – Podaje wartość cosinusa argumentu X.

COS(X)
Funkcja ta oblicza wartość cosinusa argumentu X podanego w radianach. Funkcja przyjmuje wartości z przedziału od -1 do 1.

EXP – Podnosi liczbę e (Eulera) do potęgi X.

EXP (X)
Funkcja podnosi e (2.71828183) do potęgi X.

PRZYKŁAD:
PRINT EXP(1)
2.71828183

FNxx – Oblicza wartość funkcji zdefiniowanej przez użytkownika.

FNxx(X)
Oblicza wartość zdefiniowanej przez użytkownika funkcji dla argumentu X. Funkcja nosi nazwę xx i musi być uprzednio zdefiniowana w instrukcji DEF FNxx.

PRZYKŁAD:
10 DEF FNAA(X) _ (X-32)*5/9
20 INPUT X
30 PRINT FNAA(X)
RUN

?40 (? jest zachętą do wprowadzenia danej)
4.44444445

FRE – Podaje ilość wolnej pamięci w komputerze.

FRE(X)
gdzie X jest argumentem fikcyjnym (nie ma znaczenia). C64podaje liczbę bajtów jako 16-bitową wartość ze znakiem. Aby otrzymać liczbę dziesiętną należy użyć: PRINT FRE(0) < 0*-65536 + FRE(0)

PRZYKŁAD:
PRINT FRE(0) Podaje aktualną liczbę wolnych bajtów dla programu w BASICu i zmiennych.

INT – Oblicza część całkowitą (obcięcie) liczby zmiennoprzecinkowej.

INT(X)
Funkcja ta oblicza część całkowitą wyrażenia. Jeśli wyrażenie jest dodatnie, oznacza to odrzucenie części ułamkowej i zwrócenie pozostałej części całkowitej.

PRZYKŁAD:
PRINT INT(3.14)
3

PRINT INT(-3.14)
-4

LEFT$ – Zwraca znaki znajdujące się z lewej strony ciągu.

LEFT$(łańcuch znaków, liczba znaków)
Funkcja ta zwraca ciąg złożony z żądanej liczby lewych, skrajnych znaków podanego łańcucha. Jeśli łańcuch ma mniej znaków niż podana liczba, to zwracany jest cały ciąg. Liczba znaków musi być z przedziału 0-255. W przypadku liczby 0 zwracany jest łańcuch pusty.

PRZYKŁAD:
PRINT LEFT$(„COMMODORE”,5)
COMMO

LEN – Podaje długość ciągu znaków.

LEN(łańcuch znaków)
Funkcja podaje ilość znaków w łańcuchu. Znaki niedrukowalne oraz spacje są także uwzględniane.

PRZYKŁAD:
PRINT LEN(„COMMODORE”)
9

LOG – Oblicza wartość logarytmu naturalnego z X.

LOG (X)
Funkcja ta oblicza logarytm naturalny X, gdzie X>0. Logarytm naturalny ma podstawę równą e (zob.. EXP(X)).
Aby obliczyć logarytm przy podstawie 10 podziel wynik przez LOG(10).

PRZYKŁAD:
PRINT LOG(37/5)
2.00148

MID$ – Zwraca podciąg ciągu większego.

MID$(łańcuch znaków, pozycja początkowa, długość)
Funkcja ta zwraca podciąg o żądanej długości, zaczynający się od wybranej pozycji początkowej w łańcuchu wejściowym. Pozycja początkowa określa pierwszy znak od którego podciąg się zaczyna. Długość podciągu jest określona przez trzeci argument funkcji. Pozycja początkowa może wynosić od 1 do 255, długość od 0 do 255. Jeśli wartość początkowa jest większa od długości ciągu wejściowego, lub argument długości wynosi 0, to MID$ zwróci łańcuch pusty. Jeśli argument nie zostanie podany, to zostaną zwrócone wszystkie znaki na prawo od pozycji początkowej (wraz z nią).

PRZYKŁAD:
PRINT MID$(„COMMODORE 64 C”,3,5)
MMODO

PEEK – Podaje zawartość wybranej komórki pamięci.

PEEK(X)
Funkcja ta podaje zawartość komórki pamięci o adresie X, gdzie X jest z zakresu 0 do 65535. Wynik funkcji jest z zakresu 0 do 255. Jest to dopełnienie instrukcji POKE.

PRZYKŁAD:
PRINT PEEK(650)
0

W przykładzie tym 0 oznacza, że klawiatura znajduje się w trybie normalnym (pod względem tego, które klawisze są samopowtarzalne).

C -Podaje wartość pi.

PRZYKŁAD:
PRINTc
3.14159265

POS – Podaje numer kolumny kursora.

POS (X)
Funkcja POS podaje, w której kolumnie ekranu znajduje się aktualnie kursor. X jest argumentem fikcyjnym, który musi być umieszczony, ale którego wartość jest ignorowana.

PRZYKŁAD:
10 PRINT „KURSOR JEST W KOLUMNIE”;
20 PRINT POS(0)

Kiedy uruchomisz ten program komputer napisze: KURSOR JEST W KOLUMNIE 22. Oznacza to, że po wyświetleniu słów KURSOR JEST W KOLUMNIE kursor znajdował się w kolumnie 22.

RIGHT$ – Zwraca podciąg składający się ze skrajnie prawych znaków ciągu.

RIGHT$(łańcuch, Ilość znaków)
Funkcja ta zwraca podciąg złożony za skrajnie prawych argumentów tekstowych. Długość ciągu określona jest przez argument ‚ilość znaków’, który może być z zakresu 0-255. Jeśli wartość tego argumentu wynosi zero, to zwracany jest łańcuch pusty. Jeśli ‚ilość znaków’ jest większa niż długość ciągu, to zwracany jest cały ciąg. Zobacz także funkcje LEFT$ i MID$.

PRZYKŁAD:
PRINT RIGHT$(„KOMPUTER”5)
PUTER

RND – Zwraca liczbę przypadkową.

RND(X)
Funkcja ta podaje liczbę przypadkową z zakresu 0 do 1. Jest ona użyteczna w grach, w celu stymulowania rzutu kostką lub innych elementów losowych. Jest również użyteczna w pewnych zastosowaniach statystycznych. Gdy X=0 Generuje liczbę losową w oparciu o zegar komputera. Gdy X>0 Produkuje powtarzalne liczby przypadkowe w oparciu o opisaną niżej liczbę bazową. Gdy X< 0 Produkuje liczbę przypadkową używaną jako liczba bazowa. Rozpoczyna sekwencję powtarzalną. W celu zasymulowania rzutu kostką, używaj formuły INT(RND(1)*6+ 1). Najpierw liczba przypadkowa mnożona jest przez 6, co rozszerza zakres od 0 do 6. Teraz dodaje 1 (co powoduje, że zakres zmienia się od liczb większych od 1 a mniejszych od 7). Funkcja INT dokonuje odrzucenia części ułamkowej, pozostawiając liczby w zakresie od 1 do 6.

PRZYKŁADY:
PRINT RND(0) Wyświetla liczbę przypadkową od 0 do 1.
0.507824123

PRINT INT(RND(1)*100+1) Wyświetla liczbę przypadkową z zakresu od 1 do 100.
89

SGN – Zwraca znak argumentu X.

SGN(X)
Funkcja ta podaje znak argumentu X według następującej konwencji: zwraca-1 jeśli X0.

PRZYKŁAD:
PRINT SGN(4.5);SGN(0);SGN(-2.3)
1 0 -1

SIN – Oblicz sinus argumentu.

SIN(X)
Funkcja ta zwraca sinus argumentu X podanego w radianach. Wartość funkcji jest w przedziale 0,1.

PRZYKŁAD:
PRINT SIN(c/3)
0.866025404

SPC – Powoduje przeskoczenie kursora do nowej pozycji.

SPC(X)
Funkcja ta używana jest w instrukcjach PRINT i PRINT# w celu p zeskoczenia o X miejsc od aktualnej pozycji kursora. Zwróć uwagę, że przeskoczone pozycje nie są kasowane. Zobacz także funkcję TAB, która przesuwa kursor do ustalonej pozycji.

PRZYKŁAD:
PRINT „COMMODORE’ ;SPC(6);”64C”
COMMODORE 64C

SQR – Oblicza wartość pierwiastka kwadratowego z argumentu.

SQR(X)
Funkcja ta zwraca wartość równą pierwiastkowi kwadratowemu (ang.. SQare Root) argumentu X, gdzie X jest liczbą nieujemną. Jeśli argument jest ujemny, pojawi się komunikat ILLEGAL QUANTITY ERROR (niedopuszczalna wartość).

PRZYKŁAD:
PRINT SQR(25)
5

STR$ – Zwraca postać łańcuchową liczby.

STR$(X)
Funkcja ta zwraca łańcuch (ang.. STRing) reprezentujący wartość liczbową argumentu X przy pomocy znaków ASCII. Funkcja zwraca dokładnie te same znaki, które zostałyby wydrukowane przy pomocy PRINT. Oznacza to, że liczby dodatnie poprzedzone są dwiema spacjami, a ujemne spacją i znakiem minus. Odwrotna do funkcji STR$ jest funkcja VAL.

PRZYKŁAD:
PRINT STR$(123.45)
123.45

PRINT STR$(-89.03)
-89.03

PRINT STR$(1 E20)
1E+20

TAB – Przesuń kursor do pozycji tabulatora.

TAB (X)
Funkcja TAB jest używana w instrukcjach PRINT i PRINT# w celu wykonania warunkowego skoku do kolumny o określonej pozycji. TAB funkcjonuje inaczej w przypadku ekranu niż w przypadku drukarki lub dyskietki. W przypadku drukarek i dyskietek TAB spełnia identyczną funkcję jak SPC (zobacz opis SPC). 11V przypadku ekranu, jeśli kolumna X znajduje się po prawej stronie od bieżącej pozycji ekranu, to X stanie się nową pozycją kursora. Jeśli X jest w miejscu kursora, lub na lewo od niego, to funkcja TAB nie ma żadnego efektu. Znaki przeskoczone nie są kasowane.

PRZYKŁAD:
10 PRINT „COMMODORE”;TAB(25);”64C”
COMMODORE 64C

TAN – Oblicza wartość tangensa argumentu.

TAN (X)
Funkcja ta oblicza wartość argumentu X podanego w radianach.

PRZYKŁAD:
PRINT TAN(.785398163)
1

USR – Wywołuje podprogram maszynowy.

USR(X)
Kiedy używana jest ta funkcja, to BASIC umieszcza wartość A w akumulatorze zmiennoprzecinkowym (FAC), w komórkach pamięci od $0061 do $0066 (od 97 do 102) i wywołuje wektor USR. Musisz umieścić adres swojego podprogramu maszynowego w komórkach $0311(785) i $0312(786) (młodszy / starszy bajt adresu). Ponieważ USR jest funkcją, zatem zwraca wartość rzeczywistą umieszczoną w akumulatorze zmiennoprzecinkowym w chwili powrotu. Wektor USR wskazuje normalnie na procedurę ILLEGAL QUANTITY ERROR (nielegalna wartość).

PRZYKŁAD:
10 POKE 785,0
20 POKE 786,192
30 A=USR(X)
40 PRINT A

Linie 10 i 20 umieszczają adres startowy procedury ($C00 = 49152; $00 = 00; $CO =192) pod adresami 785 i 786. Linia 30 zapamiętuje wartość akumulatora zmiennoprzecinkowego w A.

VAL – Zwraca wartość liczbową odpowiadającą podanemu łańcuchowi.

VAL(X$)
Funkcja ta zamienia łańcuch znaków X$ na wartość liczbową, jest zatem operacją odwrotną do STR$. Łańcuch jest analizowany od skrajnie lewej strony do prawej, w celu odszukania możliwie dużej ilości cyfr. Jeśli Commodore natrafi na niedopuszczalny znak, to tylko część łańcucha do tego miejsca zostanie zamieniona na liczbę. Dopuszczalnymi znakami numerycznymi są: 0-9, spacje, + i – ; tylko przed liczbą lub po E kropka dziesiętna (jedna) znak wykładnika E (jeden). Jeśli brak jest w ciągu znaków numerycznych zwracana jest wartość zero.

PRZYKŁAD:
10 A$=”120″
20 B$=”365″
30 PRINT VAL(A$) + VAL(B$)
RUN
485

Kurs Basic’a cz. 6

A oto już szósty odcinek, który prezentuję po przejściach związanych z maturą i egzaminami wstępnymi! Co miałem zdać to zdałem, a tam gdzie się miałem dostać się dostałem. Teraz mogę powrócić. Z góry wszystkim sorrki za to , że niniejszy kurs ciągnie się jak olej ze smarem, ale uzasadnienie napisałem powyżej. Dobra, koniec marudzenia. Omówimy dzisiaj takie słowa kluczowe Basic’a jak: DIM, POKE, REM, STOP, CLR.

DIM

O tablicach powiedziałem już trochę we wcześniejszych odcinkach, ale dzisiaj uzupełnimy niektóre informacje. Jeśli nasza tablica będzie miała więcej niż 11 elementów musimy użyć instrukcji DIM, aby poinformować komcia o ilości zmiennych zawartych w tablicy o określonej nazwie. Należy przy tym pamiętać, że raz utworzona tablica przebywa w pamięci, więc ją zajmuje. Dlatego nie należy tworzyć tablic niewykorzystywanych i/lub większych niż to jest potrzebne. Aby obliczyć rozmiar danej tablicy nazleży pomnożyć wszystkie wymiary tablicy powiększone o 1 (każdy indeks elementu zaczyna się od liczby 0). W jednej linijce możemy utworzyć więcej niż jedną tablicę, ale nazwy nie mogą się powtarzać. A teraz parę przykładów:

  • 10 DIM A(9)

  • 20 FOR I=0 TO 9

  • 30 A(I)=I:PRINT A(I)

  • 40 NEXT

Powyższy program tworzy tablicę o nazwie A z dziesięcioma elementami (pamiętać, że pierwszy element ma indeks równy 0). Następnie tablica jest wypełniana liczbami od 0 do 9, które są potem wyświetlane na ekranie. Możemy również deklarować tablice wielowymiarowe, a ich przykłady podaję poniżej:

  • DIM B7(15,2); DIM CC%(4,4,4)

Zmiennymi tablicowymi posługujemy się w identyczny sposób jak z normalnymi zmiennyni, z tym, że po jej nazwie musimy jeszcze podać numer indeksu, który oznacza na jakim elemencie tablicy chcemy operować. Na temat tablic to już wszystko. Możecie sobie poczytać jeden ze wcześniejszych numerów, w którym na ten temat było trochę informacji.

POKE

Ta instrukcja jest, że to tak nazwę, nieobowiązkowa (przynajmniej na stan dzisiejszy). Służy ona bowiem na operowaniu pamięcią komputera i umożliwia jej modyfikowanie. Oczywiście, że modyfikować możemy tylko pamięc RAM (jakby ktoś nie wiedział). Po nazwie instrukcji pojawiają się dwa numery: pierwszy z nich jest numerem (tzw. adresem) komórki pamięci, do której chcemy wpisać określoną wartość, a drugim jest ta właśnie wartość. Wartości te muszą mieścić się w przedziale 0-255 i zastępują one liczbę dotychczas zawartą w komórce.

Przykład(y):

POKE 53280,0:POKE 53281,0:POKE 646,1

Powyższe komendy zmieniają kolor obrzeża i tła na czarny(komórki 53280 i 53281), a kolor liter zmieniony jest na biały (komórka 646). Możemy poeksperymentować z innymi liczbami i spróbować zrobić jakieś fajne efekty (jak na Basa). Pamiętam mój pierwszy taki efekt, który nazwałem flash, gdyż kilka kolorów migało jednocześnie na wszystkich płaszczyznach. I oto on:

    10 R=INT(RND(1)*255)-1

  • 20 FOR I=1 TO R

  • 30 POKE 53280,R:POKE 53281,R-12:

  • 40 NEXT

Poniżej przedstawiam tablicę kolorów komcia, które można wpokowywać w komórki pamięci:

  • 0 – czarny

  • 1 – biały

  • 2 – czerwony

  • 3 – turkusowy

  • 4 – fioletowy

  • 5 – zielony

  • 6 – niebieski

  • 7 – żółty

  • 8 – pomarańczowy

  • 9 – brązowy

  • 10 – jasnoczerwony

  • 11 – szary 1

  • 12 – szary 2

  • 13 – jasnozielony

  • 14 – jasnoniebieski

  • 15 – szary 3

Za pomocą instrukcji POKE możemy również wydobywać dźwięki, przełączać tryb tekstowy na tryb graficzny. Ale jak już mówiłem takie programy napisane w Basie są wolne i trzeba mieć olbrzymią cierpliwość (a z cierpliwością jak z cnotą – łatwo ją stracić). Jeśli chodzi o niektóre instrukcje zostaną one później wyjaśnione (teraz mogę powiedzieć, że RND to generator liczb pseudolosowych; INT to funkcja zwracająca część całkowitą danej liczby dziesiętnej).

Instrukcję POKE można z powodzeniem stosować do operowania na tzw. pamięci  ekranowej. Cóż to takiego jest? Otóż jest to pamięć, w której są przechowywane informacje na temat co jest aktualnie wyświetlane na ekranie. Dzięki instrukcji POKE możemy wyświetlać różne znaki, tworzyć proste animacje itp. Jak to robimy? Już pokazuję na prostym przykładzie. Chcemy umieścić literę „A” na środku ekranu. W przypadku komcia jest to 20 kolumna i 12 wiersz. Natomiast pamięć ekranu to komórki w zakresie od 1024 (lewy, górny róg) do 2023 (prawy dolny). Jak widać trzeba by było obliczać jaki jest numer komórki pamięci w 20 kolumnie i 12 wierszu. Na szczęście mądrzy ludzie trochę pomyśleli i pokazali nam wzór dzięki któremu bez problemu taką rzecz policzymy. A oto on:

  • ADRES_KOMÓRKI = 1024 + X + 40*Y

Gdzie: X – numer kolumny (współrzędna pozioma; 0 – 39), Y – numer wiersza (współrzędna pionowa; 0 – 24).

Skoro to już wiemy możemy przejść do konkretów. Ze powyższego wzoru wychodzi nam, że 20 kolumna i 12 wiersz to komórka o adresie 1524 (1024 + 20 + 40*12 = 1524). Teraz nam zostaje wpokowanie do niej odpowiedniej cyfry oznaczającej dużą literę „A”: POKE 1524,1. Naciskamy RETURN i na środku ekranu powinna nam się pojawić litera A. Proste ? No myślę. A teraz co możemy wpisywać do pamięci ekranu ? Ogólnie rzecz biorąc wszystko co siedzi w tzw. generatorze znaków. Jest to inaczej taki obszar pamięci ROM (stałej komputera), w którym siedzą wszystkie litery, znaki, cyfry, które możemy wprowadzać na ekran za pomocą klawiatury. Z tego co wiem, w instrukcji do komcia znajdowała się cała tabela prezentująca wszystkie znaki wraz z ich kodami liczbowymi. Póki co wiem, że nie wszyscy ją mogą mieć więc wkrótce postaram się ją jakoś zamieścić na naszych łamach. Na koniec tych nieco bardziej skomplikowanych przemyśleń proponuję programik wykreślający funkcję sinus dla kątów od 0 do 351 (na podstawie C&A):

  • 10 PRINT CHR$(147)

  • 20 POKE 53280,14:POKE 53281,11

  • 30 FOR KAT=0 TO 351 STEP 9

  • 40 X=KAT/9

  • 50 Y=INT(SIN(KAT*PI)/180)*10)

  • 60 POKE 1504+X-Y*40,81

  • 70 NEXT KAT

  • 80 GET A$:IF A$=” „THEN 80

  • 90 PRINT CHR$(147):END

REM

Ten rozkaz użyty w programie służy do wstawiania komentarzy co ułatwia czytelność tegoż programu dla innych jego użytkowników. Problem w tym poleceniu polega na tym, żeby nie przesadzać z ilością komentarzy (zarówno jeśli chodzi o ich liczbę jak i długość). Komentarze powinny krótko opisywać poszczególne części programu, szczególnie jeśli nasz program podzielony na procedury, które wypełniają poszczególne działania. Komentarze są instrukcjami niezwykle potrzebnymi, ale ich zbyt duża liczba tylko przeszkadza.

Przykład:

  • 10 REM tu możesz pisać różne bzdury i uwagi lub bzdurne uwagi

STOP

Ta instrukcja zatrzymuje wykonywanie się programu przy czym zostaje wyświetlony komunikat BREAK IN nnn, gdzie nnn jest numerem linii, w której został zatrzymany program (czyli tam gdzie umieściliśmy STOP). Działanie programu możemy wznowić za pomocą polecenia CONT. Instrukcję STOP najczęściej umieszcza się w podejrzanych miejscach programu, aby zbadać czy nie zachodzą tam jakieś błędy.

CLR

Ta instrukcja kasuje wszystkie zmienne zawarte w pamięci, natomiast sam program pozostawia nietknięty. Instrukcja ta jest wykonywana automatycznie po poleceniu RUN.

Kurs Basic’a cz. 5

Co, to już piąty odcinek? Kiedyś powiedzałbym, że to niemożliwe. Ale spoko, ten odcinek dedykuje rozkazom FOR…NEXT, GOSUB…RETURN, ON, GET.

FOR…NEXT…STEP

Nieraz zastanawiałem się jak napisać program, który wypisywałby np. sto razy moje imię? Czy to znaczy, że muszę pisać sto razy komendę PRINT? W tym przypadku chyba bym zwariował (i chyba nie tylko ja :-))))))) Jednak pojawia się nam z pomocą FOR…..NEXT. Dzięki tej komendzie możemy nakazać computrowi, aby wykonał część programu kilka razy, w zalężności od decyzji użytkownika programu lub programisty. Np. powyższy program możemy zapisać następująco:

10 FOR I=1 TO 100
20 PRINT „MIKE”
30 NEXT

Ten program właśnie wypisuje 100 razy MIKE. Linia 10 inicjuje licznik pętli (czayli zmienną I) wartością 1, a następnie nakazuje inkrementacje zmiennej I do 100. Linia 20, nie chce mi się już tłumaczyć, natomiast linia 30 oznacza, że należy zwiększyć wartość I (jeśli jeszcze nie doszła do 100) i rozpocząć kolejną pętlę. Po rozkazie NEXT z reguły podaje się nazwę zminennej, którą chcemy zwiększyc (inkremetnować), ale ponieważ nasz program ma tylko jedną zmienną możemy pominąć jej nazwę. Poza tym istnieje jeszcze jeden opcjonalny parametr o nazwie STEP, który nakazuje zwiększyć wartość o pewną liczbę. Jeśli nie podajemy rozkazu STEP (jak w powyższym programie) przybiera on cyfrę 1. W poniższym przykładzie program wyświetla liczby od 10 do 100 skacząc co 10:

10 FOR I=10 TO 100 STEP 10
20 PRINT I
30 NEXT

Ponadto możemy tworzyć zagnieżdżone pętle tzn. jedną w drugiej. I znwu programik, który wypisuje w jednej kolumnie liczby od 10 do 100 skacząc co 10, a w drugiej liczby od 100 do 150 skacząc co 5:

10 FOR I=10 TO 100 STEP 10
20 FOR J=100 TO 150 STEP 5
30 PRINT I,J
40 NEXT J,I

Należy pamiętać, że po NEXT należy podać nazwę zmiennej, która należy do najbardziej zagnieżdżonej pętli, czyli u nas J. W przeciwnym przypadku program nie będzie działał właściwie.

GOSUB…RETURN

W poprzednim odcinku poznaliśmy instrukcję GOTO, która nakazywała programowi skok do określonej linii i wykonywanie od niej dalszej części programu. Instrukcja GOSUB działa podobnie tzn. program skacze do linii podanej po rozkazie, ale umożilwia powrót do linii z której nastąpił skok dzięki poleceniu RETURN. Jest to tzw. podprogram lub procedura. Poza tym instrukcja GOSUB umożliwia wybranie określonego numer linii w zależności od danych wprowadzonych przez użytkownika. Ale po kolei:

10 GOSUB 40
20 PRINT A$
30 END
40 A$=”MIKE”
50 RETURN

Program skacze do linii 40 i przypisuje zmiennej A$ łańcuch tekstowy następnie powraca do programu przed END (programu głównego) i wypisuje na ekranie wartość zmiennej A$. Oczywiście jest to program zbyt trywialny, aby w zupełności pokazać możliwości GOSUB.

ON

Ta komenda łączy się nierozerwalnie również z rozkazemi GOTO i GOSUB. Jest ona jakby skróconą wersją IF….THEN. Pozwala ona w zależności od danych wprowadzonych przez użytkownika wybór określonej linii do której program ma wykonać skok. Jeśli dana wartość jest równa 0 lub większa od liczby numerów podanych w tej instrukcji to ON jest pomijana. I kolejny przykład:

10 INPUT X
20 ON X GOTO 100,200,300,400,500

Wykonanie tego programu zależy od wartości zmiennej X. Jeśli np. X bedzie wynosić 1 to program skoczy do lnii 100, jeśli 2 do linii 200 itd, itp.

GET

Instrukja GET jest bardzo podobna do instrukcji INPUT, jednakże pozwala ona na, nie wprowadzanie nie łańcuchów tekstowych, a pojedynczych znaków. Jeśli nie został naciśnięty żaden klawisz przypisywany jest znak pusty (w przypadku zmiennej tekstowej) lub zero (w przypadku zminnej liczbowej). Podczas używania zmiennej liczbowej konieczne jest podanie wartości cyfrowej,w przeciwnym przypadku zostanie wyświetlony komunikat o błędzie. Poza tym konieczne jest podanie instrukcji GET w pętli sprawdzającej, czy został naciśnięty jakiś klawisz. Nie kapejszyn?!? No to mały przykładzik:

10 GET A$:IF A$=””THEN 10
Ta linia oczekuje na naciśnięcie dowolnego klawisza. Natomiast to:

10 GET A$:IF A$”A”THEN 10
Program nie zakończy się jeżeli nie pacniemy litery A.

I KONIEC… na dzisiaj. Pamiętajcie eksperymentujcie. Miłego bejzikowania.

Kurs Basic’a cz. 4

Dzisiejszy odcinek poświęcam instrukcjom PRINT, INPUT, GOTO i IF……THEN.

PRINT

Jest to jedna z pierwszych instrukcji jaką powinien poznać początkujący programista. Dzięki niej możemy wykonywać szereg różnych akcji. Po PRINT może wystąpić:

  • łańcuch tekstowy ujęty w cudzysłów

  • nazwa zmiennej

  • funkcja

  • znaki formatujące

Ostatnia pozycja służy do formatowania danych wychodzących na ekran. Na przykład: przecinek dzieli ekran na cztery kolumny, średnik poleca drukowanie jenego tekstu za drugim. Oto przykładowa instrukcja PRINT:

PRINT 2+2

Kiedy naciśniemy RETURN to pokaże się nam wynik 4. Oczywiście możemy obliczać różne działania artymetyczne (radzę zajrzeć do jednego z poprzednich numerów). A tu mamy krótki programik:

10 PRINT „Halo”
20 PRINT „Halo”, A$
30 PRINT A+B
40 PRINT J
60 PRINT A, B, C, D

Linia 10 wypisuje na ekranie łańcuch tekstowy Halo, w linii 20 również zostaje wyświetlone Halo, a w pewnej odległości za nim jest wyświetlona wartość zmiennej łańcuchowej o nazwie A$. Linia 30 wyświetla sumę liczb A i b. Linia 40 wyświetla zawartość zmiennej J i w końcu linia 60 wyświetla zawartość zmiennych A, B, C i D. Radzę poćwiczyć używanie tej komendy, gdyż w żadnym języku programowania nie moża się bez niej obejść. Jeszcze kilka rad:

Wynik PRINT 5+10/2 będzie inny niż wynik instrukcji PRINT (5+10)/2. Wniosek nasuwa się sam: UŻYWAĆ NAWIASÓW. Pamiętajcie o tym jeśli nie chcecie popełniać podstawowych błędów. Jest jeszcze inny format instrukcji PRINT a mianowicie #PRINT, która pozwala wyprowadzać m.in. na drukarkę. Funkcje formatujące takie jak: POS, SPC i TAB (które nierozerwalnie wiążą się z instrukcją PRINT) omówimy nieco póżniej. No i na koniec, możemy zastępować instrukcję PRINT znakiem zapytania (?), ale nie możemy tak robić w przypadku rozkazu #PRINT (tzn. nie możemu go zapisać jaki #?). Czyli innymi słowami instrukcje:

PRINT „Mike”

i

? „Mike”

są równoważne. No i to tyle jeśli chodzi o instrukcję PRINT.

INPUT

Instrukcja INPUT nakazuje programowi zatrzymanie się, aż do czasu, gdy użytkownik wpisze odpowiednie dane, które są następnie użyte w dalszej części programu. Format instrukcji INPUT jest różnorodny, ale najczęściej można go spotkać w dwóch formach. Po instrukcji INPUT występują nazwy zmiennych, do których zostaną wprowadzone dane od użytkownika (mogą być liczbowe i/lub tekstowe). Oczywiście typy zmiennych muszą być dopasowane do typu wprowadzanego przez użytkownika. Np. jeśli użytkowanik musi wprowadzić łańcuch tekstowy (np. swoje imię), to po instrukcji INPUT musi wystąpić nazwa zmiennej ze znakiem $. W przeciwnym wypadku komputer wyświetli komunkat: TYPE MISMATCH ERROR, czyli niezgodność typów.A co się stanie jeśli w tym przypadku użytkownik wpisze nie jakieś słowo, a liczbę? Komputer nie wyświetli w tym przypadku komunikatu o błędzie, ale 1 już nie będzie cyfrą, a jednoznakowym łańcuchem tekstowym. Po prostu nie będzie traktowana jak 1, ale jako „1”. Odwołując się do komendy PRINT, wydanie polecenia:

PRINT „1”+1

skończy się komunikatem o błędzie wymienionym powyżej. Dlaczego? A spróbujcie dodać jabłka do dżojtów i co wam z tego wyjdzie?

Po instrukcji INPUT może również wystąpić (tak jak w instrukcji PRINT) łańcuch tekstowy zawarty w cudzysłowach. Dobra koniec suchej teorii, czas na programy:

10 PRINT „Podaj swoje imię”
20 INPUT A$
30 PRINT „Cześć „; A$

Czy trzeba coś tłumaczyć? Mam nadzieję, że nie. Ale powyższy program możemy również zapisać w skróconej formie:

10 INPUT „Jak masz na imię”; A$
20 PRINT „Cześć „; A$

Po instrukcji INPUT możemy podać więcej nazw zmiennych, ale musimy je rozdzielić przecinkami. Przykładem niech będzie program obliczający obwód trójkąta różnoramiennego:

10 INPUT „Podaj dłuość boków trójkąta (a. b, c) „; A, B, C
20 PRINT „Obwód trójkąta wynosi „; A+B+C

Oczywiście użytkownik wprowadzjąc długości boków musi je również je rozdzielić przecinkami. Np. jeśli musi wprowadzić liczby 5 10 15, musi je rozdzielić przecinkami, czyli 5, 10, 15. I KONIEC.

GOTO

Instrukcja GOTO może być zapisana jako GO TO, czyli idź do. Po tym rozkazie podajemy numer linii, do której program ma skoczyć i od tego momentu wykonywać program. Przy tej instrukcji należy uważać, gdyż zmniejsza ona czytelność programu. W innych językach (takich jak C++ czy Pascal) używanie tej instrkcji nie przysparza przyjaciół. Przykłady? Jeden wystarczy:

10 PRINT „Mike”
20 GOTO 10

Tutaj na ekranie zobaczymy napis Mike, który będzie się wyświetlał tak długo, dopóki nie przerwiemy programu (np. klawiszem RUN/STOP).

IF…THEN

Instrukcja IF…..THEN (jeżeli warunek to) pozwala komputerowi na zmienienie kolejności wykonywania się programu. Co to znaczy? Znaczy to tyle, że dalsze wykonywanie się programu jest uzależnione od danych jakie wprowadził użytkownik. Przykład pierwszy z brzegu:

10 INPUT „Podaj swoją ksywę „; A$
20 IF A$=”Mike” THEN PRINT „Jesteś Maciek”
30 IF A$=”Luc” THEN PRINT „Jesteś Łukasz”
40 END

W zależności od tego, jaką wartość przyjmie zmienna A$, to program wykona różne instrukcję. Jeśli użytkownik wprowadzi łańcuch Luc to program wyświetli jesteś Łukasz, a jeśli Mike to Jesteś Maciek. Natomiast jeśli wprowadzimy jakiś inny zwrot to program najnormalniej na świecie się zakończy (instrukcja END oznacza koniec programu, ale w sumie można ją pominąć). Powyższy program można zapisać w różnych formach np.:

10 INPUT „Podaj swoją ksywkę „;A$
20 IF A$=”Mike” THEN GOTO 50
30 IF A$=”Luc” THEN GOTO 60
40 END
50 PRINT „Jesteś Maciek”:END
60 PRINT „Jesteś Łukasz”:END

W tym przypadku program jest dłuższy, ale jego wynik jest dokładnie taki sam jak tego powyżej. No i jeszcze kilka uwag:

  • dwukropek informuje komputer, że w jednej linii chcemy umieścić więcej instrukcji

  • instrukcje GOTO w ostanim programie możemy opuścić, co pozwala znowu na skrócenie programu (numer linii podajemy od razu po instrukcji THEN)

Oczywiście możliwości instrukcji IF….THEN są olbrzymie. Możemy porównywać liczby, długości wyrazów. Oto już przed ostatni przykład w tym odcinku:

10 INPUT „Wpisz jakąś liczbę „;A
20 IF A<5 THEN PRINT "Liczba ";A;" jest mniejsza od 5":END
30 IF A=5 THEN PRINT „Liczba „;A;” jest równa 5″:END
40 IF A>5 THEN PRINT „Liczba „;A;” jest większa od 5″:END
50 END

No i jeszcze operatory OR, AND i NOT.

10 INPUT „Wprowadź jakąś liczbę „;A
20 B=10:C=20
30 IF AB THEN PRINT A;” jest mniejsze od „;C;” ale większe od „;B
40 IF AB THEN PRINT „Liczba powyżej 10 albo poniżej 20”
50 IF A=NOT C THEN PRINT „Ta liczba to nie 20”

To już koniec, ale na samo zakończenie ostatnia już rada: musicie trochę poeksperymentować. Początki są trudne, ale z czasem wszystko stanie się jasne. Po prostu piszcie…. programy. Do następnego odcinka.

Kurs Basic’a cz. 3

Witam w 3 już odcinku naszego kursu. Dzisiaj będziemy omawiać polecenie umożliwiające poprawę i modyfikowanie programów oraz nagrywanie i odczytywanie ich z dysku/kasety. Bez zbędnych ceregieli przechodzimy do tematu.

CONT (Continue)

Polecenie to wykorzystujemy do kontynuowania programu, zatrzymanego poleceniami STOP i/lub END. Polecenie to nie będzie działało jeśli zmieniliśmy lub dodaliśmy w programie numery linii. Nie będzie równiż działało wtedy, gdy program zostanie przerwany w wyniku błędu. W takich przypadkach otrzymamy komunikat: CAN’T CONTINUE ERROR.

LIST

Polecenie to pozwala nam na wyświetlenie (wylistowanie) linii programu na ekranie. Możliwe jest wylistowanie całego programu lub jego części.

Przykłady:

  • LIST wylistuje na ekranie cały program

  • LIST 10- wylistuje program od linii 10 do końca

  • LIST 10 wyświetla tylko 10 linię programu

  • LIST -10 pokazuje linie od początku do wiersza 10

  • LIST 10-20 pokazuje wiersze od 10 do 20 włącznie

LOAD

Polecenie to służy do wczytywania programu z dyskietki/kasety do pamięci komputera. Po wpisaniu LOAD zostanie załadowany pierwszy program napotkany na taśmie. Po tym rozkazie możemy od razu podać w cudzysłowach nazwę programu, który chcemy wczytać. Następnie musimy komputerowi przekazać, czy chcemy wczytywać program z dysku, a potem naciskamy RETURN.

Przykłady:

  • LOAD czyta pierwszy program jaki wystąpi na taśmie

  • LOAD „HALO” szuka na taśmie programu o nazwie HALO i wczytuje go do pamięci

  • LOAD A$ szuka programu o nazwie ulokowanej w zmiennej A$ i wczytuje go do pamięci

  • LOAD „HALO”, 8 szuka programu o nazwie HALO na dyskietce i wczytuje go do pamięci

  • LOAD „*”, 8 wczytuje pierwszy program z dyskietki

NEW

Polecenie to usuwa program znajdujący się aktualnie w pamięci. Kasowane są również wszystkie zmienne używane przez ten program. Jeśli nie nagraliśmy programu na dysk/kasetę, to właśnie go straciliśmy :((((. Tego polecenia możemy również używać w programach, jeśli chcemy, aby program po zakończeniu sam się wykasował z pamięci. Ponadto w SIMON’S BASIC’U znajduje się polecenie o nazwie OLD, które umożliwia odzyskanie programu wymazanego poleceniem NEW.

RUN

Polecenie to służy do uruchamiania programu znajdującego się w pamięci komputera. Po wpisaniu samego polecenia (bez żadnego parametru), program uruchomi się od wiersza o najniższym numerze. Możemy jednak podać numer wiersza, od którego ma się rozpocząć uruchomienie programu.

Przykłady:

  • RUN program startuje od linii o najniższym numerze

  • RUN 100 program jest uruchamiany od linii o nr 100

  • RUN X wystąpi komunikat UNDEFINED STATEMENT ERROR – wiersz o podanym numerze musi istnieć, a jego numer musi być podany bezpośrednio (nie w zmiennej)

SAVE

Jest to polecenie odwrotne do LOAD, tzn. jego zadaniem jest nagrywanie programu znajdującego się w pamięci komputera na dysk/kasetę. Po podanie samego SAVE program zostanie zapisany na taśmie, jednak bez żadnej nazwy. Aby mu ją nadać po poleceniu otworzymy cudzysłów i wpisujemy nazwę, pod którą program ma istnieć. Jeżeli chcemy nagrać program na dyskietkę, to po nazwie programu stawiamy przecinek i liczbę 8. Jest jeszcze dodatkowa liczba, tym razem 0 lub 1, która mówi o tym, czy po nagraniu na kasetę ma być postawiony znacznik końca taśmy. Oznacza to, że po wpisaniu polecenia LOAD, komputer będzie przeszukiwał taśmy do chwili napotkanie znacznika. Jeśli nic nie znajdzie wyświetli komunikat FILE NOT FOUND ERROR.

Przykłady:

  • SAVE zapisuje na taśmie program bez nazwy

  • SAVE „HALO” zapisuje program na taśmie pod nazwą HALO

  • SAVE A$ zapisuje program na taśmie pod nazwą zawartą w zmiennej A$

  • SAVE „HALO”, 8 zapisuje program na dyskietce pod nazwą HALO

  • SAVE „HALO”, 1, 1 zapisuje program na taśmie pod nazwą HALO i stawia za nim znacznik końca taśmy

VERIFY

Polecenie to każe komputerowi porównanie programu znajdującego się w pamięci komputera z programem zapisanym na dyskietce/kasecie. Pozwala to sprawdzić, czy program został zapisany bez żadnych błędów. Po wpisaniu tego rozkazu zostaje porównany pierwszy program zapisany na taśmie z programem rezydującym w pamięci. Po VERIFY, możemy podać nazwę programu, z którym chcemy przeprowadzić porównanie oraz czy program znajduje się na dysku lub kasecie.

Przykłady:

  • VERIFY porównuje z następnym programem z kasety

  • VERIFY „HALO” szuka programu o nazwie HALO i z nim porównuje program z pamięci

  • VERIFY „HALO”, 8 szuka programu na dyskietce i porównuje go z programa z pamięci

Na koniec drobna uwaga: po każdym poleceniu, rozkazie, instrukcji NACISNĄĆ RETURN. W kolejnym odcinku poznamy słowa kluczowe BASIC’A i wykorzystamy wiedzę już poznaną.