Autor: Dietmar Harlos
Zum fehlerfreien Kompilieren werden der Standard-BASIC-Compiler (CCBAS.EXE) und der AS05 Assembler (AS05.EXE) benötigt. Der Standardcompiler liegt der DOS-IDE bei und kann zusammen mit dem Assembler auf der C-Control-intern-Homepage heruntergeladen werden.
Durch welchen Assemblercode ein BASIC-Befehl in Maschinensprache umgewandelt
wird ist für den Anwender vollständig transparent und kann in
einer Konfigurationsdatei festgelegt werden. Wer etwas von der Assemblersprache
versteht, kann den Compiler durch Ändern dieser Datei eigenen Wünschen
anpassen und hochoptimierte Kompilate erstellen lassen.
Während der Programmausführung holt die C-Control ein Token nach dem anderen über den I²C-Bus aus dem EEPROM und führt die zu jedem Token gehörende Betriebssystemroutine aus. Viele Routinen holen zudem noch Datenbytes aus dem EEPROM, die hinter dem Token folgen.
Für das Lesen eines Tokens aus dem EEPROM und das anschließende Suchen und Aufrufen der entsprechenden Betriebssystemroutine benötigt der Mikrokontroller etwa 377 Taktzyklen (ungefähr 188 µs). Jedes Datenbyte, das zusätzlich gelesen werden muß, schlägt noch einmal mit mindestens 208 Taktzyklen (104 µs) zu Buche. Selbst der einfachste Befehl ("DEACT wordport") kann aus diesem Grund also maximal 5000 mal pro Sekunde ausgeführt werden. Ein Befehl wie "a=b+c" wird vom Standardcompiler in die Befehlsbytes "22 1 22 2 51 25 0" übersetzt. Hierbei sind 22, 51 und 25 Tokenbytes und 1, 2 und 0 Datenbytes. Für die Interpretation der Token werden in diesem Fall etwa 754 µs und für das Lesen der Datenbytes etwa 312 µs benötigt. Das eigentliche Durchführen der Berechnung mit Hilfe der Betriebssystemroutinen benötigt hingegen "nur" 190 µs. In diesem Fall wird also 85 % (!) der benötigten Ausführungszeit für die Interpretation und das Lesen aus dem EEPROM verschenkt. Letzteres ist ein besonderes Nadelöhr - die C-Control verbringt fast 60 % ihrer Zeit mit dem Lesen vom I²C-Bus!
Alle Berechnungen und Wertzuweisungen werden vom Betriebssystem mit Hilfe eines Rechenstacks durchgeführt. Bevor eine Berechnung durchgeführt wird, müssen erst die Zahlen, die an der Rechnung beteiligt sind, auf den Stack gepusht, die Berechnung ausgeführt und das Ergebnis vom Stack gepoppt werden. Selbst so einfache Wertzuweisungen wie "a=b" werden durchgeführt, indem zuerst der Wert von b auf den Stack geschrieben, und anschließend der Stackinhalt in die Variable a gespeichert wird. Durch die konsequente Verwendung des Rechenstacks kann die C-Control auch komplexe Berechnungen durchführen, nur leider benötigt das Pushen und Poppen relativ viel Zeit. In obigen Beispiel sind es etwa 130 µs.
Mit Hilfe des neuen Compilers kann der Befehl "a=b+c", ohne Lesen vom
I²C-Bus und ohne Benutzung des Rechenstacks, in nur 5 µs (oder
noch schneller!) ausgeführt werden.
Zur Installation muß der Anwender den gesamten Inhalt des ZIP-Archivs, in dem sich dieser Text befunden hat, in das Quelltext-Verzeichnis entpacken. Anschließend müssen noch der Standardcompiler CCBAS.EXE und der Assembler AS05.EXE hinzukopiert werden.
Entscheidend zur problemlosen Kompilierung ist, daß der Compiler CCBAS2MC.EXE, die Konfigurationsdatei CCBAS2MC.CFG, der Standardcompiler und der AS05-Assembler in einem gemeinsamen Verzeichnis stehen.
Dem ZIP-Archiv liegt eine Batchdatei namens COMPILE.BAT bei. Wenn diese durch einen Doppelklick im Explorerfenster gestartet wird, dann übersetzt der Compiler das BASIC-Programm TEST1_C.BAS. Durch Editieren der Batchdatei kann der Compiler natürlich veranlaßt werden, auch jede andere BASIC-Programmdatei zu übersetzen.
Wer die C-Control bisher nur unter Windows programmiert hat, kann auch die DOS-IDE installieren und den Compiler CCBAS.EXE durch CCBAS2MC.EXE im Menü "Option -> Tools" ersetzen. Die DOS-IDE kann auch sehr gut unter Windows in einem DOS-Fenster benutzen werden (50 Zeilen-Modus bei einer Schriftgröße von 7 x 12 und einer Screenauflösung von 1024x768 Bildpunkten oder 43 Zeilen bei 800x600 Punkten). Das beiliegende Terminalprogramm MINITERM.EXE sollte allerdings nicht benutzt werden; dafür kann aber TERMINAL.EXE, aus der C-Control-intern-Sammlung eingesetzt werden.
Der Compiler unterstützt nur den C-Control/BASIC-Mikrokontroller
der Version 1.1 (vom 20. Dezember 1996). BASIC-Programme für die C-Control-2
und die ältere Unit mit der Bezeichnung "XCTRL96A" können mit
diesem Compiler nicht übersetzt werden.
Das zu kompilierende BASIC-Programm und das Programm, in das der kompilierte Code später eingebunden werden soll, müssen die gleichen Variablendeklarationen benutzen. Das heißt, am Beginn der beiden Programme müssen die gleichen DEFINE-Anweisungen stehen, sonst besteht Gefahr, daß sich Variablen überschneiden.
Der Befehl PRINT wird vom Compiler nicht voll unterstützt (was am geringen Platz im internen EEPROM liegt). Nur die Variante mit angehängtem Semikolon, bei der eine Zahl oder Variable ausgegeben wird, darf im zu kompilierenden BASIC-Programm verwendet werden (also z.B. "PRINT 123;"). Falls ein Zeilenvorschub benötigt wird, muß dieser per PUT generiert werden ("PUT 13 : PUT 10"). Auch Tabellen dürfen nicht benutzt werden.
Parameterübergaben an das kompilierte Programm müssen - wie
bei jeder normalen Subroutine - immer über Variablen stattfinden.
Die Rückgabe von Werten kann ebenfalls über Variablen geschehen.
Siehe dazu folgendes Beispiel:
| define a byte
define b byte define c byte a=b+c |
| Bild 1.1a: Das zu kompilierende BASIC-Programm TEST1_C.BAS |
Zunächst muß obenstehendes BASIC-Programm abgetippt und unter dem Namen TEST1_C.BAS in das Verzeichnis gespeichert werden, in dem der Compiler installiert wurde. Wer zu faul zum Abtippen ist, findet die fertige Datei im ZIP-Archiv. Nun kann die Kompilierung durch einen Doppelklick auf die Batchdatei COMPILE.BAT gestartet werden. Alternativ wird die "MS-DOS-Eingabeaufforderung" gestartet und in das Compiler-Verzeichnis gewechselt. Das geschieht mit dem CD-Befehl; also zum Beispiel mittels "cd c:\temp\ccbas2mc". Dann kann die Kompilierung durch Eingabe von "CCBAS2MC test1_c.bas" gestartet werden.
Wenn der Compilerlauf ohne Probleme vonstatten gegangen ist, müßten
drei neue Dateien im Verzeichnis vorhanden sein: TEST1_C.DAT (die Tokendatei),
TEST1_C.ASM (Assemblercode) und TEST1_C.S19 (der assemblierte Assemblercode).
Uns interessiert jetzt vor allen Dingen die S19-Datei. Sie enthält
unser kompiliertes BASIC-Programm. Die Datei muß in das folgende
Hauptprogramm TEST1.BAS mittels SYSCODE-Befehl eingebunden und per SYS
&h101 gestartet werden:
| define a byte
define b byte define c byte b=100
syscode "test1_c.s19" |
| Bild 1.1b: In dieses BASIC-Programm wird das Kompilat eingebunden und mittels SYS &h101 aufgerufen |
Das obenstehende BASIC-Hauptprogramm wird ganz normal mit dem Standardcompiler übersetzt und zur C-Control gesendet. Es werden nun nicht nur BASIC-Token, sondern auch sogenannte Systembytes übertragen. Die Systembytes stellen unser kompiliertes Programm dar. Sie werden von der C-Control in das interne EEPROM (ab Adresse $101) geschrieben. Nach dem Programmstart sollte der Mikrokontroller auf dem RS232-Bus die Zahl 123 übertragen. Das kann mit einem Terminalprogramm kontrolliert werden.
Wer etwas von der Assemblersprache versteht, kann sich ja auch einmal
die vom Compiler erstellte ASM-Datei anschauen. Man sieht recht deutlich,
daß der Compiler sehr effektiven Programmcode erzeugt hat!
| org $101
lda $a2 ; 22 1
22 2 51 25 0
rts |
| Bild 1.1c: Der vom Compiler erzeugte Assemblercode (wird von AS05.EXE assembliert) |
Um ein kompiliertes Programm zur C-Control zu übertragen und zu starten, wird grundsätzlich ein nicht kompiliertes, zweites BASIC-Programm ("Hauptprogramm") benötigt, in dem das Kompilat mittels SYSCODE eingebunden und per SYS &h101 gestartet wird. Es ist wichtig, daß die vom Compiler erstelle S19-Datei in dem Verzeichnis steht, in dem auch der Quelltext des Hauptprogramms abgespeichert wird. Denn der SYSCODE-Befehl unterstützt bei der Angabe des Dateinamens keine Pfadangabe.
Weitere Beispielprogramme befinden sich am Ende dieser
HTML-Seite.
An dieser Stelle ist es vielleicht notwendig, die Begriffe Token, Tokenbefehl
und BASIC-Befehl genauer zu unterscheiden: Ein BASIC-Befehl ist das, was
der Benutzer in eine BAS-Datei schreibt (z.B. "PRINT a"). Diese BASIC-Befehle
werden vom Standardcompiler übersetzt und in Tokenbefehle umgewandelt
(z.B. "22 0 30 31 13 10 0"). Tokenbefehle bestehen aus einem Tokenbyte
und einem oder mehreren sich anschließenden Datenbytes oder Datenwords.
An dieser Stelle muß festgehalten werden, daß jeder BASIC-Befehl
aus mehreren Tokenbefehlen bestehen kann. Letztere führen immer nur
kleine Teilaktionen, wie das Pushen von Werten auf den Rechenstack,
Addieren mit Hilfe des Stacks, Poppen in eine Variable, oder ähnliches
aus.
| define a byte
define b byte define byteport1 byteport[1] #anfang
|
| Bild 2.1a: Der Quelltext des zu kompilierenden BASIC-Programms |
Die C-Control holt bei der Programmausführung ein Tokenbyte aus dem seriellen EEPROM und ruft die entsprechende Betriebssystemroutine auf. Falls zu dem Tokenbefehl noch zusätzliche Datenbytes gehören, werden diese selbsttätig von der Betriebssystemroutine aus dem EEPROM geholt.
Es ist überhaupt nicht schwierig, einen BASIC-Compiler zu erstellen,
der stur jeden Tokenbefehl in ein entsprechendes Assembleräquivalent
übersetzt, das einfach nur die passenden Betriebssystemroutinen aufruft.
BASIC-Programme, die auf diese Weise kompiliert wurden sind etwa um den
Faktor 7 mal schneller als Interpretierte. Da Tokenbefehle aber immer nur
kleine Teilaktionen durchführen und vom Rechenstack regen Gebrauch
machen, sind die erzeugten Kompilate jedoch weder geschwindigkeits- noch
platzoptimiert. Dabei ist Letzteres ganz besonders entscheidend, denn das
interne EEPROM ist ja nur 255 Byte groß!
| org $101
lab4:
lda $92 ; 25 0
clra ;lda #0 ; 22 0
lda #1 ;
22 1
jsr $155c ; 64 lda $91 ; 4 0 19
bra lab4 ; 3 0 4 lab19:
|
| Bild 2.1b: Der erzeugte, nicht optimale Assemblercode. Hier werden nur Betriebssystemroutinen aufgerufen. |
Aus diesem Grund besteht die Möglichkeit, in der Konfigurationsdatei CCBAS2MC.CFG mehrere, zusammengehörige Tokenbefehle gemeinsam abzuhandeln und optimierten Assemblercode zu erzeugen, der z.B. ohne Stack auskommt.
Beispiel: Wenn der C-Control-Mikrokontroller auf die Tokenbefehlskombination "11 0 25 0" trifft, pusht er zuerst den aktuellen Zustand von PORTB (an Adresse $1) auf den Stack und poppt anschließend den Wert vom Stack in die Bytevariable, die im RAM an Adresse $a1 liegt. Was liegt also näher, als diese Befehlskombination als eine Einheit ohne Umweg über den Stack in Assembler umzusetzen: "lda $1", "sta $a1" und fertig! Diese beiden Assemblerbefehle benötigen nur 4 Byte im internen EEPROM, die nicht optimierte Variante (die zudem weitaus langsamer ist) benötigt 8 bis 10 Bytes.
Ich habe in der Konfigurationsdatei bereits einige Optimierungen durchgeführt.
Wobei ich mich in erster Linie auf den optimierten Zugriff auf Bytevariablen,
Bytewerten, Byteports, Bitvariablen und Bitports beschränkt habe,
denn bekanntlich ist die 6805'er eine 8-Bit-CPU, weshalb auf Daten im Byteformat
ganz besonders leicht zugegriffen werden kann. Wenn in einem Programm Wordvariablen
oder Wordwerte auftauchen, wird unoptimierter Code erstellt, der einfach
zu jedem Tokenbefehl die entsprechende Betriebssystemroutine aufruft. Ebenso
verhält es sich mit komplexen Berechnungen, bei denen der Rechenstack
benutzt werden muß. Auf jeden Fall gibt es immer eine - wenn auch
vielleicht nicht optimale - Möglichkeit, jedes beliebige BASIC-Programm
in Maschinencode zu konvertieren.
| org $101
lab4:
;lda $a1 ; 22 0 22 1
64 4 0 19
;bra lab4 ; 3 0 4 ;lab19:
|
| Bild 2.1c: Durch das Zusammenziehen von Tokenbefehlen optimiertes Kompilat |
Wer die Konfigurationsdatei editieren möchte, sollte sich auf der
C-Control-intern-Homepage umschauen. Dort gibt es unter anderem das komplette
ROM-Listing des C-Control-Betriebssystems. Eine komplette
Tokenliste steht am Ende dieser Seite.
Optimierte Befehle im Byteformat
Zusätzlich zu den hier aufgeführten Befehlen werden FOR..NEXT-Schleifen mit Bytevariablen optimiert. Diese sind einige hundert mal schneller als in interpretiertem BASIC.
Ein Sternchen hinter einem Ziel bedeutet, daß eine Befehlkombination
nicht 100% kompatibel zum CCBASIC-Dialekt ist (siehe Inkompatiblitäten
zum CCBASIC-Dialekt).
| ZIEL | TERM | ||
| 1. Operand | Rechenoperation | 2. Operand | |
| IF..THEN*
Bytevariable= Byteport= DA-Port= Stack=* |
Bytewert
Bytevariable Byteport AD-Port |
AND
NAND OR NOR XOR |
Bytewert
Bytevariable Byteport |
| >
>= < <= = <> |
|||
| Bytevariable=
Byteport= DA-Port= Stack= |
MIN ( )
MAX ( ) |
||
| Bytevariable=
Byteport= DA-Port= |
+
- |
||
| Bytevariable= | Bytevariable | SHL
SHR |
1 |
| WERTZUWEISUNGEN
UND BEFEHLE
MIT EINEM OPERANDEN |
|
| IF..THEN
Bytevariable= Byteport= DA-Port= Stack= PUT GET |
Bytewert
Bytevariable Byteport AD-Port |
| Bytevariable=
Byteport= DA-Port= |
NOT(Bytewert)
NOT(Bytevariable) NOT(Byteport) NOT(AD-Port) |
| IF..THEN | RXD |
| NOT(RXD) | |
Optimierte Befehle im Bitformat
Die optimierten Bitbefehle werden zwar viel schneller ausgeführt
als in interpretiertem BASIC, doch sind sie relativ verschwenderisch mit
dem Platz im internen EEPROM. Es kann unter Umständen günstiger
sein, im Byteformat auf Bitports oder Bitvariablen zuzugreifen. Das ist
auch der Grund dafür, warum ich noch nicht alle Bitbefehle optimiert
habe.
| ZIEL | TERM | ||
| 1. Operand | Rechenoperation | 2. Operand | |
| IF..THEN | Bitvariable
Bitport |
AND
NAND OR NOR XOR |
Bitvariable
Bitport |
| =
<> |
|||
| WERTZUWEISUNGEN
UND BEFEHLE
MIT EINEM OPERANDEN |
|
| IF..THEN
Bitvariable= Bitport= |
Bitvariable
Bitport |
| Bitvariable=
Bitport= |
ON
OFF |
| IF..THEN | NOT(Bitvariable)
NOT(Bitport) |
| define a byte
define b byte define c byte c=(a+b) SHR 1 |
| Bild 3.1a: Dieser Ausdruck kann vom Compiler nicht optimiert werden |
Ein Ausdruck wie "a AND b OR c" könnte z.B. komplett im Byteformat
ausgewertet werden, wenn a, b und c Bytevariablen sind. Dagegen kann "a
+ b" nur im Byteformat berechnet werden, wenn das Resultat in einer Bytevariablen
oder einem Byteport gespeichert wird. Der Ausdruck "(a + b) SHR 1" kann hingegen
im allgemeinen auch dann nicht im Byteformat ausgewertet werden, wenn das
Ziel ein Byte ist. Denn wenn z.B. a=200 und b=100 ist, ergibt "(a + b)"
das Zwischenergebnis 44 (300 MOD 256, da ja im Byteformat gerechnet wird).
"SHR 1" entspricht einer Division durch 2, ergibt also 22. Der Anwender
erwartet aber 150. In diesem Fall muß also komplett im Wordformat
gerechnet werden. Allerdings geht das nur mit Programmcode, der deutlich
mehr Platz im internen EEPROM belegt. Es ist fraglich, ob sich dieser hohe
Aufwand lohnt.
| org $101
clra ;lda #0 ; 22 0
lda #1 ;
22 1
jsr $1342 ; 51 ldx #1 ;
20 0 1
jsr $1316 ; 47 lda $92 ; 25 2
rts |
| Bild 3.1b: Der Compiler erzeugt ein Kompilat, das die Berechnung mit Hilfe des Rechenstacks ausführt |
Theoretisch wäre es möglich, einen Compiler zu erstellen,
der alle Berechnungen nur im Byteformat durchführt. Das würde
allerdings bedeuten, die Kompatibilität zum CCBASIC-Dialekt aufzugeben.
| define a byte
define b byte define c byte c=a+b
|
| Bild 3.2a: Jetzt wurde der komplexe Term in zwei einfache aufgespalten |
Bis auf weiteres müssen komplexe Berechnungen im zu kompilierenden
BASIC-Programm in einfache Teilausdrücke zerlegt werden, damit der Compiler
Optimierungen durchführen kann. "d = a AND
b OR c" muß in "d = a AND b" und "d = d OR c" zerlegt werden; "d
= (a + b) SHR 1" wird zu "d = a + b" und "d = d SHR 1"; und so weiter.
Hierbei führt der Compiler automatisch Optimierungen durch, so daß
im fertigen Kompilat nicht ständig in die Variable d geschrieben und
aus dieser gelesen wird. Der einzige Nachteil, der in Kauf genommen werden
muß, ist, daß das Schreiben des BASIC-Programms etwas umständlicher
wird.
| org $101
lda $a1 ; 22 0
22 1 51 25 2
;lda $a3 ; 22 2 20 0
1 47 25 2
rts |
| Bild 3.2b: Wider erwarten ist das Kompilat deutlich kürzer und sehr viel schneller |
Wie bereits an anderer Stelle erwähnt, ist das natürlich kein
Muß. Es kann auch jeder andere Berechungsterm verwendet werden -
allerdings wird dieser dann nicht optimal in Maschinensprache umgesetzt
und verschwendet unnötig Rechenzeit und kostbaren Speicherplatz im
internen EEPROM.
.
Die Inkompatiblitäten könnten durch Editieren der Konfigurationsdatei
mit mehr oder weniger großem Aufwand eliminiert werden. Vermutlich
wird sich darum die Liste der Inkompatiblitäten in folgenden Versionen
des Compilers ändern. Trotzdem würde ich gern Rückmeldungen
von anderen Anwendern erhalten, in wie weit sich der Compiler an die Vorgaben
des CCBASIC-Dialekts halten soll. Es ist nämlich auch denkbar, zugunsten
von Platz- und Geschwindigkeitsoptimierungen darauf weitgehend zu verzichten.
Am Beginn der Datei stehen einige Informationen, die beim Ändern oder Hinzufügen nützlich sind. Dahinter folgen die 84 nicht optimierten Tokenbefehle, auf die vom Compiler immer dann zurückgegriffen wird, wenn kein optimierter Befehl existiert. Die optimierten Befehle stehen am Ende der Datei.
Bitte bei Veränderungen Vorsicht walten lassen und vorher die angegeben
Beispiele genau studieren. Der Compiler führt zwar etliche Kausalitätsprüfungen
durch, doch kann er natürlich nicht in jedem Fall erraten, was der
Programmierer erreichen möchte.
Das Übertragen und Empfangen von Werten über die RS232-Schnittstelle kann problemlos in interpretiertem BASIC vorgenommen werden. Die Schnittstelle ist so langsam, daß die Ablaufgeschwindigkeit des Programms so gut wie keine Rolle spielt.
Wer eigene BASIC-Befehle "designen" möchte, kann mitten im zu kompilierenden BASIC-Programm, an einer Stelle, an der normalerweise Befehle stehen, eine Tabelle einfügen oder eine Subroutine aufrufen, die eine Tabelle enthält. In diese Tabelle werden dann eigene Kunsttoken geschrieben, mit der die C-Control normalerweise nichts anzufangen weiß. Wenn nun in der Konfigurationsdatei CCBAS2MC.CFG zu diesen Token Assemblercode steht, wird der natürlich auch ins Kompilat übernommen! Als Kunsttoken dürfen alle Bytes von 85 bis 99 benutzt werden. Wer noch mehr zusätzliche Befehle benötigt, kann auch zwei Bytes als Token benutzen.
Falls der kompilierte Teil eines Programms bereits fehlerfrei funktioniert und nur noch Änderungen an dem interpretiertem Hauptprogramm durchgeführt werden müssen, sollte vor dem Übertragen des Programms zur C-Control Unit der SYSCODE-Befehl auskommentiert werden. In diesem Fall wird das Kompilat (das sich ja im internen EEPROM befindet) nicht verändert und so wertvolle Schreibzyklen gespart. Laut Motorola verträgt das interne EEPROM nur 10000 (in Worten: zehntausend) Programmierzyklen!
Der C-Control-Einplatinencomputer basiert zum Großteil auf dem
MC68HC05B6 Mikrokontroller von der Firma Motorola. Conrad Electronic hat
für diesen Chip ein eigenes Betriebssystem inklusive BASIC-Interpreter
geschrieben, von Motorola in das ROM brennen lassen und diesen Chip anschließend
zusammen mit einem Quarz und einem seriellen EEPROM auf eine Platine gelötet,
und fertig war der C-Control-Einplatinencomputer. Von Motorola gibt es
aber auch vollständig kompatible Mikrokontroller, die statt ROM ein
EPROM besitzen (z.B. MC68HC705B16-N). Diese Kontroller haben sogar mehr
RAM und das EPROM ist größer als das ROM des MC68HC05B6. Das
EPROM könnte problemlos das Betriebssystem der C-Control-Unit aufnehmen,
so daß noch genug Platz bliebe, um zusätzlich auch ein mehrere
Kilobyte großes kompiliertes BASIC-Programm hineinzuprogrammieren.
Auf diese Weise könnten relativ problemlos schnelle Programme für
einen Mikrokontroller in BASIC entwickelt werden. Üblicherweise müssen
diese in Assembler oder in der Sprache C programmiert werden. Wenn leichte
Veränderungen am Betriebssystem vorgenommen werden, kann man sogar
ohne das serielle EEPROM am I²C-Bus auskommen. Auf jeden Fall ist
zu beachten, daß der ORG-Befehl am Beginn der vom Compiler erstellen
ASM-Datei die Adresse enthält, an der das Kompilat später im
Speicher steht. Weitere Informationen zu den EPROM-Mikrokontrollern gibt
es auf der Internetsite von Motorola oder im Manual zum MC68HC05B6.
Es ist auch möglich, das Geld auf mein Konto zu überweisen. Im Feld "Verwendungszweck" muß dann eine gültige e-mail-Adresse und dahinter "CCBAS2MC" angegeben werden. Die Durchschrift oder eine Kopie des Überweisungsbelegs sollte aus Sicherheitsgründen zusätzlich an meine Postadresse geschickt werden. Das Konto bei der Deutschen Bank ist nicht mehr aktiv. Bitte nur noch das unten angegebene Konto bei der Advance Bank benutzen.
Nach dem Freischalten kann das Programm unbegrenzt oft benutzt werden. Falls Updates erscheinen, können diese ebenfalls freigeschaltet werden oder es werden vergünstigte Updatepreise für registrierte Benutzer angeboten.
Durch das Zahlen der Registriergebühr wird die Weiterentwicklung des Programms und die Entwicklung neuer Programme direkt unterstützt. Wer sich nicht registrieren läßt, schneidet sich also ins eigene Fleisch.
Falls jemand mehr als 30 Testmöglichkeiten benötigt, kann
er den Compiler (CCBAS2MC.EXE) und die Konfigurationsdatei (CCBAS2MC.CFG)
löschen und anschließend das ZIP-Archiv, in dem die beiden Dateien
aus dem Internet heruntergeladen wurden, neu entpacken. Danach kann der
Compiler weitere 30 mal gestartet werden. Aus moralischen Gründen
sollte das aber nicht zu häufig geschehen.
.
| Meine Postadresse:
Dietmar Harlos Webereistraße 25 32139 Spenge |
e-mail:
dharlos@web.de . . |
(Neue) Bankverbindung:
Advance Bank München Bankleitzahl 702 300 00 Kontonummer 3008620647 |
Das Copyright der Dateien CCBAS2MC.EXE, CCBAS2MC.CFG und INFO.HTM liegt bei Dietmar Harlos. CCBAS2MC.EXE und INFO.HTM dürfen nicht ohne meine Genehmigung in irgendeiner Weise verändert und dann weitergegeben werden. Änderungen an CCBAS2MC.CFG müssen im Dateikopf hinter dem Copyright kenntlich gemacht werden.
Das ZIP-Archiv, in dem das Programmpaket enthalten war, darf unverändert
an jeden interessierten Anwender weitergegeben werden, sofern dies unentgeltlich
geschieht. Das registrierte Programm CCBAS2MC.EXE darf ebensowenig wie
der Registrierschlüssel an eine dritte Person weitergegeben werden.
| define a byte
define byteport1 byteport[1] for a=0 to 255
|
| Bild 4.1a: Die FOR..NEXT-Schleife läuft interpretiert etwa 870 ms. Als optimiertes Kompilat werden nur 3.8 ms benötigt! |
| org $101
clr $a1 ;lda #0 ; 20 0 0 25 0
lab9:
lda $a1 ; 20 0
255 74 0 0 27
inc $a1 ;lda $a1 ; 20 0 1 76 0 0 9
lab27:
|
| Bild 4.1b: Die hochoptimierte FOR..NEXT-Schleife - rund 235 mal schneller als interpretiertes BASIC. |
In diesem Beispiel wird außerdem gezeigt, wie Daten an das Hauptprogramm
(blau hinterlegt) mit Hilfe des Befehls "RETURN wert" zurückgegeben
werden können.
| define a byte
define b byte define clock port [2] define io port [3] b=0
|
| Bild 5.1a: Programmsegment zum Lesen von einer Chipkarte. Die Rückgabe erfolgt über den Stack. |
| define a byte
define b byte ... define clock port [2] define io port [3] ...
#chipkartenbyte
syscode "test51a.s19" |
| Bild 5.1b: Das Hauptprogramm zum Lesen von einer Chipkarte. Die Rückgabe erfolgt über den Stack. |
| org $101
clr $a2 ;lda #0 ; 20 0 0 25 1
clr $a1 ;lda #0 ; 20 0 0 25 0
lab14:
brclr #2,$01,lab35 ; 10 2 4 0 35 lda $a2 ; 22 1
20 0 1 43 25 1
lab35:
lda $a1 ; 20 0
7 74 0 0 51
inc $a1 ;lda $a1 ; 20 0 1 76 0 0 14
lab51:
rts ; 6 |
| Bild 5.1c: Der vom Kompiler erzeugte Assemblercode. Der PULSE-Befehl ist platz- aber nicht geschwindigkeitsoptimal |
Die in der Tabelle aufgeführte Adresse gibt an, an welcher Adresse
im ROM die Hauptroutine des jeweiligen Befehls beginnt.
| Token | Adresse | Befehl (und Beschreibung) |
| 0 | $15B7 | ignoriert, 1 Byte lang |
| 1 | $15B8 | intern, Rechenstack loeschen |
| 2 | $15BB | PAUSE |
| 3 w | $15CB | GOTO, ELSE |
| 4 w | $15E0 | IF .. THEN (hole das letzte Word vom Stack und springe zur Adresse w, falls das Word gleich 0 ist) |
| 5 w | $169D | GOSUB |
| 6 | $16A6 | RETURN |
| 7 | $1A0B | RETURN INTERRUPT |
| 8 w | $170A | SYS |
| 9 b | $1714 | SLOWMODE |
| 10 b | $1720 | intern, push data from bitport b to stack |
| 11 b | $172B | intern, push data from byteport b to stack |
| 12 | $1736 | intern, push data from wordport to stack |
| 13 b | $1740 | intern, store Top-Of-Stack to bitport b |
| 14 b | $174B | intern, store Top-Of-Stack to byteport b |
| 15 | $1756 | intern, store Top-Of-Stack to wordport |
| 16 b | $1761 | intern, push data from ad-port b to stack |
| 17 b | $176F | intern, store Top-Of-Stack to da-port b |
| 18 | $15B7 | ignoriert, 1 Byte lang |
| 19 | $15B7 | ignoriert, 1 Byte lang |
| 20 w | $1796 | intern, push wordvalue w to stack |
| 21 b | $17A0 | intern, push bitvar b to stack |
| 22 b | $17A7 | intern, push bytevar b to stack |
| 23 b | $17AE | intern, push wordvar b to stack |
| 24 b | $17B5 | intern, store Top-Of-Stack to bitvar b |
| 25 b | $17BC | intern, store Top-Of-Stack to bytevar b |
| 26 b | $17C3 | intern, store Top-Of-Stack to wordvar b |
| 27 w | $17CA | LOOKTAB (hole die Nummer des zu lesenden Eintrags vom Stack und speichere anschliessend das Word von Adresse w + Eintrag auf dem Stack) |
| 28 b | $1806 | intern, push internal var b to stack |
| 29 b | $1881 | intern, store Top-Of-Stack to internal var b |
| 30 | $18D4 | PRINT number |
| 31 s | $18DF | PRINT string |
| 32 | $18ED | PUT |
| 33 | $18F2 | RXD |
| 34 | $18F9 | GET |
| 35 | $1915 | INPUT |
| 36 b | $1900 | HANDSHAKE |
| 37 | $190E | CTS |
| 38 | $15B7 | ignoriert, 1 Byte lang |
| 39 | $15B7 | ignoriert, 1 Byte lang |
| 40 | $12B6 | NOT |
| 41 | $12C3 | AND |
| 42 | $12D2 | NAND |
| 43 | $12D6 | OR |
| 44 | $12E5 | NOR |
| 45 | $12E9 | XOR |
| 46 | $12F8 | SHL |
| 47 | $1316 | SHR |
| 48 | $1442 | RANDOMIZE |
| 49 | $1468 | RAND |
| 50 | $1334 | intern, (unary -) negate last word on stack |
| 51 | $1342 | intern, (+) add last two words on stack & push result to stack |
| 52 | $1351 | intern, (-) subtract last word on stack from last-but-one word & push result |
| 53 | $1360 | intern, (*) multiply last two words on stack & push result |
| 54 | $137E | intern, (/) divide last-but-one word on stack by last word & push result |
| 55 | $139C | MOD |
| 56 | $13BA | ABS |
| 57 | $13E8 | SQR |
| 58 | $1484 | MAX |
| 59 | $14A4 | MIN |
| 60 | $14C4 | intern, (>) test if last-but-one word is bigger than last word & push result |
| 61 | $1510 | intern, (>=) test if last-but-one word is bigger/equal last word & push result |
| 62 | $14EA | intern, (<) test if last-but-one word is lower than last word & push result |
| 63 | $1536 | intern, (<=) test if last-but-one word is lower/equal to last word & push result |
| 64 | $155C | intern, (=) test if last two words on stack are equal & push result |
| 65 | $1579 | intern, (<>) test if last two words are not equal & push result |
| 66 | $13CC | SGN |
| 67 | $15B7 | ignoriert, 1 Byte lang |
| 68 | $15B7 | ignoriert, 1 Byte lang |
| 69 | $15B7 | ignoriert, 1 Byte lang |
| 70 b | $197C | Befehle zum Zugriff auf die Datendatei (OPEN# FOR READ, OPEN# FOR WRITE, OPEN# FOR APPEND, CLOSE#, PRINT# oder INPUT#) |
| 71 | $19D8 | EOF |
| 72 b | $19DF | BAUD |
| 73 w | $19E6 | INTERRUPT w an Adresse $b9,$ba schreiben |
| 74 b w | $161F | intern, fuer FOR..NEXT-Schleifen: Vergleiche Word auf dem Stack mit der Bytevariablen b, falls beide gleich sind springe nach w |
| 75 b w | $1628 | intern, fuer FOR..NEXT-Schleifen: Vergleiche Word auf dem Stack mit der Wordvariablen b, falls beide gleich sind springe nach w |
| 76 b w | $1631 | intern, fuer FOR..NEXT-Schleifen: Addiere zur Bytevariablen b das letzte Word auf dem Stack und springe zur EEPROM-Adresse w |
| 77 b w | $1640 | intern, fuer FOR..NEXT-Schleifen: Addiere zur Wordvariablen b das letzte Word auf dem Stack und springe zur EEPROM-Adresse w |
| 78 | $15B7 | ignoriert, 1 Byte lang |
| 79 | $15B7 | ignoriert, 1 Byte lang |
| 80 b | $177A | TOG |
| 81 b | $1781 | PULSE |
| 82 b | $1788 | DEACT bitport b |
| 83 b | $178F | DEACT byteport b |
| 84 | $0A82 | DEACT wordport |
| 255 | END |