This page (revision-21) was last changed on 03-Feb-2023 15:21 by Florian Dingler 

This page was created on 20-Feb-2010 19:38 by Carsten Strotmann

Only authorized users are allowed to rename pages.

Only authorized users are allowed to delete pages.

Page revision history

Version Date Modified Size Author Changes ... Change note
21 03-Feb-2023 15:21 20 KB Florian Dingler to previous

Page References

Incoming links Outgoing links

Version management

Difference between version and

At line 9 changed one line
Welcher Atari-Fan kennt ihn nicht, den superflinken ACTION!-Compiler von Optimized Systems Software (OSS)? Ohne Übertreibung ist das die beste und schnellst Programmiersprache für alle 8-Bit Computer von Atari, wenn nicht die schnellste für alle 6502-Computer überhaupt. Und die darf natürlich im Rahmen der Assemblerecke nicht vergessen werden.
Welcher Atari-Fan kennt ihn nicht, den superflinken ACTION!-Compiler von Optimized Systems Software (OSS)? Ohne Übertreibung ist das die beste und schnellste Programmiersprache für alle 8-Bit Computer von Atari, wenn nicht die schnellste für alle 6502-Computer überhaupt. Und die darf natürlich im Rahmen der Assemblerecke nicht vergessen werden.
At line 11 changed one line
Den Lesern der Assemblerecke ist ACTION! schon längst kein Unbekannter mehr, denn in der [CK 10/85|Musik in ACTION] haben wir bereits ein Musikprogramm vorgestellt, das vollkommen in ACTION! geschrieben war. Diesmal wird noch etwas tiefer gebohrt und gezeigt, wie man ACTION!-Programme noch kürzer und noch schneller machen kann. Außerdem gibt's als besonderes Bondbon eine Runtime-Package, mit der ACTION!-Programme auch ohne Steckmodul laufen.
Den Lesern der Assemblerecke ist ACTION! schon längst kein Unbekannter mehr, denn in der [CK 10/85|Musik in ACTION] haben wir bereits ein Musikprogramm vorgestellt, das vollkommen in ACTION! geschrieben war. Diesmal wird noch etwas tiefer gebohrt und gezeigt, wie man ACTION!-Programme noch kürzer und noch schneller machen kann. Außerdem gibt's als besonderes Bonbon eine Runtime-Package, mit der ACTION!-Programme auch ohne Steckmodul laufen.
At line 15 changed one line
In vielen ACTION!-Listings, die in amerikanischen Zeitschriften zu finden waren, wurden eifrig PEEK- und POKE-Befehle eingesetzt. Das zeigt, dass die Autoren noch nicht erkannt haben, welche eleganten und leistungsfähigen Konstruktionen ACTION! anbietet und damit PEEK und POKE vollkommen überflüssig werden lässt. Nehmen wir als Beispiel nut die Abfrage eines Joysticks über die Speicherzelle 632 ([STICK0]). Ein Test auf die Mittelstellung könnte lauten:
In vielen ACTION!-Listings, die in amerikanischen Zeitschriften zu finden waren, wurden eifrig PEEK- und POKE-Befehle eingesetzt. Das zeigt, dass die Autoren noch nicht erkannt haben, welche eleganten und leistungsfähigen Konstruktionen ACTION! anbietet und damit PEEK und POKE vollkommen überflüssig werden lässt. Nehmen wir als Beispiel nur die Abfrage eines Joysticks über die Speicherzelle 632 ([STICK0]). Ein Test auf die Mittelstellung könnte lauten:
At line 24 changed one line
Diese Variable ist nicht nur um einiges kürzer, sondern im Ablauf mindesten 10 mal schneller! Um das zu verstehen, muss man sich ansehen, wie der ACTION!-Compiler intern arbeitet. PEEK() ist innerhalb von ACTION! als Funktion vordefiniert und wird daher als Aufruf eines Unterprogramms per JSR übersetzt. Zuvor muss das Argument von PEEK noch in die Register des 6502-Prozessors geladen werden, so dass sich etwa folgendes Maschinenprogramm für den Zugriff auf die Speicherzelle 632 ergibt:
Diese Variable ist nicht nur um einiges kürzer, sondern im Ablauf mindesten 10 mal schneller! Um das zu verstehen, muss man sich ansehen, wie der ACTION!-Compiler intern arbeitet. PEEK() ist innerhalb von ACTION! als Funktion vordefiniert und wird daher als Aufruf eines Unterprogramms per JSR übersetzt. Zuvor muss das Argument von PEEK noch in die Register des 6502-Prozessors geladen werden, so dass sich etwa folgendes Maschinenprogramm für den Zugriff auf die Speicherzelle 632 ergibt:
At line 38 changed one line
Auf der anderen Seite ist klar, dass mit diesen adressierten Variablen nicht jeder PEEK- oder POKE-Befehl ersetzbar ist. Einfachstes Beispiel wäre das Ändern eines der fünf Farbregister in Abhängigkeit von einer Variablen. Mit POKE(708+I,0) würde das mit I ausgewählte Farbregister mit der Farbe schwarz vorbelegt. Hier bieten sich die ungeheuer universalen Arrays des ACTION!-Compilers an. Wie bei einfachen Variablen können auch Felder auf feste Adressen gelegt werden und somit ist es möglich, eine Gruppe von Betriebssystem- oder Hardware-Registern als Array aufzufassen. Mit BYTE ARRAY FARBE = 708 definiert man die Schattenregister der Farbspeicher als ein Feld FARBE, und die obige POKE-Anweisung verkürzt sich zu FARBE(I)=0.
Auf der anderen Seite ist klar, dass mit diesen adressierten Variablen nicht jeder PEEK- oder POKE-Befehl ersetzbar ist. Einfachstes Beispiel wäre das Ändern eines der fünf Farbregister in Abhängigkeit von einer Variablen. Mit POKE(708+I,0) würde das mit I ausgewählte Farbregister mit der Farbe schwarz vorbelegt. Hier bieten sich die ungeheuer universalen Arrays des ACTION!-Compilers an. Wie bei einfachen Variablen können auch Felder auf feste Adressen gelegt werden und somit ist es möglich, eine Gruppe von Betriebssystem- oder Hardware-Registern als Array aufzufassen. Mit
{{{BYTE ARRAY FARBE=708}}} definiert man die Schattenregister der Farbspeicher als ein Feld FARBE, und die obige POKE-Anweisung verkürzt sich zu
At line 40 changed one line
Aber damit haben wir den Compiler noch lange nicht ausgeschöpft. Mit einem kleinen Trick wird der erzeugte Code viel kürzer und schneller: BYTE ARRAY FARBE (0) =708. Diese Definition sagt dem Compiler, dass er es mit einem kurzen Feld zu tun hat, das schnell adressiert werden kann. Im Objektprogramm kann der Compiler dann die X-Indizierung ausnutzen und die Anweisung FARBE(INDEX)=0 so übersetzten:
{{{FARBE(I)=0}}}
At line 43 added 10 lines
Aber damit haben wir den Compiler noch lange nicht ausgeschöpft. Mit einem kleinen Trick wird der erzeugte Code viel kürzer und schneller:
{{{BYTE ARRAY FARBE(0)=708}}}
Diese Definition sagt dem Compiler, dass er es mit einem kurzen Feld zu tun hat, das schnell adressiert werden kann. Im Objektprogramm kann der Compiler dann die X-Indizierung ausnutzen und die Anweisung
{{{FARBE(INDEX)=0}}}
so übersetzen:
At line 67 changed one line
Letzte und universelle Möglichkeit zum Ersetzten von PEEK und POKE bietet der Pointer. Derartige Zeiger-Variablen enthalten eine Adresse einer anderen Variablen oder einer beliebigen Speicherzelle. Basic-Kenner werden jetzt einwerfen, dass daran nichts Besonderes ist, schließlich kann jede normale Variable auch eine Adresse enthalten. Wozu also Pointer? Diese Spezial-Variablen haben Fähigkeiten, die über das normale Maß hinausgehen. So kann durch das Anfügen des Pointer-Symboles "^" der Inhalt der Variablen erreicht werden, auf die der Pointer zeigt. Sehen Sie sich das gleich an einem Beispiel an:
Letzte und universelle Möglichkeit zum Ersetzen von PEEK und POKE bietet der Pointer. Derartige Zeiger-Variablen enthalten eine Adresse einer anderen Variablen oder einer beliebigen Speicherzelle. Basic-Kenner werden jetzt einwerfen, dass daran nichts Besonderes ist, schließlich kann jede normale Variable auch eine Adresse enthalten. Wozu also Pointer? Diese Spezial-Variablen haben Fähigkeiten, die über das normale Maß hinausgehen. So kann durch das Anfügen des Pointer-Symboles "^" der Inhalt der Variablen erreicht werden, auf die der Pointer zeigt. Sehen Sie sich das gleich an einem Beispiel an:
At line 75 changed one line
Die erst Zeile definiert einen Pointer des Namens ZEIGER, der auf das erste Farbregister gerichtet ist. Der Variablen F wird der Inhalt von Speicherzelle 708 zugeordnet, das entspricht dem Befehl F=PEEK(708). Nun kommt der Trick: Der Pointer wird um eins erhöht, so dass er nun auf die Zelle 709 deutet. Die dritte Zeile erhöht schließlich den Inhalt von 709 um zwei, in Basic müsste man hier mit POKE 709,PEEK(709)+1 viel umständlicher vorgehen.
Die erst Zeile definiert einen Pointer des Namens ZEIGER, der auf das erste Farbregister gerichtet ist. Der Variablen F wird der Inhalt von Speicherzelle 708 zugeordnet, das entspricht dem Befehl F=PEEK(708). Nun kommt der Trick: Der Pointer wird um eins erhöht, so dass er nun auf die Zelle 709 deutet. Die dritte Zeile erhöht schließlich den Inhalt von 709 um zwei, in Basic müsste man hier mit POKE 709,PEEK(709)+2 viel umständlicher vorgehen.
At line 83 changed one line
Erneut haben wir den ACTION!-Compiler nur mit Halbgas gefahren. Jedem Assemblerprogrammierer wird bei der Besprechung der Pointer aufgefallen sein, dass es sich hierbei um eine reinrassige indirekte Adressierung handelt. und so etwas kann der 6502 nun mal eben nur in der Zero-Page. Wenn daher ein Pointer benutzt wird, muss der Compiler dafür sorgen, dass die Adresse in ein Arbeitsregister der Zero-Page geschrieben wird, und dann erst kann der Zugriff erfolgen. Warum also nicht gleich alle Pointer in die Zero-Page legen? Und es funktioniert! Der ACTION!-Compiler erkennt, wenn ein Pointer gleich dort ist, wo er sein sollte und arbeitet dann auch wesentlich schneller. Nimmt man an, dass ZEIGER in der Zero-Page liegt so wird ZEIGER=255 folgendermaßen übersetzt:
Erneut haben wir den ACTION!-Compiler nur mit Halbgas gefahren. Jedem Assemblerprogrammierer wird bei der Besprechung der Pointer aufgefallen sein, dass es sich hierbei um eine reinrassige indirekte Adressierung handelt, und so etwas kann der 6502 nun mal eben nur in der Zero-Page. Wenn daher ein Pointer benutzt wird, muss der Compiler dafür sorgen, dass die Adresse in ein Arbeitsregister der Zero-Page geschrieben wird, und dann erst kann der Zugriff erfolgen. Warum also nicht gleich alle Pointer in die Zero-Page legen? Und es funktioniert! Der ACTION!-Compiler erkennt, wenn ein Pointer gleich dort ist, wo er sein sollte und arbeitet dann auch wesentlich schneller. Nimmt man an, dass ZEIGER in der Zero-Page liegt so wird ZEIGER=255 folgendermaßen übersetzt:
At line 155 changed one line
Besser geht es natürlich mit eine Runtime-Package (RTP).Von OSS wurde zwar eine RTP angekündigt, die aber bei uns nie auf dem Markt erschien. Gerüchten nach zu urteilen, hat es Probleme zwischen OSS uns Action Computer Services (dem Hersteller von ACTION!) gegeben. Damit bleibt dem geplagten Benutzer nur eine Lösung: Eine eigene Runtime-Package muss her. Und hier ist sie. Sie brauchen nur Listing 2 und 3 abzutippen und unter den angegebenen Filenamen abzuspeichern. Später schreiben Sie in Ihr Programm
Besser geht es natürlich mit eine Runtime-Package (RTP).Von OSS wurde zwar eine RTP angekündigt, die aber bei uns nie auf dem Markt erschienen. Gerüchten nach zu urteilen, hat es Probleme zwischen OSS uns Action Computer Services (dem Hersteller von ACTION!) gegeben. Damit bleibt dem geplagten Benutzer nur eine Lösung: Eine eigene Runtime-Package muss her. Und hier ist sie. Sie brauchen nur Listing 2 und 3 abzutippen und unter den angegebenen Filenamen abzuspeichern. Später schreiben Sie in Ihr Programm