Action! again

1, 2

Action! again

von eda70 » Fr 20. Aug 2010, 13:34
Wenn ich ein Array indirekt dimensioniere in dem ich die Werte in [] angebe,
wie kann ich dann die Länge des Array feststellen, damit ich mit einem Pointer nicht darüberhinaus "pointe" ?
Code: Alles auswählen
BYTE ARRAY WERTE[1 2 3 4 5 6 7 8 9 ... 300 301 302]


Und kann man ein Pointer Array machen?
Damit man bei mehreren Pointern einfach mit einer Schleife durchlaufen kann.

Werden von Action! die Pointer immer in einem bestimmten Speicherbereich abgelegt (Zero-Page)
oder kann man den Speicherplatz frei festlegen?

Re: Action! again

von FlorianD » Fr 20. Aug 2010, 20:54
zu 1: die Länge kann man nicht ermitteln. Also immer selber aufpassen.

zu 2: guck mal in das Buch von GoodByte. Da ist ab Seite 119 schön erklärt, wie das geht.
Code: Alles auswählen
PROC ZEIGEFEHLER(BYTE errnum)
BYTE ARRAY errmsg
CARD ARRAY addr(6)

addr(0)="DISK"
addr(1)="GARBAGE"
addr(2)="HUPS"
addr(3)="MUFL"
addr(4)="HEPP"
addr(5)="UNKNOWN"

IF errnum >=0 AND errnum<5 THEN
  errmsg=adr(errnum)
ELSE
  errmsg=adr(5)
FI
printe("Fehler Nr ")
printb(errnum)
print(":")
printe(errmsg)
RETURN


zu 3: normalerweise liegt ein Pointer irgendwo. Es muss ja nur festgelegt werden, dass der Inhalt der Speicherzelle des Pointers nicht der Wert selbst ist, sondern die Adresse, unter der der Wert liegt.

Mit Trick kann man den Pointer in die Zeropage bringen, das spart ein paar Taktzyklen bei jedem Aufruf. Das gab es einen Artikel von Peter Finzel drüber, zu finden hier: http://wiki.strotmann.de/wiki/attach/AC ... neller.pdf

Re: Action! again

von eda70 » Mo 23. Aug 2010, 21:41
Vielleicht irre ich mich ja, aber in dem Beispiel wird sich meines Erachtens die Tatsache zu Nutze gemacht, dass unbenutzte Variablen nicht gelöscht werden.
So werden die Texte in den Speicher gelegt. Dann wird die Start-Adresse des ByteArrays verschoben. Dadurch werden die Texte korrekt ausgegeben.
Ein echter Pointer ist das in meinen Augen nicht, denn ein Zugriff auf ein Zeichen des Array ist so nicht möglich.

Was für eine Schleife gehen müßte, wenn man die Adressen (Card) in einem Card Array speichert und den Wert dann in einen "Zwichenpointer" übergibt:
Code: Alles auswählen
For i= 1 to 4 do
  zwptr=ptr(i) ;zwptr ist der Zwischenpointer und ptr das Array in dem die Adressen gespeichert werden
  wert=zwptr^
  ptr(i)==+wert
od

Re: Action! again

von eda70 » Mo 23. Aug 2010, 22:09
Ich bin etwas verwirrt. Beim Testen mit meinem Hilfspointer für Schleifen, hatte ich unerwartete Ergebnisse. Also den Code soweit zurück gebaut, dass die Ergebnisse eigentlich vorhersehbar sein sollten - aber eben nur sollten....
Code: Alles auswählen
PROC MAIN()

  BYTE ARRAY ST1=[1 2 3 4 5 6 7 8 9]
  BYTE POINTER HELP
  HELP=@ST1
  PRINTCE(HELP)
  PRINTBE(HELP^)
  HELP==+8     
  PRINTCE(HELP)
  PRINTBE(HELP^)
RETURN

Ausgabe:
10187 - ist wohl ok
194 - hier hätte ich 1 erwartet
10195 - ist ok +8 eben
169 - hier hätte ich 8 erwartet

Wo ist mein Fehler? :roll:

Re: Action! again

von FlorianD » Mo 23. Aug 2010, 22:26
eda70 hat geschrieben:Ich bin etwas verwirrt. Beim Testen mit meinem Hilfspointer für Schleifen, hatte ich unerwartete Ergebnisse. Also den Code soweit zurück gebaut, dass die Ergebnisse eigentlich vorhersehbar sein sollten - aber eben nur sollten....
Code: Alles auswählen
PROC MAIN()

  BYTE ARRAY ST1=[1 2 3 4 5 6 7 8 9]
  BYTE POINTER HELP
  HELP=@ST1
  PRINTCE(HELP)
  PRINTBE(HELP^)
  HELP==+8     
  PRINTCE(HELP)
  PRINTBE(HELP^)
RETURN

Ausgabe:
10187 - ist wohl ok
194 - hier hätte ich 1 erwartet
10195 - ist ok +8 eben
169 - hier hätte ich 8 erwartet

Wo ist mein Fehler? :roll:



Hi,

ich habe es eben ausprobiert. Seltsam, ich hätte erwartet dass es geht.
Aber lass mal das @ vor dem ST1 weg, dann geht es!
Das @ braucht man wohl nur, wenn man einfache Variablen referenziert.
Wenn ich sage HELP=ST1 kann ja nur die Adresse gemeint sein, sonst würde ja ein Index fehlen ST1(3)

In Action! werden Arrays wie Pointer behandelt steht (Kapitel 8.2.2 "...der Arrayname ist ein Pointer auf das erste Element eines Arrays...")

Re: Action! again

von eda70 » Di 24. Aug 2010, 09:42
FlorianD hat geschrieben:Aber lass mal das @ vor dem ST1 weg, dann geht es!
Das @ braucht man wohl nur, wenn man einfache Variablen referenziert.

Das ist ja blöd. Da wäre ich jetzt nie drauf gekommen.

Re: Action! again

von Dietrich » Di 24. Aug 2010, 22:22
Eigentlich ist das ganz logisch: ST1 ist ein Pointer, also ist HELP=@ST1 ein Pointer, der auf den Pointer ST1 zeigt. D.h. das BYTE HELP^ ist dann das Low-Byte des Pointers ST1 und das CARD HELP^ ist der Pointer ST1. Und das BYTE HELP^^ müsste dann das erste Byte des Arrays sein. (Hab ich jetzt allerdings nicht ausprobiert, das Handbuch schweigt sich jedenfalls darüber aus.)

Vielleicht ist es eine gute Idee, die ungarische Notation zumindest für Pointer zu benutzen. Also AST1 (A=Array) statt ST1 und PAST1 (P=Pointer) statt HELP. Dann hebt sozusagen jedes ^ und () ein P bzw. A auf - das ist einfach zu merken. (Statt A kann man auch nur Ps benutzen.) So habe ich früher in C programmiert.

Gruß Dietrich

Re: Action! again

von eda70 » Mi 25. Aug 2010, 09:56
Wenn man es so betrachtet klingt es in der Tat logisch :)

(Nur der vollständigkeithalber:
Ein Byte-Pointer ist ein 16bit Pointer (wie alle Pointer), der auf einen Bytewert zeigt.
D.h. bei der indirekten Adressierung bA=bpB^ wird nur ein Byte übergeben.)

Re: Action! again

von Bernd » Mi 25. Aug 2010, 14:04
Wenn ich mir die Logik anschaue, so kommt dies einer X indizierte indirekte Adressierung in Assembler gleich. X ist der "Offset" auf den ersten Pointer in der Zero Page,
in der die eigentliche 16 Bit Adresse steht, von dem das Byte geladen oder gespeichert wird. Action kommt Assembler da sehr nahe.

Bernd

Re: Action! again

von Dietrich » Mi 25. Aug 2010, 23:24
So,

ich habe jetzt zum ersten Mal ACTION ein wenig rumprobiert:

1) BYTE ARRAY X(5) (optional mit =[...])
X ist ein Pointer, X^ ist dasselbe wie X(0), @X gibt Error 17

2) BYTE ARRAY X=[1 2 3 4 5] (ohne Längenangabe in Klammern)
Dasselbe wie bei 1), nur gibt @X keinen Fehler, sondern ist ein Pointer, der hinter (!) den Array X zeigt. Das ist aber wohl ein Bug, hier sollte wahrscheinlich auch Error 17 kommen. Immerhin, mit @X-X kann man die Länge von X abfragen ;-)

3) Multiplikation
Entgegen dem Handbuch funktioniert das auch mit CARDs einwandfrei, das Ergebnis wird immer modulo 65535 berechnet. Also ist z.B. 10000*10000=57600, 256*256=0, 40000*2=14464. Das liegt wohl daran, dass auch bei Multiplikationen die Zweier-Komplement-Rechnung funktioniert.

4) Division
Die Division arbeitet dagegen nicht mit CARDs, sondern immer mit INTs. CARD-Zahlen dürfen also nicht größer als 32767 sein (diese doch wichtige Einschränkung habe ich im Handbuch aber nicht gefunden).

5) MOD
Funktioniert offenbar nicht mit negativen Zahlen (da kommt Unsinn heraus).

6) Division durch 0
Gibt keinen Fehler, sondern immer 255 (auch als CARD) ?!?

7) Typkonvertierungen
CARDs und INTs werden als 2-Byte Werte von 0-65535 gespeichert. INTs sind CARDs, die im Zweierkomplement interpretiert werden. Man kann jeder Variablen ohne Compile-Fehler Werte von -65535 bis +65535 zuweisen. Z.B. ist -1 dasselbe wie 65535 und entsprechend ist -65535 dasselbe wie 1.

Weiter bin ich noch nicht gekommen ...

Re: Action! again

von eda70 » Fr 27. Aug 2010, 14:06
Das ist ja interessant! Blöd nur, wenn man nicht weiß, ob es ein Bug oder ein Feature ist.
Dann sollte man im Zweifel wohl auf Nummer Sicher gehen.

Einige Fehler sind auch schon bekannt.
Hier der Link zur einer Fehlerdatei. http://www.umich.edu/~archive/atari/8bit/Unverified/Cislib_a/bugs1.act
In dem Verzeichnis liegen noch mehr Fehlerdateien. Und für einige auch schon Lösungen.

Leider gibt es nicht so wirklich viel Dokus über Action!...

Re: Action! again

von Dietrich » Fr 27. Aug 2010, 22:44
Boah, das sind aber viele Bugs :shock:

Ich habe mich noch weiter mit Arrays beschäftigt:

BYTE ARRAY X=[1 2 3 4]
BYTE POINTER Y = X

Jetzt zeigt Y (genau wie @X) hinter den Array X !!! Autsch, das tut weh! Aber:

BYTE ARRAY X(0)=[1 2 3 4]
BYTE POINTER Y = X

Jetzt ist's korrekt. Also niemals BYTE ARRAY X=[...] benutzen, sondern immer BYTE ARRAY X(0)=[...] !
Die verschiedenen Array-Varianten werden wie folgt compiliert:

a) BYTE ARRAY(n)=[...]
compiliert genau den Klammerinhalt, n wird ignoriert (kann daher immer 0 sein)

b) BYTE ARRAY X(n) mit n<=256
compiliert genau n Bytes als Platzhalter für den Array. Da der mitten im Variablen-Bereich steht, stellt sich die Frage, ob der Array mit abgespeichert wird?!?

c) BYTE ARRAY X(n) mit n>256
compiliert eine Adresse, die auf einen reservierten Array im ACTION-Variablenspeicher zeigt (liegt hinter dem Programm) sowie die Länge. Die Länge scheint aber nirgends benutzt zu werden ???

d) BYTE ARRAY X
compiliert nur eine Adresse (2 Byte) genau wie BYTE POINTER X und reserviert keinen Array-Speicherplatz.

e) BYTE ARRAY X=adr
compiliert gar nichts, sondern ersetzt lediglich überall X durch Zugriff auf die Adresse adr.

f) BYTE ARRAY X(n)=adr mit n<=256
wie e)

g) BYTE ARRAY X(n)=adr mit n>256
compiliert die Adresse + Länge, es wird natürlich kein Array-Speicherplatz reserviert.

Die Anfangsadresse des compilierten ACTION-Programms steht in $491/2. Der Program Counter beim Compilieren steht in $E/F. D.h. wenn man $E/F während des Compile per SET-Direktive ändert, kann man das Programm an beliebige Stellen compilieren. Das ist aber höchstens für uninitialisierte Variablen oder das ganze Programm sinnvoll, da sonst ACTION das Programm wohl nicht speichern kann.

Weiß jemand, wo die RUN-Adresse des ACTION-Programms nach dem Compile steht?

Schade, dass solche interessanten und durchaus wichtigen Dinge nicht im Handbuch stehen. Denn eigentlich kann man nur dann vernünftig ACTION programmieren, wenn man weiß, was der Compiler eigentlich macht ... :cry:

Und noch was: In der Runtime finde ich bei fast allen PROCs folgendes Konstrukt:

PROC BLABLA()=*

Der Stern steht wohl für den Compile Program Counter (in Codeblocks wird mit * auf diesen zugegriffen). Aber wo ist der Unterschied zu PROC BLABLA() ohne Stern?

Re: Action! again

von FlorianD » Sa 28. Aug 2010, 00:28
Super, Dietrich! Endlich mal Klarheit was da abgeht. Das muss unbedingt in eine Überarbeitung des Handbuches.

hier steht was zu Pointern drin und den $0E, $0F Adressen drin:
http://wiki.strotmann.de/wiki/attach/AC ... neller.pdf

Interne Variablen
http://wiki.strotmann.de/wiki/Wiki.jsp? ... 0Variables

Der * bei den PROC=*() bedeutet, dass Action darauf verzichtet die Parameter in lokale Variablen abzulegen. Bei Aufrufen werden die Parameter immer in A,X,Y übergeben PROC blubb=*(BYTE areg,xreg,yreg)

Re: Action! again

von FlorianD » Sa 28. Aug 2010, 01:15
und hier das große Bugsheet, schön formatiert:
http://wiki.strotmann.de/wiki/Wiki.jsp? ... 20Bugsheet

Re: Action! again

von Dietrich » So 29. Aug 2010, 22:36
Danke Florian, auch für die interessanten Links.

FlorianD hat geschrieben:Der * bei den PROC=*() bedeutet, dass Action darauf verzichtet die Parameter in lokale Variablen abzulegen. Bei Aufrufen werden die Parameter immer in A,X,Y übergeben PROC blubb=*(BYTE areg,xreg,yreg)

Achso, ich dachte, die ersten 3 Bytes der Parameter werden immer in A,X,Y übergeben. Ich nehme mal an, das gilt auch für aufgerufenen 6502-Code, also sowas wie PROC CIO=$E454, oder?

1) Ich habe heute nun mal CARD und INT ARRAYs ausprobiert. Leider hilft da der (0)-Trick von oben nicht. Es kann passieren, dass ein POINTER auf einen CARD/INT-Array danebengreift. Da sind wohl noch einige Experimente nötig, wann genau das passiert ... Also besser keine POINTER auf CARD/INT-ARRAYS benutzen. Und nicht @ auf eine Array-Variable anwenden!

2) "<type> ARRAY" ist dasselbe wie "<type> POINTER", z.B. funktioniert

BYTE POINTER X=[1 2 3 4]
BYTE POINTER X(10)

Ebenso kann man mit Indizes auf Pointer zugreifen (die dann als Array angesehen werden).

3) Auch INT und CARD sind dasselbe, d.h. es ist egal, ob man eine Variable als INT oder CARD deklariert. Ein Unterschied macht sich nur bei Prozeduren, Funktionen und Operatoren bemerkbar, die ein CARD als INT interpretieren oder umgekehrt. Die CARDs 32768 bis 65535 entsprechen den INTs -32768 bis -1 (Zweier-Komplement-Rechnung).

4) Noch was zu MOD: Sind X,Y>0 so ist -X MOD Y = X MOD -Y = X/Y, seltsam! Dagegen ist -X MOD -Y = X MOD Y, was OK ist. Und n MOD 0 ist n & 255. Also:

- MOD nur auf Zahlen von 0 bis 32767 anwenden (insbesondere nicht auf negative INTs)

5) Zur Division durch 0: Es ist n/0 = 255, falls n<256 und n/0 = 65535, falls n>=256. Das sind jeweils die größtmöglichen Werte für CARDs bzw. BYTEs. Also sozusagen "unendlich", was mathematisch OK wäre.

Re: Action! again

von FlorianD » Mo 30. Aug 2010, 00:27
Hallo Dietrich,

Dietrich hat geschrieben:Danke Florian, auch für die interessanten Links.
FlorianD hat geschrieben:Der * bei den PROC=*() bedeutet, dass Action darauf verzichtet die Parameter in lokale Variablen abzulegen. Bei Aufrufen werden die Parameter immer in A,X,Y übergeben PROC blubb=*(BYTE areg,xreg,yreg)

Achso, ich dachte, die ersten 3 Bytes der Parameter werden immer in A,X,Y übergeben. Ich nehme mal an, das gilt auch für aufgerufenen 6502-Code, also sowas wie PROC CIO=$E454, oder?

Da habe ich mich blöd ausgedrückt. Du hast recht, die ersten 3 Parameter gehen immer in A,X,Y. Wie das mit dem Rest dann ist habe ich keine Ahnung. Aber das findest Du bestimmt raus, hihi :-)

Dietrich hat geschrieben:2) "<type> ARRAY" ist dasselbe wie "<type> POINTER", z.B. funktioniert ...

Das steht auch so in Goodbytes Anleitung drin.

Prima dass Du das so sorgfältig angehst. Da gibts jemanden, der einen neuen Compiler schreibt, guck mal unter
http://www.noniandjim.com/Jim/atari/Act ... piler.html
der freut sich bestimmt über Deinen Input.

Viele Grüße,
Florian

Re: Action! again

von eda70 » Mi 1. Sep 2010, 16:00
FlorianD hat geschrieben:Prima dass Du das so sorgfältig angehst. Da gibts jemanden, der einen neuen Compiler schreibt, guck mal unter
http://www.noniandjim.com/Jim/atari/Act ... piler.html
der freut sich bestimmt über Deinen Input.

Dann könnte man Gury gleich mit informieren. Er arbeitet an Effectus und hat für die Infos sicher auch gute Verwendung...

Re: Action! again

von eda70 » Mo 17. Jan 2011, 15:16
FlorianD hat geschrieben:...die ersten 3 Parameter gehen immer in A,X,Y. Wie das mit dem Rest ...

Code: Alles auswählen
Adresse          | n-tes Byte der Parameter
-----------------+-------------------------
A Register       |     1.
X Register       |     2.
Y Register       |     3.
$A3              |     4.
$A4              |     5.
:                |     :
:                |     :
$AF              |     16.


Interessant (seh' grad, weiter oben ist das schon erwähnt...): Benennt man eine Proc mit "PROC Name=*(...)" , werden die Parameter wie oben genannt übergeben.
Benennt man sie normal mit "Proc Name(...)" werden die Parameter direkt im Speicher ab $A0 abgelegt.
(Fragt sich nur, was steht dann in A, X und Y?)

Re: Action! again

von eda70 » Mi 19. Jan 2011, 23:13
Wie kann ich eigentlich feststellen, wenn ich eine kleine Proc compiliert habe, wie dann das Compilat (ML) aussieht?

Re: Action! again

von funkheld » Mo 29. Aug 2011, 12:41
Für die Frage hätte ich auch mal gern eine Antwort, wie das Compilat aussieht.

danke.

gruss
1, 2