forked from mist64/c64ref
-
Notifications
You must be signed in to change notification settings - Fork 0
/
c64mem_64er.txt
4095 lines (3059 loc) · 249 KB
/
c64mem_64er.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
- C64 RAM Map (64'er)
-
- Dr. H. Hauck
- Memory Map mit Wandervorschlägen
- 64'er Sonderheft 1986/07
-
- OCRed and formatted by Michael Steil <[email protected]>
-
- Corrections (typos as well as content), translations etc.
- welcome at: https://github.com/mist64/c64ref
-
------------------------------------------------------------
-
# This plain text file is formatted so that it can be automatically
# parsed in order to create cross-references etc.
# * Lines starting with "-" is top-level information. The first line
# is the title. Lines starting with "--" are separators.
# * Lines starting with "#" are internal comments.
# * Hex addresses start at column 0.
# * Symbols start at column 13.
# * The description starts at column 21.
# * All lines of the description until the first blank line are
# combined into the heading.
# * A '.' character at the end of a heading line represents a hard
# line break.
# * The remaining text is in MarkDown format.
# * All addresses are 4 digits and have a leading '$'.
# The encoding is UTF-8.
$0000 D6510 Datenrichtungsregister für Ein-/Ausgabe-Port des 6510-Mikroprozessors
$0001 Datenregister für Ein-/Ausgabe-Port des 6510-Mikroprozessors
Im Gegensatz zum Mikroprozessor des VC 20 hat der des C 64 sechs Ein-/Ausgabe-
Leitungen, die einzeln programmierbar sind und so eine direkte Verbindung
zwischen dem Mikroprozessor und der Außenwelt herstellen. Warum nur sechs
Leitungen und nicht wie üblich acht? Auf dem Chip selbst könnten acht Bit
verkraftet werden, aber es stehen nur sechs Anschlußbeine zur Verfügung.
Um trotzdem flexibel zu bleiben, ist dieses Tor zum Prozessor - zutreffend auch
»Port« genannt - in beiden Richtungen begehbar. Jede einzelne der sechs
Leitungen kann vom Programmierer auf »Eingang« oder auf »Ausgang« geschaltet
werden. Dazu dient das Datenrichtungsregister in der Speicherzelle 0.
#### Datenrichtungsreglster in Zelle 0
Wenn zum Beispiel in das Bit 4 der Zelle 0 eine 0 hineingePOKEt wird, ist die
Leitung Nummer 4 des Ports auf »Eingang« geschaltet. Es gilt für alle 6 Bit
(Nummer 0 bis 5):
* Bit auf 0 = Eingang
* Bit auf 1 = Ausgang
Beim Einschalten schreibt das Betriebssystem in dieses Register die
Dualzahl ..101111 (dezimal=47). Das heißt also, daß nur die Leitung Nummer 4
als Eingang verwendet wird, alle anderen aber als Ausgang. Warum das so ist,
sehen wir gleich. Vorher will ich aber noch erwähnen, daß im C 64 von dieser
Flexibilität des Mikroprozessor-Ports kein Gebrauch gemacht wird. Ich habe das
ganze Betriebssystem durchgesehen, aber das einzige Mal, wo die Speicherzelle 0
angesprochen wird, ist eben bei der Einschaltroutine.
Das heißt aber nicht, daß Sie, lieber Hobby-Programmierer, darauf verzichten
müssen. Ich kann mir vorstellen, daß besonders Ausgefuchste unter Ihnen durch
POKEn eines anderen Bitmusters in die Speicherzelle 0 vielseitige Befehle
erzeugen und einsetzen können.
Das wird besonders deutlich, wenn Sie jetzt sehen, mit welchen Teilen des
Computers diese sechs Leitungen verbunden sind.
#### Datenregister in Speicherzelle 1
Mit diesem Register steuert der Mikroprozessor (und damit natürlich das
Betriebssystem) die Auswahl von Speicherblöcken und den Betrieb mit dem
Kassettenrecorder. Dem Programmierer steht diese Möglichkeit über POKEn auch
zur Verfügung.
Bit 0
schaltet den Speicherbereich 40960 bis 49151 ($A000 bis $BFFF) zwischen dem
Basic-Übersetzer (Interpreter) im ROM und freiem RAM um (Normalzustand = 1).
Bit 1
schaltet den Speicherbereich 57344 bis 65535 ($E000 bis $FFFF) zwischen dem
Betriebssystem (Kernel) im ROM und freiem RAM um (Normalzustand = 1).
Bit 2
schaltet den Speicherbereich 53248 bis 57343 ($D000 bis $DFFF) zwischen
Zeichen-ROM und Ein-/Ausgabe-ROM um (Normalzustand = 1).
Bit 3
sendet serielle Daten zum Kassettenrecorder (Normalzustand = 0).
Bit 4
prüft, ob eine der Tasten des Recorders gedrückt ist, welche den Motor
einschalten (Normalzustand = 1).
Bit 5
schaltet den Motor des Recorders ein und aus (Normalzustand = 1).
#### Die RAM-ROM-Umschaltung
Sie wissen, daß Ihr C 64 deswegen so heißt, weil er 64 KByte Speicherplätze
hat. Nur stimmt das nicht! Er hat nämlich 88 KByte und müßte eigentlich C 88
heißen.
Da mit den 16 Bit der High-/Low-Byte-Methode (siehe Texteinschub Nr. 2) nur 64
KByte adressierbar sind, müssen die restlichen 22 KByte bei Bedarf eingeschoben
werden - und das machen die oben erwähnten Bit 0 bis 2 des Datenregisters.
In Bild 1 sehen Sie die drei oben erwähnten Speicherblöcke, die sowohl mit RAM
als auch mit ROM belegt sind, einer davon gleich doppelt. Ich habe ihnen
folgende Namen gegeben:
* 40960 bis 49151 ($A000 bis $BFFF) = BLOCK A
* 53248 bis 57343 ($D000 bis $DFFF) = BLOCK D
* 57344 bis 65535 ($E000 bis $FFFF) = BLOCK E
Tabelle 2 gibt Ihnen die Übersicht über die gemeinsame Wirkung der Bit 0, 1 und
2 des Datenregisters auf den jeweiligen Inhalt der Speicherblöcke.
Der Vollständigkeit halber muß ich hier noch erwähnen, daß neben den drei
ersten Bits der Speicherzelle 1 noch zwei weitere Signale die RAM/ROM-
Umschaltung beeinflussen. Es sind das die Leitungen auf Pin 8 und 9 des
Erweiterungssteckers (GAME und EXROM), welche durch Spiel- und Programmodule
benutzt werden. Eine genaue Beschreibung der dadurch erzeugten sinnvollen
Speicherkombinationen finden Sie in dem Buch »64 Intern« von Data Becker ab
Seite 14. Zwei Anwendungsbeispiele dieser Umschaltung finden Sie im
Texteinschub Nr. 3 »Manipuliertes Basic«.
#### Betrieb des Kassettenrecorders
Bit 3, 4 und 5 regeln, wie schon gesagt, den Betrieb des Kassettenrecorders.
Zu Bit 3 ist oben schon das Notwendige gesagt.
Bit 4 ist im Normalzustand auf 1, »normal« heißt hier, solange keine der Motor-
Tasten der Datasette (PLAY, REWIND, FAST FORWARD) gedrückt ist. Zur Probe:
10 X=PEEK(1)
funktioniert das alles nur, wenn - wie im »Normalfall« - das Bit 4 des
Datenrichtungsregisters (Speicherzelle 0) auf 0 (Eingang) steht.
Bit 5 schaltet den Motor der Datasette ein und aus. Es bietet sich an, damit
per Programm die Datasette zu schalten - wenn so etwas nützlich ist. Leider ist
dieses Bit etwas schwieriger zu handhaben, da es in der Interrupt-Routine des
Betriebssystems eine Rolle spielt.
Die Tasten der Datasette werden nämlich 60mal in der Sekunde abgefragt. Wenn
keine Taste gedrückt ist, setzt das Betriebssystem sowohl das sogenannte
»Interlock«-Register in Speicherzelle 192 auf 0 als auch Bit 5 der Zelle 1 auf
1, wodurch der Motor ausgeschaltet wird beziehungsweise bleibt. Da kann man
nicht dagegen an. Wir haben nur eine Chance, wenn eine Taste bereits gedrückt
ist und der Kassettenmotor schon läuft.
Dann nämlich können wir zuerst das Interlock-Register mit einem Wert größer als
0 lahmlegen:
POKE 192,255
Jetzt läßt sich der Motor der Datasette mit Bit 5 steuern: POKE 1,39
beziehungsweise POKE 1,PEEK(1) OR 32 schaltet den Motor aus,
POKE 1,7 beziehungsweise POKE 1,PEEK(1) AND 31 schaltet den Motor ein.
Das Interlock-Register in Speicherzelle 192 werde ich später noch einmal
erwähnen, da es seine Funktion auch beim VC 20 ausübt, allerdings mit anderen
Ein-/Ausgangs-Ports. Das ist alles, was zur Speicherzelle 1 zu sagen ist.
Ab Speicherzelle 3 bis zur Speicherzelle 672 gelten alleAngaben sowohl für den
C 64 als auch für den VC 20, zumindest was die Bedeutung der Zellen betrifft.
Ihr Inhalt kann entsprechend der verschiedenen Adressen der Betriebssysteme
voneinander abweichen. Wie üblich werde ich natürlich jeweils darauf aufmerksam
machen.
$0002 unbenutzt
$0003-$0004 Vektor auf die Routine zur Umwandlung einer Gleitkommazahl in eine ganze Zahl
mit Vorzeichen
In diesen beiden Speicherzellen steht also ein Vektor. Was das ist, wird im
Texteinschub Nr. 4 näher erläutert. Beim VC 20 deutet dieser Vektor auf die
Adresse 63674 ($D1AA), beim C 64 auf 45482 ($B1AA). Sie können das mit
PRINT PEEK (3)+256*PEEK (4)
leicht nachprüfen. Ab diesen Adressen beginnt im Basic-Übersetzer (Interpreter)
ein Programm, welches - natürlich in Maschinensprache - eine Gleitkommazahl in
eine ganze Zahl umwandelt.
Diejenigen Leser, die mit Gleitkommazahlen nicht so vertraut sind, möchte ich
auf den Texteinschub Nr. 6 verweisen. Er ist nur eine kleine Einführung. Eine
detaillierte Beschreibung finden Sie im Assemblerkurs (Teil 8) von Heimo
Ponnath (Ausgabe 4/85) beziehungsweise im 64er-Sonderheft 8/85, ab Seite 42.
Dieses Umwandlungsprogramm steht nicht nur den Maschinen, sondern auch den
Basic-Programmierern zur Verfügung, allerdings nur über den USR-Befehl und da
auch nur, wenn der »Floating Point Accumulator« #1 (FAC1) in den besagten
Adressen 97 bis 102 mitbenutzt wird. Ich verschiebe daher alle weiteren Details
auf unsere Ankunft bei diesen Speicherzellen.
$0005-$0006 Vektor auf die Routine zur Umwandlung einer ganzen Zahl in eine Gleitkommazahl
Dieses Programm ist die Umkehrung der oberen Routine. Sie beginnt beim VC 20 ab
Speicherzelle 54161 ($D391), beim C 64 ab 45969 ($B391). Da hier prinzipiell
dasselbe gilt wie oben, möchte ich nur kurz den Vorteil beleuchten, den
derartige Vektoren haben. Eigentlich könnten wir direkt auf die im Vektor
enthaltenen Adressen springen - wenn wir sie kennen.
Ein Sprung auf die Adresse des Vektors erlaubt uns jedoch immer die völlige
Ignoranz seines Inhalts - und Commodore erlaubt die Änderung der Adressen im
Basic-Übersetzer, wie es ja beim C 64 gegenüber dem VC 20 auch gemacht worden
ist, ohne daß vorhandene Programme umgeschrieben werden müssen.
$0007 Suchzeichen zur Prüfung von Texteingaben in Basic
Diese Speicherzelle wird viel von denjenigen Basic-Routinen als
Zwischenspeicher benutzt, die den direkt eingegebenen Text absuchen, um
Steuerzeichen (Gänsefüße, Kommata, Doppelpunkte und die Zeilenbeendigung durch
die RETURN-Taste) rechtzeitig zu erkennen. Normalerweise wird in der Zelle 7
der ASCII-Wert dieser Zeichen abgelegt. Die Speicherzelle 7 wird aber auch von
anderen Basic-Routinen benutzt. Sie ist daher für den Programmierer praktisch
nicht zu verwerten.
$0008 Suchzeichen speziell für Befehlsende und Gänsefüße
Wie Speicherzelle 7 dient auch die Zelle 8 als Zwischenspeicher für Basic-
Texteingabe und zwar während der Umwandlung von Basic-Befehlen in den vom
Computer verwendeten Befehlscode (Tokens). Die Speicherzelle 8 ist in Basic
nicht verwertbar.
$0009 Spaltenposition des Cursors vor dem letzten TAB- oder SPC-Befehl
Speicherzelle 9 wird von den Basic-Befehlen TAB und SPC verwendet. Vor ihrer
Ausführung wird die Nummer der Spalte, in der sich der Cursor befindet, aus der
Speicherzelle 211 ($00D3) nach 9 gebracht, von wo sie geholt wird, um die Position
des Cursors nach der Ausführung von TAB und SPC auszurechnen.
Diese komplizierte Erklärung können wir durch Ausprobieren deutlicher machen.
Dazu PRINTen wir 16mal den Buchstaben X hintereinander (Semikolon!), allerdings
mit SPC (2) jeweils um 2 Spalten versetzt.
10 FOR I=0 TO 15
20 PRINT SPC (2) "X";
30 PRINT PEEK (9);
40 NEXT I
Nach jedem X wird durch Zeile 30 die »alte« Cursor-Spaltenposition ausgedruckt
und zwar in derselben Zeile, ausgelöst durch das Semikolon. Dadurch erhöht sich
laufend die in Speicherzelle 9 stehende Positionsangabe des Cursors. Wir
erhalten folgenden Ausdruck:
..X.0...X.6...X.12...X.19...X.26...X.33...X.40...X.47.
..X.54...X.61...X.68...X.75...X.82...X.1...X.7...X.13
Sie können die Positionsnummer nachrechnen. Berücksichtigen Sie aber dabei, daß
bei PRINT vor und nach jeder Zahl eine Stelle frei bleibt, die erste für das
Vorzeichen, die zweite wegen des Abstandes.
Wichtig ist außerdem, daß die maximal mögliche Spaltenzahl nicht die
Bildschirmspaltenzahl, sondern die »logische« Spaltenzahl ist, also 88 beim VC
20 und 80 beim C 64.
Wir können die Cursorposition in Adresse 9 auch abfragen und ein Programm damit
steuern. Fügen Sie einfach in das obige Programm die folgende Zeile 35 ein:
35 IF PEEK (9)=33 THEN PRINT "END": END
Sobald Position 33 erreicht ist, bleibt das Programm stehen.
$000A Flagge für LOAD oder VERIFY
In Zelle 10 steht eine 0, wenn geladen wird und eine 1 bei einem VERIFY. Warum
das so ist, will ich kurz erläutern:
Die Basic-Routinen für LOAD beziehungsweise für VERIFY sind völlig identisch.
Was das Betriebssystem hinterher daraus machen muß, ist natürlich
unterschiedlich. Das Basic erspart sich eine doppelte Routine, zeigt aber mit
der Flagge in Speicherzelle 10 den Unterschied an.
Erwähnenswert ist noch, daß das Betriebssystem in einer Art Nationalismus seine
eigene Flagge aufzieht: Den Unterschied zwischen LOAD und VERIFY speichert es
seinerseits in Zelle 147 ($0093) ab. Soweit ich es sehen kann, sind Inhalt und
Bedeutung beider Speicherzellen völlig identisch.
Ich habe für Sie zwar kein Kochrezept zur Anwendung der LOAD-VERIFY-Flagge in
einem Programm vorrätig, möchte Sie aber trotzdem ein bißchen zum Spielen
anregen. Um meine Erklärung nachzuvollziehen, tippen Sie bitte direkt LOAD ein.
Den Ladevorgang brechen Sie mit der STOP-Taste ab und fragen dann den Inhalt
der Zelle 10 ab mit
PRINT PEEK (10)
Wir erhalten eine 0.
Wiederholen Sie bitte diesen Vorgang, aber mit VERIFY. Wir erhalten jetzt eine
1 - Quod erat demonstrandum.
Wir können auch in die Zelle 10 hineinPOKEn. Die »Wachablösung« zwischen Basic
und Betriebssystem unter Hissen der Flagge in Zelle 10 findet beim VC 20 in der
Speicherzelle 57705, beim C 64 in 57708 statt. Bevor wir diese Maschinenroutine
mit SYS 57705 (SYS 57708) starten, geben wir mit dem Inhalt der Speicherzelle
10 an, ob es ein LOAD oder ein VERIFY sein soll.
Legen Sie ein Band mit Programm in die Datasette. Um ein LOAD zu erzeugen,
geben wir direkt ein:
POKE 10,0:SYS 57705
(POKE 10,0:SYS 57708)
Entsprechend der Anweisung auf dem Bildschirm drücken Sie PLAY, und das
Auffinden des ersten Programms wird mit LOAD gemeldet. Machen Sie das Ganze
noch einmal, diesmal aber POKEn Sie bitte eine 1 in die Zelle 10. Jetzt meldet
das Betriebssystem das Auffinden des Programms mit VERIFY.
Wie gesagt, vielleicht fällt Ihnen eine Anwendung dafür ein.
$000B Flagge für den Eingabepuffer/Anzahl der Dimensionen von Zahlenfeldern (Arrays)
Alle Buchstaben und Zeichen, die mit der Tastatur direkt eingetippt werden,
kommen in einen Eingabe-Pufferspeicher.
Er beginnt ab Speicherzelle 512 ($0200). Sobald die RETURN-Taste gedrückt wird,
wandelt eine Routine des Basic-Übersetzers den Text in Codezahlen (Tokens) um.
Diese Routine und eine andere, welche die Zeilen eines Programms
aneinanderhängt, verwenden die Zelle 11 als Zwischenspeicher.
Sobald die Textumwandlung beendet ist, steht in Zelle 11 eine Zahl, die die
Länge der Token-Zeile angibt.
Die Zelle 11 wird außerdem noch von den Basic-Routinen benutzt, die ein Feld
(Array) aufbauen oder ein bestimmtes Element in einem Array suchen. Was ein
Feld oder Array ist, finden Sie in den Commodore-Handbüchern gut beschrieben.
Außerdem gehe ich bei der Behandlung der Speicherzellen 47 bis 50 näher darauf
ein.
Diese Routinen also verwenden die Speicherzelle 11, um die Anzahl der
verlangten DIMensionen und den für ein neu aufgebautes Feld nötigen
Speicherbedarf zu berechnen.
$000C Flagge für Basic-Routinen, die ein Feld (Array) suchen beziehungsweise aufbauen
Diese Speicherzelle wird von den Basic-Routinen als Zwischenspeicher benutzt,
die feststellen, ob eine Variable ein Feld (Array) ist, ob das Feld bereits
DIMensioniert worden ist, oder ob ein neues Feld die unDIMensionierte Zahl von
11 Elementen hat.
$000D Flagge zur Bestimmung des Datentyps (Zeichenkette/String oder Zahl)
Diese Flagge zeigt den Routinen des Basic-Übersetzers an, ob es sich bei den
zur Verarbeitung anstehenden Daten um einen String oder um Zahlenwerte handelt.
Zeigt die Flagge 255 ($FF), ist es ein String. Bei 0 handelt es sich um Zahlen.
Diese Bestimmung erfolgt jedesmal, wenn eine Variable definiert oder gesucht
wird. Diese Flagge kann leider nicht durch ein Basic-Programm abgefragt werden.
$000E Flagge zur Bestimmung des Zahlentyps (Ganze Zahl oder Gleitkommazahl)
Sobald durch die Flagge in der vorherigen Zelle 13 eine Zahl signalisiert wird,
steht hier die Zahl 128 ($80), wenn es sich um eine ganze Zahl handelt, während
eine 0 die Zahl als Gleitkommazahl identifiziert.
Damit wollen wir ein bißchen experimentieren. Zeile 10 definiert eine
Gleitkommazahl, Zeile 20 druckt sie und die Flagge aus Zelle 14 aus.
10 A=13.41
20 PRINT A,PEEK (14)
Wir erhalten dieZahl 13.41 und als Flagge eine 0.
30 B=INT (A)
40 PRINT B,PEEK (14)
INT bildet die ganze Zahl von 13.41. Also müßte die Flagge in Zelle 14 auf 128
stehen. Weit gefehlt! Da intern auch die 13 als Gleitkommazahl berechnet wird,
erhalten wir immer noch eine 0.
50 B%=A
60 PRINT B%,PEEK (14)
Erst die Definition der Variablen B als ganze Zahl (mit %) ergibt die Flagge
128.
70 D=16*B%
80 PRINT D,PEEK (14)
Die Multiplikation einer ganzen Zahl mit der Ganzzahl-Variablen B% fällt in
dieselbe Kategorie wie Zeile 30 oben, da die Verarbeitung als Gleitkommazahl
erfolgt. Also erhalten wir zu Recht eine 0. Erst wenn D als ganze Zahl (Zeile
90) ausgewiesen wird, steht die Flagge wieder auf 128:
90 D%=16*B%
100 PRINT D%, PEEK (14)
$000F Flagge bei LIST, Garbage Collection und Textumwandlung
Die Routine des LIST-Befehls muß unterscheiden zwischen Basic-Befehlen und
normalem Text. Wenn eine Zeichenkette durch ein »Gänsefüßchen« identifiziert
worden ist, wird die Flagge gesetzt, und der Text wird ausgedruckt.
Unter »Garbage Collection« (Müllabfuhr) wird die Routine des Betriebssystems
verstanden, welche zu bestimmten Anlässen im Variablenspeicher alle nicht mehr
benötigten Strings entfernt, um Platz zu schaffen. Dabei wird eine Flagge in
Zelle 15 gesetzt, die anzeigt, daß eine Müllabfuhr bereits stattgefunden hat.
Wenn bei der Speicherung eines neuen Strings zu wenig Speicherplatz vorhanden
ist, wird bei der Flagge nachgesehen, ob gerade vorher schon durch die
Müllabfuhr (Garbage Collection) der Speicher entrümpelt worden ist. Falls das
der Fall ist, wird OUT OF MEMORY angezeigt, falls nicht, wird eine Müllabfuhr
durchgeführt.
Schließlich wird Zelle 15 auch bei der Umwandlung von Basic-Befehlen in
internen Codezahlen (Tokens) eingesetzt.
$0010 Flagge zur Anzeige eines Variablen-Feldes oder einer selbstdefinierten Funktion
Im Basic-Übersetzer gibt es eine Routine, die den Speicher absucht, ob es eine
Variable mit bestimmten Namen bereits gibt. Wenn diese mit einer Klammer
beginnt, wird die Flagge in Zelle 16 gesetzt, um anzuzeigen, daß es sich um
eine Array-Variable oder um eine mit DEF FN selbstdefinierte Funktion handelt.
$0011 Flagge für INPUT, GET oder READ
Die Basic-Routinen für INPUT, GET und READ sind zum großen Teil identisch. Um
Speicherplatz zu sparen, verwendet der Basic-Übersetzer die identischen Teile
nur einmal. Um in die nichtidentischen Teile verzweigen zu können, wird in
Zelle 17 angezeigt, um welchen der drei Befehle es sich gerade handelt. Die
Flagge steht auf 0 für INPUT, auf 64 ($40) für GET und auf 152 ($98) für READ.
Mit dem folgenden kleinen Programm können wir das leicht nachprüfen.
10 DATA 3
20 READ A
30 PRINT PEEK (17)
40 INPUT B
50 PRINT PEEK (17)
60 GET C$:IF C$= " "THEN 60
70 PRINT PEEK (17)
Zeile 10 und 20, 40 sowie 60 sind Anwendungen der drei zur Debatte stehenden
Basic-Befehle. Nach der Durchführung jedes Befehls wird in den Zeilen 30, 50
und 70 die jeweilige Flagge ausgelesen.
Nach RUN erhalten wir als Resultat der Zeile 20 die Zahl 152, als Resultat von
Zeile 30 die INPUT-Aufforderung mit Fragezeichen. Geben Sie irgendeine Zahl und
RETURN ein. Wir erhalten so die 0. Die GET-Schleife in Zeile 40 wartet auf
einen Tastendruck, dann erhalten wir 64.
$0012 TANSGN Flagge für Vorzeichen bei SIN, COS und TAN
Die Routinen des Basic-Übersetzers (Interpreter), welche die drei
trigonometrischen Funktionen SIN, COS und TAN berechnen, verwenden die
Speicherzelle 18 zur Bestimmung des Vorzeichens.
Zur Erinnerung: Die trigonometrischen Funktionen haben in den vier »Quadranten«
des Kreises (0-90, 90-180, 180-270, 270-360 Grad) nicht unbedingt dieselben
Vorzeichen. Die Vorzeichen ändern sich allerdings nur an den Grenzen der
Quadranten, wie in Bild 2 zu sehen ist. Die Flagge in Zelle 18 gibt das
Vorzeichen nicht direkt an, sondern auf Umwegen. Die Darstellung ist in der
folgenden Tabelle zusammengefaßt.
Dabei bedeutet »gleich«: 0-0-0-0 oder 255-255-255 »Wechsel«: 0-255-0-255 Da die
Erklärung mit »gleich« beziehungsweise »Wechsel« nicht gerade einleuchtend ist,
schlage ich vor, daß Sie sich das Ganze mit dem folgenden kleinen Programm
selbst anschauen, welches für viele Werte des Winkels im Bogenmaß - und in
kleinen Schritten - den Wert der Flagge, daneben den Winkel I und den Wert der
Funktion mit Vorzeichen ausdruckt.
10 FOR I=0 TO 10 STEP 0.01
20 PRINT PEEK(18);INT (I*100)/100;SIN(I):NEXT
Diese etwas umständliche Art, den Wert von I auszudrucken, vermeidet
Rundungsfehler und begrenzt den Ausdruck auf zwei Dezimalstellen. Wenn Sie die
Winkelwerte von I in Graden ausgedruckt haben wollen, können Sie eine ändere
Zeile 20 verwenden, welche die Umrechnungsformel vom Bogenmaß in Grade
verwendet: Winkel in Grad = Winkel im Bogenmaß * 180/π
20 PRINT PEEK(18);INT(I*180/π);SIN(I):NEXT
Statt SIN können Sie genauso gut COS und TAN einsetzen.
In Bild 2 sind nicht nur die Kurven und die Bereiche der Vorzeichen, sondern
auch die Winkelbereiche sowohl im Bogenmaß als auch in Graden dargestellt.
$0012 DOMASK Flagge bei Vergleich
Die Speicherzelle 18 wird auch noch von anderen Routinen des Basic-Interpreters
beansprucht und zwar von allen, die einen Vergleich wie <, >, >= und so weiter
durchführen. Entsprechend der Art des Vergleichs steht dann in der Zelle 18
eine Ziffer von 0 bis 6.
Das folgende Programm macht das deutlich.
10 A=2
20 FOR I=1 TO 3
30 IF I=A THEN PRINT I; PEEK(18); "="
40 IF I<>A THEN PRINT I; PEEK(18); "><"
50 IF I>A THEN PRINT I; PEEK(18); ">"
60 IF I<A THEN PRINT I; PEEK(18); "<"
70 IF I>=A THEN PRINT I; PEEK(18); ">="
80 IF I<=A THEN PRINT I; PEEK(18); "<="
90 IF I<A OR I=A THEN PRINT I; PEEK(18); "< OR ="
100 NEXT I
Kurz zur Erklärung dieser Zeilen: In der FOR..NEXT-Schleife wird die Variable I
mit der Konstanten A=2 verglichen. In den Zeilen 30 bis 90 werden alle
möglichen Vergleichsoperatoren durchgeprüft. Jeder der zutrifft, druckt den
Wert von I, den Wert der dann in Zelle 18 stehenden Flagge und schließlich den
Vergleichsoperator aus. Aus dem Resultat dieses Programms läßt sich folgende
Tabelle zusammenstellen:
| Vergleich | Flagge in 18 |
|-----------|--------------|
| < OR = | 0 |
| > OR = | 0 |
| > | 1 |
| = | 2 |
| >= | 3 |
| < | 4 |
| <> | 5 |
| <= | 6 |
Sie sehen, die Flagge für die kombinierten Vergleichsoperatoren entspricht der
Summe ihrer Einzelwerte. Nur die Verknüpfung über OR nicht, denn die ergibt 0.
$0013 Flagge zur Kennzeichnung des laufenden Ein-/Ausgabegerätes
Immer dann, wenn von Basic Daten ein- oder ausgegeben werden, schaut die
entsprechende Routine des Übersetzers in Zelle 19 nach, um welches
Peripheriegerät es sich handelt. Zur Debatte stehen Tastatur, Datasette, RS232-
User-Port, Bildschirm, Drucker und Floppy-Laufwerk.
Die Flagge ihrerseits ist ausschlaggebend für die feinen Unterschiede, wie zum
Beispiel das Fragezeichen, bei Eingabe von der Tastatur (INPUT) oder die
Anweisung »Press Play on Tape« bei Eingabe von der Datasette.
Beim Einschalten des Rechners setzt die Initialisierungsroutine des
Betriebssystems, die beim VC 20 ab Adresse 58276 ($E3A4), beim C 64 ab 58303
($E3BF) beginnt, die Flagge in Zelle 19auf 0. Die Null bedeutet Eingabe über
Tastatur und Ausgabe über Bildschirm.
Wenn Sie einen Disassembler haben, drucken Sie doch einmal das Assemblerlisting
aus. Sie werden in Adresse 58324/58325 ($E3D4/$E3D5), beim C 64 in 58354/58355
($E3F2/$E3F3) den Befehl finden, der eine Null nach Zelle 19 ($0013) bringt.
Immer dann, wenn ein Programm nicht Tastatur und Bildschirm, sondern eines der
oben genannten anderen Peripheriegeräte anspricht (indem mit OPEN.... eine
Datei = Logical File eröffnet wird), wird in Zelle 19 die Nummer der gerade
bearbeiteten Datei eingetragen, mit den bereits beschriebenen Konsequenzen.
Ich will hier nicht weiter darauf eingehen, da wir den Inhalt von Zelle 19
selbst nicht auslesen können. Er wird nämlich immer gleich wieder auf Null
gesetzt.
Wir können ihn aber durch POKE verändern. Durch POKE 19,1 gaukeln wir dem
Rechner vor, daß Ein- und Ausgabe über »externe« Geräte läuft, selbst wenn nur
die Tastatur und der Bildschirm betrieben werden.
Wenn zum Beispiel der Rechner der Meinung ist, daß ein INPUT von der Datasette
kommt, druckt er kein Fragezeichen aus; auch kein EXTRA IGNORED als
Fehlermeldung bei zu zahlreicher Eingabe und das alleinige Drücken der RETURN-
Taste ignoriert er auch, im Gegensatz zum »normalen« INPUT Probieren Sie es
aus:
10 INPUT "TEST"; A$
20 PRINT A$
In diesem Normalfall erscheint nach RUN darunter die Aufforderung TEST?
Eine Eingabe, zum Beispiel XX, erscheint mit einem Abstand daneben, und nach
RETURN wird XX an den Anfang der nächsten Zeile gedruckt. Alle falschen
Eingaben werden mit den üblichen Fehlermeldungen quittiert.
Jetzt fügen wir ein:
5 POKE 19,1
Nach RUN erscheint wieder die Aufforderung TEST, aber ohne Fragezeichen. Die
Eingabe XX wird ohne Abstand daneben gesetzt und nach RETURN mit einem Abstand
in derselben Zeile weitergeschrieben.
Das Drücken der RETURN-Taste setzt den Cursor nicht wie üblich in die nächste
Zeile, sondern schiebt ihn in derselben Zeile weiter.
Diesen zusätzlichen Effekt muß man beachten, da er sehr störend für den Verlauf
eines Programms sein kann.
Man kann ihn natürlich auch nutzbringend einsetzen, hat er doch die Eigenschaft
eines automatischen »Cursor UP«. Eine pfiffige Anwendung dieser Art wurde von
Brad Templeton für den PET erfunden und ist von Jim Butterfield für eine MERGE-
Routine mit dem Namen »Magic Merge« veröffentlicht worden.
Da diese Routine aber primär auf der Eigenschaft der Speicherzelle 153 basiert,
werde ich sie dann erläutern, sobald wir bei der Zelle 153 angelangt sind.
Zurück zur Flagge in Zelle 19.
Umgekehrt können wir POKE 19,0 leider nicht nutzen, da die betroffenen Befehle
GET, GET#, INPUT, INPUT# und PRINT # die Flagge sofort auf den richtigen Wert
setzen. Nur PRINT und LIST tun das nicht, wie wir bei dem PRINT-Befehl oben ja
gesehen haben.
$0014-$0015 Zeilennummer für LIST, GOTO, GOSUB und ON, Zeiger der Adresse bei PEEK, POKE,
SYS und WAIT
In diesen Speicherzellen wird die Zeilennummer der Sprungbefehle GOTO, ON..GOTO
und GOSUB sowie die Zeilenangabe beim LIST-Befehl gespeichert. Da die Werte bis
maximal 65535 gehen können, braucht der Computer 2 Byte zur High-/Low-Byte-
Darstellung.
Die GOTO-Routine (im VC 20 ab 51360 = $C8A0, im C 64 ab 43168 = $A8A0)
vergleicht die Zahl in 20 und 21 mit der laufenden Zeilenzahl. Wenn sie kleiner
ist, wird ab der ersten Zeile des Programms gesucht. Ist sie aber größer, dann
beginnt die Suche ab der laufenden Zeilenzahl. Die Suche geht solange, bis die
in 20 und 21 angegebene Zeilenzahl gefunden ist. Dann fährt das Programm mit
dieser Zeile fort.
LIST speichert in 20 und 21 die höchste auszulistende Zeilennummer ab, falls
keine Angabe beim LISTen gegeben worden ist, den Wert 65535 ($FFFF).
Die Befehle PEEK, POKE, SYS und WAIT verwenden diese Speicherzellen zur Angabe
der Adressen, die dem Befehl immer folgen müssen.
Leider können wir die Speicherzellen 20 und 21 mit Basic-Programmen nicht
bearbeiten; ihr Inhalt wird immer gleich auf 20 zurückgesetzt.
$0016 Zeiger auf den nächsten freien Speicherplatz im »Temporary String Descriptor
Stack«
Dieser Zeiger bezieht sich in seiner Wirkung auf die übernächsten
Speicherzellen 25 bis 33 ($0019 bis $0021).
Diese werden als Stapelspeicher (Stack) für Angaben über vorläufige
Zeichenketten - auf englisch »Temporary String Descriptor« - verwendet.
Die Speicherzelle 22 ($0016) ihrerseits enthält einen Zeiger auf den jeweils
nächsten verfügbaren Platz in diesem Speicher ab Zelle 25. Da er eine Kapazität
von 3 * 3 Byte hat, zeigt der Zeiger auf die Zelle 25 ($0019), wenn er leer ist.
Bei einem Eintrag zeigt er auf 28 ($001C), bei zwei Einträgen auf 31 ($001F) und
schließlich auf 34 ($0022), wenn der Speicher voll ist.
Eine Zeichenkette ist dann »vorläufig«, wenn sie noch nicht einer
Stringvariablen zugeordnet worden ist, zum Beispiel »Mahlzeit« in dem Basic-
Befehl
PRINT "MAHLZEIT".
Beim Einschalten setzt das Betriebssystem mit der Einschaltroutine ab Adresse
58303 ($E3BF) im C 64, beim VC 20 ab 58276 ($E3A4) den Zeigerauf 25. Die
Stringverwaltungsroutine ab 46215 ($B487) im C 64 beziehungsweise ab 54407
($D487) im VC 20 fragt bei String-Eingaben die Flagge ab. Nach jeder Eintragung
in den Speicher ab Zelle 25 wird der Zeiger um 3 weitergesetzt.
Sie können die Leerflagge 25 mit
PRINT PEEK (22)
leicht nachprüfen.
Die anderen Eintragungen können nicht nachgeprüft werden, weil sie sofort auf
25 zurückgesetzt werden.
Wir können sie aber durch POKE beeinflussen; ob das sinnvoll ist, ist eine
andere Frage.
10 POKE 22,34
20 PRINT "MAHLZEIT"
Die Zahl 34 in Zelle 22 sagt dem Programm, daß der Speicher ab Zelle 25 voll
ist. Wir bekommen statt der MAHLZEIT eine Fehlermeldung serviert.
Mit einem POKE-Befehl, der als Argument die für den vorgesehenen Zweck
ungültige Zahl 35 verwendet:
POKE 22,35
erreichen wir allerdings zwei interessante »Dreckeffekte«. Zum einen
unterdrückt der Befehl die Ausgabe des READY, zum anderen aber bewirkt er, daß
bei LIST ein Listing ohne Zeilennummern ausgedruckt wird, sowohl auf dem
Bildschirm als auch mit dem Drucker.
#### Das billigste editierfähige Textverarbeitungssystem
Die Idee dazu habe ich von Mike Apsey’s Hinweis in »Commodore User« Juli 1984.
Mit Zeilennummern versehen, läßt sich jeder beliebige Text schreiben,
verbessern, verschieben, abspeichern, aber nicht RUNen!!
Der POKE-Befehl von oben (POKE 22,35) gefolgt von einem CMD und LIST, druckt
dann alles brav als reinen Text aus. Die maximale Zeilenlänge entspricht der
Zeilenlänge des jeweiligen Computers.
Probieren Sie es aus:
10 DER COMPUTER BIETET IN DER
20 DATENFERNÜBERTRAGUNG
30 UNGEAHNTE MÖGLICHKEITEN.
40 ABER DIE GEFAHR
50 USW. USW.
60:
Jede Zeile wird mit der RETURN-Taste abgeschlossen. Damit auch alles gedruckt
wird, muß - zumindest bei meinem Drucker (1526) - eine »Leerzeile« folgen
(Zeile 60). Mit
POKE 22,35:OPEN 1,4:CMD 1:LIST
wird der Text ohne Zeilennummern ausgedruckt. Sie können ihn vorher nach
Belieben verändern.
Wie gesagt, nur nicht mit RUN starten, denn das bringt unweigerlich eine
Fehlermeldung.
$0017-$0018 Zeiger auf die Adresse der letzten Zeichenkette im »Temporary String Stack«
Der Inhalt dieser 2 Byte zeigt auf den zuletzt benutzten Speicherplatz
Innerhalb der Adresse 22 bis 33. Das heißt, daß der Wert in 23 ($0017) immer um 3
kleiner ist als der in 22 ($0016), während der Wert in 24 ($0018) eine Null ist.
$0019-$0021 Stapelspeicher für Angaben über vorläufige Zeichenketten
Das ist also der Speicherbereich, von dem in den beiden vorigen Abschnitten
dauernd die Rede war. Ich gebe zu, »Descriptor Stack for Temporary Strings«
drückt die Sache präziser aus als der deutsche Text.
Die Bedeutung eines »vorläufigen« Strings habe ich oben in der Beschreibung der
Speicherzelle 22 erklärt.
Was ein Stapelspeicher (Stack) ist, entnehmen Sie bitte dem Texteinschub 6.
Jeder der 3 Byte langen Angaben im Stack von 22 bis 33 enthält die Länge sowie
die Anfangs- und Endadressen eines vorläufigen Strings, ausgedruckt als
Verschiebung im Basic-Speicherbereich.
$0022-$0025 Verschiedene Zwischenspeicher
Diese vier Speicherzellen werden vom Basic-Übersetzer (Interpreter) für
verschiedene Zwischenergebnisse und Flaggen benutzt, die aber dem Programmierer
nichts nutzen.
$0026-$002A Arbeitsspeicher für arithmetische Operationen
Diese Speicherzellen werden von den Basic-Routinen bei der Multiplikation und
Division als »Notizblatt« verwendet. Auch die Routinen, welche die
erforderliche Speichergröße beim Definieren eines Zahlenfeldes (Array)
ausrechnen, benutzen diesen Bereich.
$002B-$002C Zeiger auf den Anfang der Basic-Programme im Speicher
Dieser Zeiger, in der Low-/High-Byte-Darstellung, gibt dem Basic-Übersetzer an,
ab welcher Speicherzelle das Basic-Programm beginnt. Normalerweise ist diese
Adresse fest vorgegeben. Beim C 64 zum Beispiel zeigt der Zeiger auf 2049
($0801). Beim VC 20 ist die Lage schon schwieriger, denn der Speicherbeginn
hängt davon ab, welche Speichererweiterung eingesetzt ist. Die folgende Tabelle
3 gibt darüber Auskunft.
Tabelle 3: Beginn des Programmspeichers
| C 64 | 2049 ($0801) |
|---------------|--------------|
| VC 20 (GV) | 4097 ($1001) |
| VC 20 (+3 K) | 1025 ($0401) |
| VC 20 (+ 8 K) | 4609 ($1201) |
Mit dem Befehl
PRINT PEEK (43) + PEEK (44)*256
läßt sich der jeweilige Beginn des Programmspeichers leicht feststellen. Mit
einem POKE-Befehl kann der Programmierer diese Anfangsadresse verändern. Wozu
das gut ist, fragen Sie?
##### Anwendung #1:
Nun, wenn Sie zum Beispiel ein Maschinenprogramm mit einem Basic-Programm
gemeinsam betreiben wollen, brauchen Sie einen Speicherbereich für das
Maschinenprogramm, der vom Basic-Programm nicht belegt wird. Wir sprechen vom
»Schützen des Maschinenprogramms vor dem Überschreiben durch das Basic«. Der
Speicherbereich eines Maschinenprogramms ist immer bekannt. Nach seinem letzten
Speicherplatz kann das Basic-Programm beginnen.
Die Verschiebung der Anfangsadresse erfolgt in vier Schritten:
1. Schritt: In den Speicherplatz vor dem neuen Basic-Bereich muß eine Null
gePOKEt werden. Die Null dient zum Abgrenzen.
2. Schritt: Die Adresse der ersten Speicherzelle wird in die Low-/High-Byte-
Darstellung umgerechnet. Ich verweise dazu auf die Erklärung dieses Vorgangs
im Texteinschub Nr. 1.
3. Schritt: Das Low-Byte wird in die Speicherzelle 43, das High-Byte in die
Zelle 44 gePOKEt.
4. Schritt: Die Operation muß unbedingt mit dem Befehl NEW abgeschlossen
werden, um sicherzustellen, daß auch alle anderen Zeiger auf ihren
Anfangszustand gesetzt werden.
Im folgenden kleinen Programm wird angenommen, daß der Speicher bis zur Adresse
6000 ($1388) durch ein Maschinenprogramm belegt ist. Das Basic-Programm kann
daher ab 5002 ($138A) anfangen, denn in 5001 muß ja eine Null stehen. Die
Adresse 5002 teilt sich auf in ein High-Byte von INT (5002/256) = 19 und ein
Low-Byte von 5002-(19*256) = 138.
10 POKE 5001,0
20 POKE 43,138
30 POKE 44,19
40 NEW
Der Effekt einer solchen »Verbiegung« des Zeigers in 43 und 44 wird im
Texteinschub Nr. 7 »Der sichtbare Basic-Speicher« demonstriert.
Neben der oben erwähnten Anwendung der Zeigerverbiegung gibt es noch andere
Möglichkeiten:
##### Anwendung #2:
Christoph Sauer hat in seinem Kurs »Der gläserne VC 20« in Ausgabe 10/84 auf
Seite 158 gezeigt, wie man mehrere Programme gleichzeitig im Speicher
unterbringen und zwischen ihnen umschalten kann.
##### Anwendung #3:
Man kann zwei oder mehrere unabhängige Programme genau hintereinander in den
Speicher bringen, um sie aneinander zu hängen, was dem im Commodore-Basic
fehlenden Befehl MERGE entspricht. Dabei dürfen die Zeilennummern sich
allerdings nicht überschneiden.
##### Anwendung #4:
Durch Hinaufschieben des Basic-Bereichs kann Platz geschaffen werden für
selbstdefinierte Zeichen oder hochauflösende Grafik.
Die Speicherzellen-Paare von 45, 46 bis 55, 56 ($0037 bis $0038) zeigen auf weitere
für Basic-Programme wichtige Speicherbereiche, die deswegen gemeinsam
betrachtet werden sollten. Bild 5 stellt den Zusammenhang grafisch dar. In
diesem Bereich werden alle Variablen eines Programms gespeichert. Zur
Erinnerung:
Wir unterscheiden zwischen »normalen« Variablen (numerische und String-
Variable) und Feld-Variablen (Arrays). Dabei ist wichtig zu wissen, daß ein
Basic-Programm während des Eintippens oder Einladens von Disk beziehungsweise
Kassette in den 1. Block kommt. Während des Programmlaufs werden alle normalen
Variablen in den 2. Block geschrieben, alle Felder (Arrays) in den 3. Block und
schließlich der Text der Zeichenketten (Strings) sozusagen rückwärts vom Ende
des Arbeitsspeichers in den 4 . Block. Je nach Größe des Programms und nach
Anzahl der Variablen wandern die Blockgrenzen nach oben beziehungsweise die von
Block 4 nach unten. Wenn sie sich treffen beziehungsweise überschneiden, gibt
es »OUT OF MEMORY«.
Diese Blockbewegung ist in Bild 5 durch die Pfeile dargestellt.
$002D-$002E Zeiger auf die Anfangsadresse des Speicherbereichs für Variable
Dieser Zeiger, in der Low/High-Byte-Darstellung, gibt dem Basic-Interpreter
an, ab welcher Speicherzelle die Variablen eines Basic-Programms gespeichert
sind. Da die Variablen direkt an das Basic-Programm anschließen, zeigt dieser
Zeiger natürlich gleichzeitig auf das Ende des Basic-Programms.
Es muß betont werden, daß es sich nur um den Bereich der »normalen« Variablen
handelt, also nicht um Felder (Arrays). Anders als der Zeiger in 43 und 44, der
auf fest definierte Speicherzellen zeigt, liegt derZeiger für den Variablen-
Beginn nicht fest. Je nach Länge des Programms wandert er nach oben.
Sobald ein Programm eingetippt oder aus einem externen Speicher (Diskette,
Kassette) eingelesen ist, wird der Zeiger in 45 und 46 durch RUN auf ein Byte
hinter das Programmende gesetzt und alle Variablen werden in der Reihenfolge
ihres Auftretens gespeichert. Da normalerweise die Länge eines Basic-Programms
während des Ablaufs konstant bleibt, werden die Variablen in ihrer Position
auch nicht gestört.
Das bedeutet, daß sie sowohl vom Programm als auch vom Programmierer nach einer
Unterbrechung abgefragt werden können. Nur wenn das Programm modifiziert wird,
wandert der Zeiger zusammen mit den Variablen entsprechend weiter.
Denselben Effekt wie das oben erwähnte RUN haben übrigens auch die Befehle NEW,
CLR und LOAD. Eine Ausnahme bildet das LOAD innerhalb eines Programms, welches
den Zeiger nicht zurücksetzt. Dadurch wird ein Aneinanderhängen von mehreren
Programmen samt Variablen-Weiterverwendung unter bestimmten Voraussetzungen
ermöglicht.
Die Bearbeitung der Variablen durch das Basic-Programm und die daraus
resultierenden Kochrezepte für den Programmierer sind im Texteinschub Nr. 8
»Normale Variable in BASIC« separat erläutert.
Die verschiedenen Typen der Variablen und ihre Darstellung im Speicher finden
Sie im 64’er, Ausgabe 10/84, Seite 157 und noch ausführlicher in Ausgabe 11/84,
Seite 124, dargestellt und erklärt.
Für diejenigen Leser, welche kein Monitor- beziehungsweise Disassembler-
Programm haben oder benutzen können, ist im Texteinschub Nr. 9 »Darstellung der
normalen Variablen im Speicher« eine kleine Anleitung gegeben, wie sie die
Variablendarstellung mittels Basic anschauen können.
$002F-$0030 Zeiger auf die Anfangsadresse des Speicherbereichs für Felder (Arrays)
Dieser Zeiger, in der Low-/High-Byte-Darstellung, gibt dem Basic-Übersetzer
(Interpreter) an, ab welcher Speicherzelle die Felder (Arrays) eines Basic-
Programms gespeichert sind. Was Felder sind und wozu sie gebraucht werden, ist
im Texteinschub Nr. 10 kurz erläutert. Da die Felder direkt nach den normalen
Variablen gespeichert werden, zeigt dieser Zeiger natürlich gleichzeitig auf
das Ende des Speichers für normale Variablen.
Durch POKEn einer Adresse in die Speicherzellen 47 und 48 kann der
Speicherbereich am Anfang eines Programms beinahe beliebig verschoben werden.
Beinahe deswegen, weil die Verschiebung im Zusammenhang mit den anderen
Bereichen (siehe Bild 5) einen Sinn haben muß. Im übrigen gilt für diesen
Zeiger dasselbe, was schon für den Zeiger in 45 und 46 gesagt worden ist. Die
Darstellung der Feld-Variablen selbst kann mit der Methode angesehen werden,
die im Texteinschub Nr. 11 erklärt ist.
Wie aus den Erklärungen hervorgeht, wird bei Feldern mit Zeichenketten
(Strings) in dem von Zeiger 47 und 48 bezeichneten Speicherbereich nur die
Definition beziehungsweise die Dimensionierung gespeichert. Die eigentlichen
Zeichenketten stehen wie bei den normalen Variablen im vierten Block, vorn
Speicherende rückwärts angeordnet.
$0031-$0032 Zeiger auf die Endadresse (+1) des Speicherbereichs für Felder (Arrays)
Der Inhalt dieser Speicherzellen zeigt auf die Adresse, wo der Speicherbereich
für Felder auf· hört. Wie aus Bild 5 hervorgeht, werden die Zeichenketten vorn
Ende des verfügbaren RAM· Speichers rückwärts gespeichert. Man kann also auch
sagen, daß der Zeiger in 49 und 50 die letzte mögliche Adresse für
Zeichenketten angibt. Wenn in einem Programm neue Variablen definiert werden,
rutscht diese Adresse weiter nach oben und nähert sich dem Ende der
Zeichenketten, die durch den Zeiger in 51 und 52 angegeben wird.
Wenn sich die Speicherbereiche der Felder und Zeichenketten berühren, bleibt
der Computer stehen und führt die »Garbage Collection« (Müllabfuhr) durch - ein
Prozeß, in dem nicht mehr gebrauchte Zeichenketten entfernt und der
Zeichenketten-Speicher reduziert wird. Ist danach immer noch kein Platz, wird
OUT OF MEMORY gegeben.
Der Befehl FRE löst immer eine solche Garbage Collection aus und gibt dann die
Differenz zwischen den Adressen in den Zeigern 49 und 50 und 51 und 52 als
verbleibenden, noch verfügbaren, Speicherbereich aus.
$0033-$0034 Zeiger auf die untere Grenze des Speicherbereichs für den Text der
Zeichenketten-Variablen
Der Inhalt dieser Speicherzellen zeigt in Low-/High-Byte-Darstellung auf das
jeweilige untere Ende (siehe Bild 5) des Textspeichers von Zeichenketten. Er
bezeichnet aber zugleich auch das obere Ende des frei verfügbaren RAM-Bereichs.
Das entsteht dadurch, daß der Text der Zeichenketten vom Ende des RAM-Bereichs
nach unten gespeichert wird. In Bild 5 ist das durch den Pfeil dargestellt.
Beim Einschalten des Computers und nach einem RESET wird dieser Zeiger auf das
oberste Ende des RAM-Bereichs gesetzt. Beim C 64 ist das 40960 ($A000). Beim VC
20 hängt es von den eingesetzten Speichererweiterungen ab, ohne Erweiterung ist
die Adresse 7680 ($1E00).
Der Befehl CLR setzt den Zeiger auf die Adresse, welche durch den Zeiger in den
Speicherzellen 55 und 56 als das Ende des Basic-Speichers angegeben wird. Wozu
das dient, erkläre ich Ihnen bei der Beschreibung dieses Zeigers weiter unten.
$0035-$0036 Zeiger auf die Adresse der zuletzt eingegebenen Zeichenkette
In diesen Speicherplätzen steht die Adresse (im vierten Block, siehe Bild 5)
der Zeichenkette, die als letzte von Routinen (Programme, Direkteingabe) zur
String-Manipulation abgespeichert worden ist. Mit dem folgenden kleinen
Programm können Sie das genau sehen:
10 PRINT PEEK(53)+256*PEEK(54),
20 PRINT PEEK(51)+256*PEEK(52)
30 INPUT A$
40 GOTO 10
Zeile 10 druckt uns zuerst (links) den Zeiger auf die zuletzt eingegebene
Zeichenkette aus, Zeile 20 rechts daneben den Zeiger auf die untere
Speichergrenze der Zeichenketten. Zeile 30 fordert zur Eingabe einer
Zeichenkette auf.
Wenn Sie bei frisch eingeschaltetem Computer das Programm starten, sehen Sie
eine 0 (=vorher noch kein String eingeben) und daneben die Adresse dezimal
40960 (C 64) beziehungsweise dezimal 7680 (VC 20 ohne Erweiterung). Wenn Sie
auf das Fragezeichen des INPUT hin zum Beispiel ein A eintippen, erhalten Sie
links den vorigen Wert von rechts und rechts jetzt eine um 1 kleinere Zahl.
Eine weitere Eingabe von zum Beispiel XXXXX schiebt die alte rechte Zahl nach
links und die neue wird um die Anzahl der Zeichen, also 5, verringert.
$0037-$0038 Zeiger auf das Ende des für Basic-Programme verfügbaren Speichers
Dieser Zeiger, in der Low-/High-Byte-Darstellung, gibt dem Basic-Übersetzer an,
welches die höchste von Basic verwendbare Speicheradresse ist. Wie aus Bild 5
ersichtlich, ist diese Adresse zugleich der Anfang der als Variable
abgespeicherten Zeichenkette (Strings).
Normalerweise ist diese Adresse fest vorgegeben. Die folgende Tabelle 4 gibt
darüber Auskunft:
Tabelle 4: Ende des Programmspeichers
| | Adresse | Zeiger in 55 56 |
|-------------------|---------|-----------------|
| C 64 | 40960 | 0160 |
| VC 20 (Grundv.) | 7680 | 030 |
| VC 20 (+3 KByte) | 7680 | 030 |