Lars H. Hahn CoLa - Codesign Language Referenz-Handbuch Universität Hamburg Fachbereich Informatik Arbeitsbereich „Technische Grundlagen der Informatik“ Stand: 19.12.2000 1 Einleitung......................................................................................................................5 1.1 Systembegriff.......................................................................................................5 1.2 Entwurfsprozeß ....................................................................................................6 1.3 Ein einfaches Beispiel ..........................................................................................7 1.4 Lexikalische Struktur ...........................................................................................7 2 Datentypen....................................................................................................................9 2.1 Vordefinierte Typen .............................................................................................9 2.2 Benutzerdefinierte Typen ...................................................................................11 2.3 Arraytyp.............................................................................................................11 2.4 Kartesisches Produkt..........................................................................................12 2.5 Konstanten und Literale .....................................................................................12 3 Zuweisungen und Arithmetik ....................................................................................15 3.1 Zuweisungen......................................................................................................15 3.2 Implizite Konvertierungen..................................................................................16 3.3 Explizite Konvertierungen..................................................................................16 3.4 Grundrechenarten...............................................................................................17 3.5 Vergleichsoperatoren .........................................................................................17 3.6 Logische Operatoren ..........................................................................................17 3.7 Schiebeoperationen ............................................................................................18 4 Kontrollstrukturen .....................................................................................................21 4.1 Gültigkeitsbereiche ............................................................................................21 4.2 Verzweigungen ..................................................................................................21 4.3 Switch-Anweisung .............................................................................................21 4.4 Schleifen ............................................................................................................22 5 Funktionen und Prozesse............................................................................................25 5.1 Funktionen .........................................................................................................25 5.2 Automaten .........................................................................................................26 5.3 Rekursive Funktionen ........................................................................................27 5.4 Parallele Ausführungen ......................................................................................27 5.5 Prozesse .............................................................................................................28 5.6 Prozeßkommunikation........................................................................................28 6 Vordefinierte Funktionen...........................................................................................29 6.1 abs .....................................................................................................................29 6.2 cos .....................................................................................................................29 6.3 int ......................................................................................................................29 6.4 sp .......................................................................................................................29 6.5 max....................................................................................................................29 6.6 min.....................................................................................................................30 6.7 sin ......................................................................................................................30 6.8 sint .....................................................................................................................30 6.9 sum ....................................................................................................................30 7 Zeitbedingungen .........................................................................................................31 7.1 Absolute Zeitbedingungen..................................................................................31 7.2 Relative Zeitbedingungen...................................................................................31 7.3 Zeitbedingungen bei parallelen Instruktionen .....................................................32 Seite 4 7.4 7.5 CoLa Referenz-Handbuch Zeitbedingungen für Verzweigungen und Schleifen............................................32 Ausführungszeitpunkte.......................................................................................33 8 Ausnahmen und Unterbrechungen ............................................................................35 8.1 Abfangen von Unterbrechungen .........................................................................35 8.2 Laufzeitfehler.....................................................................................................35 8.3 Benutzerdefinierte Ausnahmen...........................................................................36 8.4 Unterbrechungen................................................................................................36 9 Kurzreferenz...............................................................................................................39 9.1 ':='......................................................................................................................39 9.2 ':~'......................................................................................................................39 9.3 '==' / '!=' / '<' / '>=' / '>' / '<=' ..............................................................................39 9.4 '>>' / '<<' ............................................................................................................39 9.5 '#>' / '<#'.............................................................................................................40 9.6 '&' / '|' .................................................................................................................40 9.7 AND ..................................................................................................................41 9.8 AUTOMAT .......................................................................................................41 9.9 BOOL ................................................................................................................41 9.10 CHAR...................................................................................................................42 9.11 CONST.................................................................................................................42 9.12 DELAY ................................................................................................................42 9.13 FUNCTION..........................................................................................................42 9.14 IF / ELSE..............................................................................................................43 9.15 INTERRUPT ........................................................................................................43 9.16 LOOP / WHILE....................................................................................................43 9.17 NOT .....................................................................................................................44 9.18 NUM / SNUM ......................................................................................................44 9.19 OR........................................................................................................................45 9.20 RATE ...................................................................................................................45 9.21 RAISE / CATCH ..................................................................................................45 9.22 STEP ....................................................................................................................46 9.23 STRUCT ..............................................................................................................46 9.24 SWITCH...............................................................................................................46 9.25 TRUE / FALSE ....................................................................................................47 9.26 TYPE....................................................................................................................47 9.27 VECTOR..............................................................................................................47 9.28 XOR .....................................................................................................................48 10 Literaturverzeichnis ...................................................................................................49 11 Anhang........................................................................................................................51 11.1 Reservierte Wörter................................................................................................51 11.2 Vollständige Syntax ..............................................................................................51 1 Einleitung CoLa (Codesign Language) ist eine Beschreibungssprache zur Spezifikation von Systemen mit Software- und Hardwareanteilen (HW-/SW-Systeme). CoLa enthält deshalb sowohl Anteile von klassischen Programmiersprachen als auch von Hardwarebeschreibungssprachen. Dennoch ist CoLa mehr als die Summe unterschiedlicher Sprachkonstrukte aus beiden Bereichen. Vielmehr war es Ziel bei der Konzeption von CoLa, die Umsetzung aller Konstrukte sowohl in Hardware als auch in Software zu ermöglichen. Die Auswahl eines Sprachmittels durch den Entwerfer legt noch nicht die spätere Partitionierung in Hardware und Software fest. Diese Entscheidung wird erst durch einen Compiler aufgrund des Kontextes und der Randbedingungen getroffen. CoLa eignet sich besonders zur Spezifikation von eingebetteten Systemen (embedded systems) auf der Systemebene. Gerade hier geht es darum, Systeme „aus einem Guß“ zu entwerfen. Ziel ist es, zunächst das Verhalten des gesamten Systems zu spezifizieren, um dann möglichst automatisch eine konkrete Realisierung in Hardware und Software zu erhalten. Dieser Bericht enthält die Definition der Syntax und der Semantik der Sprache CoLa. Für weitere Informationen der zugrunde liegenden Entwurfsmethodik wird auf die Dissertation des Autors verwiesen. Dieser Bericht erläutert somit nicht die Intentionen, die zur Aufnahme des einen oder anderen Konstruktes in den Sprachumfang von CoLa führten. Es findet an dieser Stelle auch kein Vergleich mit anderen Sprachen statt, sondern es wird ausschließlich die Bedeutung der Sprachkonstrukte erläutert. Auch wird nicht erklärt, wie eine Umsetzung in Hardware oder Software erfolgt oder wie eine mögliche Partitionierung aussehen könnte. Dieser Bericht beantwortet also nicht die Frage, warum sich CoLa besonders gut für den Entwurf von Codesign-Systemen eignet, sondern er gibt eine Anwort darauf, wie man eine korrekte Beschreibungen in CoLa erstellt. 1.1 Systembegriff CoLa ist ein Sprache zur Spezifikation von HW/SW-Systemen. Es ist deshalb sinnvoll zunächst zu definieren, was ein HW/SW-System genau ist. In [SCHNEIDER] findet sich folgende Definition des Begriffs „System“: „Ein System ist eine abgegrenzte Anordnung von aufeinander einwirkenden Gebilden. Solche Gebilde können sowohl Gegenstände als auch Denkmethoden und deren Ergebnisse sein. Diese Anordnung wird durch eine Hüllfläche von ihrer Umgebung abgegrenzt oder abgegrenzt gedacht. Durch die Hüllfläche werden Verbindungen des Systems mit seiner Umgebung geschnitten. Die mit diesen Verbindungen übertragenen Eigenschaften und Zustände sind die Größen, deren Beziehungen untereinander das dem System eigentümliche Verhalten beschreiben.“ Diese Definition ist für ein HW/SW-System schon erstaunlich gut geeignet. Ersetzt man „Gegenstände“ durch „Hardware“ und „Denkmethoden“ durch „Software“ und formuliert man etwas knapper und moderner, so erhält man die folgende Definition für ein HW/SWSystem: Seite 6 CoLa Referenz-Handbuch „Ein HW-/SW-System ist eine abgegrenzte Anordnung von miteinander interagierenen Einheiten. Einheiten können sowohl Hardware als auch Software sein. Das System hat eine feste Grenze zu seiner Umgebung. Es gibt Verbindungen zwischen System und Umgebung. Die über die Verbindungen übertragenen Werte beschreiben das Verhalten des Systems.“ Teilweise wird ein HW/SW-System auch als „heterogenes System“ bezeichnet. Dies ist allerdings mißverständlich, da nicht deutlich wird, welches die heterogene Teile des Systems sind. Es könnte z.B. auch ein System gemeint sein, das sowohl aus analogen als auch aus digitalen Komponenten besteht. 1.2 Entwurfsprozeß Zu Beginn eines jeden Entwurfsprozesses steht die Beschreibung des Systems auf der höchsten Abstraktionsebene. Am Ende des Entwurfsprozesses steht das fertige System auf der untersten Abstraktionsebene. Im Laufe des Entwurfsprozesses wird das System von einer Abstraktionsebene auf die nächst Tiefere transformiert. Auf jeder Abstraktionsebene gibt es eine Beschreibung des Systems und es kann die korrekte Funktionsweise des Systems überprüft werden. Der vorstehende Absatz beschreibt umgangssprachlich den Entwurfsprozeß eines Systems. Im folgenden wird die umgangssprachliche Formulierung schrittweise präzisiert. Es werden zunächst Systeme im allgemeinen betrachtet. In den folgenden Abschnitten wird der Entwurf von Soft- und Hardware im speziellen dargestellt. In [MARWEDEL] findet sich folgende Definition des Begriffs „Synthese“: „Synthese ist das Zusammensetzen von Komponenten oder Teilen einer niedrigeren Ebene zu einem Ganzen mit dem Ziel, ein auf einer höheren Ebene beschriebenes Verhalten zu erzielen.“ Definition 1.1 Häufig wird in der Literatur zwischen „Synthese“ und „Konstruktion“ unterschieden. Wobei „Konstruktion“ der allgemeinere Begriff ist. Mit „Synthese“ werden dann ausschließlich automatische Verfahren bezeichnet. Bisher wurde im allgemeinen von einer Beschreibung des Systems gesprochen. Es ist aber sinnvoll zwischen Beschreibungen auf unterschiedlichen Abstraktionsebenen zu unterscheiden. In diesem Zusammenhang läßt sich Synthese auch knapper als Übergang zwischen unterschiedlichen Beschreibungen auffassen: „Synthese ist die Überführung einer Spezifikation in eine Implementierung. Wobei Spezifikation die Beschreibung eines Systems auf der höheren Abstraktionsebene und Implementation die Beschreibung auf der niedrigeren Ebene ist.“ Definition 1.2 CoLa Referenz-Handbuch Seite 7 Abstraktionsebene n+1 Spezifikation Synthese Abstraktionsebene n Implementierung Abbildung 1.1 1.3 Ein einfaches Beispiel Ein einfaches Programm könnte in CoLa wie folgt formuliert werden: (num(32) out) function simple (num(32) in); function simple ( out := in * 3; ); Im obigen Beispiel wird die Funktion simple zunächst deklariert, d.h. die Ein- und Ausgangsparameter werden festgelegt. In diesem Beispiel gibt es nur einen Eingangsparameter in und einen Ausgangsparameter out. Beide haben den Typ „num(32)“. Dieser wird intern als positive 32-Bit Ganzzahl repräsentiert. Es folgt die Definition der Funktion simple. Der Eingangsparameter in wird mit der Konstanten '3' multipliziert und dem Ausgangsparameter out zugewiesen. Wobei die '3' hier für eine abstrakte Zahl steht. Es ist Aufgabe eines Compilers, eine passende Repräsentation zu wählen. Jedes CoLa-Programm muß mindestens eine Funktion enthalten. Die Funktion, deren Name mit dem Dateinamen identisch ist, ist der Startpunkt des Kontrollflusses ähnlich dem 'main' in 'C'. Diese Funktion wird Toplevel-Funktion genannt. Im Gegensatz zu 'C' wird die ToplevelFunktion nicht nur einmal gestartet und abgearbeitet, sondern wiederholt angestoßen. Die Toplevel-Funktion wird also quasi in einer Endlosschleife immer wieder aufgerufen. 1.4 Lexikalische Struktur Die lexikalische Struktur einer Sprache ist die Struktur ihrer Wörter, die Token genannt werden. Im folgenden werden vier Arten von Token unterschieden: Reservierte Wörter, z.B. function, Literale, z.B. 13, Sonderzeichen, z.B. >=, Bezeichner, z.B. in7. Bezeichner in CoLa bestehen aus Buchstaben, Zahlen und dem „Unterstrich“ ('_'). Am Anfang eines Bezeichners muß immer ein Buchstabe stehen. Umlaute und weitere Sonderzeichen sind nicht erlaubt. Reservierte Wörter heißen so, weil ein Bezeichner nicht aus Seite 8 CoLa Referenz-Handbuch derselben Zeichenfolge bestehen kann wie ein reserviertes Wort. Zwischen Groß- und Kleinschreibung wird weder bei Bezeichnern noch bei reservierten Wörtern unterschieden. In CoLa können Kommentare wie in C++ ('//') oder wie in VHDL ('--') eingefügt werden. Ein Kommentar endet mit dem Zeilenende. // Dies ist ein Kommentar -- dies auch Blöcke werden in CoLa in „normale“ Klammern '(' und ')' eingeschlossen. 2 Datentypen Ein Datentyp (kurz Typ) ist eine Menge von Werten. Variablen werden mit Hilfe der Datentypen deklariert, d.h. ihnen können im folgenden nur Werte aus der Menge, die dem Typ entspricht, zugewiesen werden. CoLa kennt vordefinierte und benutzerdefinierte Datentypen. Alle vordefinierten Typen in CoLa (num, snum, bool und char) sind einfache Datentypen. Der Benutzer kann in CoLa eigene Datentypen definieren. Hierzu stehen unterschiedliche Typkonstruktoren (type, vector und struct) zur Verfügung. Da Typen als Mengen betrachtet werden können, sind Typkonstruktoren somit Mengenoperationen, die aus den vorhandenen Typen (Mengen) neue erstellen. CoLa ist streng typisiert (strongly typed). Die gesamte Typüberprüfung (type checking) findet zur Übersetzungszeit statt. Während der Typüberprüfung stellt sich die Frage der Typäquivalenz. Die in CoLa verwendete Typäquivalenz ist die strukturelle Äquivalenz. Zwei Typen sind also gleich, wenn sie dieselbe Struktur besitzen. Dies bedeutet, daß sie mit dem gleichen Typkonstruktor aus den gleichen vordefinierten Typen aufgebaut wurden. 2.1 Vordefinierte Typen CoLa enthält num als fundamentalen vordefinierten Typ. Er dient zur Beschreibung von positiven Festkommazahlen fester maximaler Größe. Bei jeder Deklaration einer Variablen vom Typ num muß die Anzahl der für die Variable zur Verfügung stehenden Bits explizit angegeben werden: num(100) gamma; num(20) delta1, delta2; Für die Variable gamma werden 100 Bit reserviert. Dies entspricht einem Wertebereich von [0, 2100-1] bzw. [0, 1267650600228229401496703205375]. Es können mehrere Variablen gleichen Typs hintereinander in einer Zeile deklariert werden. Die Variablen delta1 und delta2 sind beide vom Typ num(20). Um vorzeichenbehaftete Zahlen verwenden zu können stellt CoLa den Typ snum (signed number) zur Verfügung. Für die folgende Variable alpha werden 8 Bit reserviert. Sie hat einen Wertebereich von [–128; 127]. snum(8) alpha; Die interne Darstellung von vorzeichenbehafteten Zahlen erfolgt im Zweierkomplement. Es ist ein Zugriff auf einzelne Bits möglich: num(8) alpha; num(1) beta; snum (3) gamma; beta := alpha[7]; gamma := alpha[3..1]; Seite 10 CoLa Referenz-Handbuch Der Variablen beta wird das höchstwertigste Bit von alpha zugewiesen, wobei das höchstwertigste Bit immer ganz links steht. Das niederwertigste Bit steht somit immer rechts und ein Zugriff erfolgt über den Indexwert '0'. gamma werden drei Bits von alpha zugewiesen. Dabei wird keine Vorzeichenkonvertierung vorgenommen. Vielmehr ist es so das die Zugriffsoperatoren '[' und ']' immer den Typ num liefern. Hat alpha z.B. den Wert 6610 (10000102) , so wird gamma der Wert 110 (0012) zugewiesen. Genaugenommen ist num(8) die Kurzschreibweise für num(8,0), einer Variablen ohne Nachkommastellen. Beispiele für Variablendeklarationen von Festkommazahlen mit Nachkommastellen sind: num(4,4) delta1; snum(4,4) delta2; Die Variable delta1 wurde mit vier Bits vor dem Komma und mit vier Bits nach dem Komma deklariert. Die Variable delta2 wurde ebenso deklariert, sie ist im Unterschied zu 15 delta1 vorzeichenbehaftet. Der Wertebereich von delta1 ist 0; 15 . Die kleinste von 16 1 = 0,0625 . Analog hierzu ist der Wertebereich von delta2 Null verschiedene Zahl ist 16 15 − 8; 7 16 . Mit den Typen bool und char stellt CoLa zusätzlich zum Typ num zwei weitere vordefinierte Typen zur Verfügung. CoLa unterstützt explizit Boolsche Datentypen. Eine Variable vom Typ bool kann somit die Werte 'true' und 'false' annehmen. bool wahroderfalsch1; num(1) wahroderfalsch2; Der Typ bool entspricht gemäß seiner internen Darstellung einem num(1). Der Wert 'true' wird durch eine '1' repräsentiert, der Wert 'false' durch eine '0'. Die Typen der Variablen wahroderfalsch1 und wahroderfalsch2 sind in diesem Beispiel also austauschbar. Ein Boolscher Wert wird verwendet, um das Ergebnis einer logischen Operation darzustellen. Einer Variablen vom Typ char kann ein ASCII-Zeichen zugewiesen werden: char zeichen1; num(8) zeichen2; zeichen := 'a'; Der Typ char entspricht einem num(8). Auch hier sind die Typen der Variablen zeichen1 und zeichen2 austauschbar. Der Wertebereich einer Variablen vom Typ char ist somit [0, 255]. CoLa Referenz-Handbuch Seite 11 2.2 Benutzerdefinierte Typen CoLa erlaubt dem Benutzer, eigene Typen, sogenannte benutzerdefinierte Typen, zu definieren. Hierzu steht der Typkonstruktor type zur Verfügung. Zwei weitere Typkonstruktoren werden mit vector und struct in den folgenden Abschnitten beschrieben. Beispiele für benutzerdefinierte Typen sind: type n32 num(32); n32 alpha; num(32) beta; Die Variable alpha ist vom Typ num(32). n32 wurde lediglich als Alias für diesen Typ definiert. Somit sind die Variablen alpha und beta hier vom gleichen Typ. Sie wurden lediglich auf zwei unterschiedliche Arten definiert. Die Typen beider Variablen sind strukturell äquivalent. 2.3 Arraytyp Ein Array ist eine Funktion f, die einen Indextyp U auf einen Komponententyp V abbildet: f: U → V Der Indextyp muß in CoLa vom Typ num(?,0) sein, d.h. positiv und ganzzahlig sein. Der Komponententyp ist beliebig. Arrays sind sogenannte homogene Typen, d.h. alle Elemente (= Komponenten) sind vom gleichen Typ. Dies ermöglicht einen dynamischen Zugriff auf die Elemente, da alle Elemente einen gleich großen Platz im Speicher benötigen. Der Indexwert kann somit auch erst zur Laufzeit berechnet werden. Der in CoLa enthaltene Typkonstruktor für einen benutzerdefinierten Arraytyp ist vector: type v10 vector(10) num(16); v10 alpha; vector(10) num(16) beta; Es wird zunächst der Typ v10 definiert. Mit dessen Hilfe wird ein Array alpha mit zehn Elementen deklariert. Jedes Element des Arrays ist vom Typ num(16). Die typäquivalente Variable beta wird direkt definiert, d.h. ihr Typ erhält keinen eigenen Namen. Mit Hilfe der eckigen Klammern '[' und ']' kann auf einzelne Elemente eines Arrays zugegriffen werden. num(10) beta; beta := alpha[3]; Einzelne Variablen können zu einem Array konkateniert werden. Ebenso kann ein Array zerteilt werden. vector(3) num(10) alpha; vector(2) num(10) beta; num(10) a, b, c; alpha := (a, b, c); Seite 12 CoLa Referenz-Handbuch beta := alpha[0..1]; Soll ein Array zerteilt werden, so müssen die Grenzen der Teilung bereits zur Übersetzungszeit bekannt sein. Der Zugriff auf ein einzelnes Element des Arrays kann über einen erst zur Laufzeit berechneten Wert erfolgen. In CoLa können auch mehrdimensionale Arrays definiert werden: vector(6) vector(5) vector(4) num(16) gamma; gamma[1][2][3] := 17; gamma[1][2] := (6, 7, 8, 9); Es wird zunächst ein dreidimensionales Feld deklariert. Es können sowohl einzelnen Werte als auch ganze Vektoren zugewiesen werden. 2.4 Kartesisches Produkt Das Kartesische Produkt besteht aus allen geordneten Elementpaaren aus zwei gegebenen Mengen U und V: U × V = { (u , v) | u ∈ U ∧ v ∈ V } Kartesische Produkte lassen sich auch für mehr als zwei Mengen bilden. Der Typkonstruktor für das Kartesische Produkt in CoLa ist struct. Ein Typ, der mit Hilfe von struct definiert wurde, ist einem mit vector definierten Typ sehr ähnlich. Die einzelnen Elemente dürfen jedoch unterschiedliche Typen haben. Man bezeichnet einen mit struct erzeugten Typ deshalb auch als heterogenen Typ, im Gegensatz zu einem homogenen Typ (vector). Die einzelnen Elemente eines mit struct erzeugten Typs haben Bezeichner. Mit ihnen wird der Zugriff auf die einzelnen Elemente ermöglicht. Die Elemente benötigen in der Regel unterschiedlich große Speicherbereiche, daher ist nur ein statischer und kein dynamischer Zugriff auf die Elemente erlaubt. Statischer Zugriff bedeutet, daß das Element, auf das zugegriffen werden soll, bereits zur Übersetzungszeit bekannt sein muß, es also nicht erst zur Laufzeit berechnet werden kann. Anders als bei vector können die Variablen nicht direkt deklariert werden, sondern der neue Typ erhält immer einen eigenen Namen. Dieser dient dann zur Deklaration der Variablen. struct struktur1(bool alpha, char beta, num(20) gamma); struktur1 delta; Es wird zunächst ein Typ struktur1 mit Hilfe von struct mit den Feldern alpha, beta und gamma definiert. Dann wird eine Variable delta mit diesem Typ deklariert. 2.5 Konstanten und Literale Analog zu Variablen können in CoLa Konstanten definiert werden: const bool wahr := true; const num(2, 4) pi := 3.14; CoLa Referenz-Handbuch Seite 13 Als Wert einer Konstanten in einer Konstantendefinition in CoLa dürfen nur Literale verwendet werden. Die Rundung von Konstanten und Literalen erfolgt nach dem Verfahren „round-to-nearest“. Teilweise problematisch ist die Ermittlung des Typs eines Literals. Innerhalb einer Konstantendefinition stellt dies kein Problem dar, weil der Typ durch den Entwerfer eindeutig spezifiziert wurde. Unklar ist der gewünschte Typ eines Literals mit Nachkommaanteil innerhalb einer Berechnung, wie z.B.: num(4) a; num(4, 4) b; a := 7; b := 0.1 * a; Der Typ eines ganzzahligen Literals läßt sich eindeutig bestimmen. Es werden soviel Bits verwendet wie minimal zur Darstellung des Wertes benötigt werden. In unserem Beispiel hat das Literal 7 somit den Typ num(3). Dieser kann ohne Probleme implizit in num(4) gewandelt werden. Nicht eindeutig ist dies im Fall von Zahlen mit Nachkommaanteil, deshalb erhalten diese immer den Typ num(?, 16). Der Vorkommaanteil wird entsprechend einer ganzen Zahl gehandhabt. Der Nachkommaanteil hingegen wird auf 16 Bit festgelegt. Falls dies nicht von Entwerfer gewünscht wird, so hat er die Möglichkeit sich passende Konstanten zu definieren. Zusammengefaßt haben in CoLa Literale die folgenden Typen: Boolsche Wert (true, false) Zeichen (z.B. 'a') Ganze Zahlen (z.B. 123) Festkommazahlen (z.B. 0.1) bool char num(?, 0) / snum(?, 0) num(?,16) / snum(?, 16) Literale mit führendem Minuszeichen erhalten den Typ snum. 3 Zuweisungen und Arithmetik 3.1 Zuweisungen Zuweisungen erfolgen in CoLa mit Hilfe von Doppelpunkt und Gleichheitszeichen ':=': num(32) alpha, beta; alpha := 7; beta := alpha; Zuweisungen an Variablen vom Typ vector oder struct können in gebundener Form (Konkatenation) erfolgen: vector(4) num(32) gamma; struct struktur1(bool a, char b, num(20) c); struktur1 delta; gamma := (1, 2, 3, 4); delta := (true, 'A', 27); Eine Konkatenation von Werten ist nicht nur auf der rechten Seite einer Zuweisung erlaubt, sondern auch auf der linken. Variablen können so zusammengefaßt werden und ihnen können gesammelt Werte zugewiesen werden: num(32) alpha, beta; vector(2) num(32) gamma; (alpha, beta) := gamma; In diesem Beispiel wird der Vektor gamma aufgespalten. Die erste Komponente wird alpha, die zweite wird beta zugewiesen. Man könnte alternativ auch schreiben: alpha := gamma[0]; beta := gamma[1]; Auf Komponenten eines struct wird mit dem Punkt ('.') zugegriffen: struct struktur1(bool a, char b, num(20) c); struktur1 delta; delta.a := true; delta.b := 'A'; delta.c := 27; Hier wird genauso wie in dem weiter oben stehenden Beispiel zunächst der neue Typ struktur1 erzeugt. Die Variable delta wird mit diesem Typ deklariert. Die Zuweisung von Werten erfolgt in diesem Fall nur nicht gesammelt, sondern einzeln. Seite 16 CoLa Referenz-Handbuch 3.2 Implizite Konvertierungen Soll einer Variablen ein Wert mit einer kleineren Wortbreite zugewiesen werden, so erfolgt eine implizite Konvertierung. Soll ein zu großer Wert zugewiesen werden, erzeugt der Compiler eine Fehlermeldung. num(8) acht_bit_breit; num(16) sechzehn_bit_breit; sechzehn_bit_breit := acht_bit_breit; // OK acht_bit_breit := sechzehn_bit_breit; // Fehler Wird einer vorzeichenbehafteten Variablen ein vorzeichenloser Wert zugewiesen, wird eine implizite Konvertierung vorgenommen. Im umgekehrten Fall gibt der Compiler eine Fehlermeldung aus. Eine implizierte Konvertierung kann hier nicht erfolgen, da eine negative Zahl nicht von einer vorzeichenlosen Variablen repräsentiert werden kann. snum(16) mit_vorzeichen; num(15) ohne_vorzeichen; mit_vorzeichen := ohne_vorzeichen; // OK ohne_vorzeichen := mit_vorzeichen; // Fehler Analog hierzu darf einer ganzzahligen Variablen kein Wert mit einem Nachkommaanteil zugewiesen werden. Im umgekehrten Fall erfolgt wiederum eine implizite Konvertierung der Ganzzahl in eine Festkommazahl. num(8) ganze_zahl; num(8,8) festkomma_zahl; festkomma_zahl := ganze_zahl; // OK ganze_zahl := festkomma_zahl; // Fehler 3.3 Explizite Konvertierungen In CoLa ist auch möglich Konvertierungen explizit vorzunehmen. Hierzu gibt es einen eigenen Zuweisungsoperator „:~“. Mit seiner Hilfe lassen sich Variablen auch Werte mit größeren Bitbreiten zuweisen. Hierbei werden überzählige Bit einfach abgeschnitten. Der Entwerfer ist für die Vermeidung eines möglichen Wertverlust selbst verantwortlich. Es folgen hierzu die gleichen Beispiele wie im vorherigen Abschnitt. num(8) ganze_zahl1, ganze_zahl2; num(8,8) festkomma_zahl; num(16) sechzehn_bit_breit; ganze_zahl1 :~ festkomma_zahl; // OK ganze_zahl2 :~ sechzehn_bit_breit; // OK Im ersten Fall erhält ganze_zahl1 nur die acht Vorkommabits von festkomma_zahl zugewiesen. Im zweiten Fall gehen die vorderen acht Bits von sechzehn_bit_breit verloren. CoLa Referenz-Handbuch Seite 17 3.4 Grundrechenarten CoLa kennt die vier Grundrechenarten Addition, Subtraktion, Multiplikation und Division: num(32) alpha, beta; alpha := beta + 2; alpha := beta - 3; alpha := beta * 4; alpha := beta / 5; Eine „Division durch Null“ erzeugt einen Laufzeitfehler. Auf Variablen, die aus mehreren Elementen bestehen (vector und struct), werden die Operationen für jedes Element einzeln durchgeführt. Dies ist im Falle der Multiplikation nicht das Skalarprodukt. Hierfür gibt es eigens eine vordefinierte Funktion in CoLa. vector(3) num(32) gamma, delta; gamma := (1, 2, 3); delta := gamma * gamma; Nach dieser Berechnung hat delta den Wert (1, 4, 9). Die eingebauten Grundrechenarten sind nicht nur für typäquivalente Variablen definiert. Die Multiplikation eines Vektors mit einem Skalarwert ist ebenso vordefiniert. Die einzelnen Komponenten werden mit dem Skalar multipliziert. Das Ergebnis ist wieder ein Vektor. 3.5 Vergleichsoperatoren Von CoLa werden die gängigen Vergleichsoperatoren unterstützt. Dies sind im einzelnen: > < == != >= <= größer kleiner gleich ungleich größer oder gleich kleiner oder gleich Es können beliebige Werte vom Typ num und snum verglichen werden, sowohl ganze Zahlen als auch Festkommazahlen. Variablen vom Typ vector oder struct werden komponentenweise verglichen. Ebenso können einzelne Komponenten als Argumente für einen Vergleichsoperator dienen. In jedem Fall müssen die Argumente einer Vergleichsoperation typäquivalent sein. Das Ergebnis einer Vergleichsoperation ist vom Typ bool. 3.6 Logische Operatoren Mit Hilfe der folgenden logischen Operatoren können Vergleiche zu logischen Ausdrücken kombiniert werden: and or not Konjunktion Disjunktion Negation Seite 18 xor CoLa Referenz-Handbuch Exklusives Oder Die Argumente eines logischen Operators müssen vom Typ bool sein. Das Ergebnis ist ebenfalls vom Typ bool. num(16) a; bool c, b; c := a > 10; b := c and (a < 100); In diesem Beispiel erhält c den Wert true, wenn a größer als zehn ist. Die Variable b wird true, wenn der Wert von a zwischen elf und 99 liegt. 3.7 Schiebeoperationen In CoLa gibt es zwei unterschiedliche Arten von Schiebeoperatoren. Es können sowohl einzelne Bits verschoben werden als auch Komponenten in einem Vektor. Die Komponenten eines Vektors werden mit dem Operator '#>' nach rechts und mit dem Operator '<#' nach links verschoben. vector(10) num(16) alpha; num(16) alt, neu; alt := alpha <# neu; In diesem Beispiel wird der Vektor alpha nach links verschoben. Hierbei ist es wichtig, daß in CoLa das Element mit dem kleinsten Index bzw. das niederwertigste Bit immer rechts steht. Somit werden hier alle Elemente einen Index höher geschoben. Das Element mit dem Index 0 wird frei und erhält den Wert der Variablen neu. Der Wert des Element mit dem Index 9 „fällt aus dem Vektor“ und wird der Variablen alt zugewiesen. Der Vektor verhält sich mit Hilfe des Schiebeoperators wie eine Pipeline. Eine Variable von Typ num verhält sich wie ein Vektor mit nur einem Element: num(16) beta; num(16) alt, neu; alt := beta <# neu; Hier erhält beta einen neuen Wert. Der alte Wert kann weiter verwendet werden. Alternativ kann man selbstverständlich schreiben: alt := beta; beta := neu; Bitweises Verschieben wird mit den Operatoren '<<' (nach links) und '>>' (nach rechts) verwirklicht. Die Schiebeoperatoren können sowohl auf Variablen vom Typ num als auch vom Typ vector angewendet werden. Im ersten Fall werden die einzelnen Bits der jeweiligen Variablen geschoben, im zweiten Fall werden die Komponenten des Vektors parallel um jeweils ein Bit verschoben. Ein Schieberegister kann wie folgt beschrieben werden: CoLa Referenz-Handbuch Seite 19 num(10) beta; num(1) alt, neu; alt := beta << neu; Hier wird eine Variable vom Typ num mit 10 Bits deklariert. Mit Hilfe des Schiebeoperators werden alle Bits um ein Bit nach links geschoben. Das niederwertigste Bit erhält den Wert der Variablen neu. Die Variable alt erhält den Wert des herausfallenden höchstwertigen Bits. Im folgenden Beispiel erfolgt das Schieben der Bits parallel. Die einzelnen Bits des Vektors neu werden von rechts in die Komponenten des Vektors gamma geschoben. vector(10) num(16) gamma; vector(10) num(1) alt, neu; alt := gamma << neu; In den vorangegangenen Beispielen wurde das Schieben nach links demonstriert. Das Rechtsschieben erfolgt analog hierzu mit Hilfe der Operatoren '>>' und '#>'. Manchmal möchte man Elemente nicht schieben, sondern rotieren. Auch dies ist in CoLa möglich: vector(10) num(16) gamma; num(16) delta; gamma <#; delta <<; Alle Elemente des Vektors gamma werden hier um ein Element nach links geschoben. Das Element mit dem Index 9 wird zum Element mit dem Index 0. Es wird gamma kein Element neu hinzugefügt, und es fällt auch keines heraus. Alle Elemente werden lediglich im Kreis geschoben. Ebenso werden die einzelnen Bits der Variablen delta rotiert. 4 Kontrollstrukturen Berechnungen werden in CoLa zu Datenblöcken zusammengefaßt. Jeder Datenblock ist in Klammern '( ... )' eingeschlossen. Datenblöcke können alternativ oder auch wiederholt ausgeführt werden. Hierzu bietet CoLa unterschiedliche Kontrollstrukturen. 4.1 Gültigkeitsbereiche Variablen dürfen nur am Anfang eines Blockes deklariert werden. Ihr Gültigkeitsbereich endet mit der schließenden Klammer ')' des jeweiligen Blockes. CoLa ist somit blockstrukturiert und besitzt lexikalische Gültigkeitsbereiche. Gültigkeitsbereiche von Variablen können Lücken haben: ... num(16) a, b; a := 7; ( num(16) a; a := 8; ) b := a; ... In diesem Beispiel wird der Variablen b der Wert 7 zugewiesen. Die zuerst deklarierte Variable ist innerhalb des inneren Block nicht sichtbar. Die lokale Variable a erhält den Wert 8. Nach Verlassen des inneren Blocks wird die äußere Variable a wieder sichtbar und wird b zugewiesen. 4.2 Verzweigungen Verzweigungen (bzw. alternative Ausführungen) werden in CoLa mit Hilfe der Befehle if und else realisiert, wobei der else-Teil optional ist. if (alpha > 10) ( beta := 2; ) else ( beta := 1; ) Wenn alpha größer als zehn ist, erhält beta den Wert '2', sonst '1'. Die Semantik unterscheidet sich nicht von der Semantik gängiger Programmiersprachen. 4.3 Switch-Anweisung Eine switch-Anweisung besteht aus einer Variablen und mehreren case-Blöcken: Seite 22 CoLa Referenz-Handbuch num(8) alpha; num(16) beta; ... switch(alpha) ( case 1 (beta := 27;) case 2 (beta := 9;) default (beta := 0;) ) Dem Schlüsselwort case folgt jeweils ein konstanter Ausdruck. Ist dieser gleich dem Wert der Variablen der switch-Anweisung, so wird der jeweilige Block ausgeführt. Paßt keiner der konstanten Ausdrücke, wird der Block nach dem 'default' ausgeführt. Anschließend wird das Programm nach der switch-Anweisung fortgesetzt. Eine Besonderheit ist, daß die Variable hinter dem switch einen beliebigen Typ haben darf. Sie kann z.B. auch von Typ vector sein. 4.4 Schleifen CoLa kennt mit der while- und loop-Schleife zwei unterschiedliche Typen von Schleifen. Beide können auch zu einer Schleife kombiniert werden. Die einfachere von beiden ist die loop-Schleife: erg := 1; loop i (1..10) ( erg := erg * i; ) Die Schleifenvariable i wird implizit deklariert und wird mit der unteren Schleifengrenze initialisiert. Sie ist nur innerhalb der Schleife gültig. Ihr kann kein Wert direkt zugewiesen werden. In dem oben stehenden Beispiel wird der auf loop folgende Block zehnmal ausgeführt. Die Schleifenvariable i nimmt dabei Werte von eins bis zehn an. Sie wird somit in jedem Durchgang um Eins erhöht. Einer loop-Schleife kann eine optionale Abbruchbedingung hinzugefügt werden: erg := 1; loop i (1..10) while (erg <= ende) ( erg := erg * i; ) Diese Schleife wird maximal zehnmal ausgeführt. Wenn erg vorher größer als ende wird, wird die Schleife vorzeitig beendet. In CoLa kann auch eine „reine“ while-Schleife verwendet werden: i := 1; erg := 1; while (i <= ende) ( erg := erg * i; i := i + 1; ) CoLa Referenz-Handbuch Seite 23 Diese Schleife hat keine zur Übersetzungszeit bekannte maximale Anzahl von Iterationen. Sie wird solange ausgeführt, wie die Bedingung nach while erfüllt ist. CoLa kennt eine Compilervariable, die die maximale Anzahl von Schleifendurchläufen von reinen whileSchleifen festlegt. Wird diese Anzahl übertroffen, führt dies zu einem Laufzeitfehler. Die Maximalzahl kann vom Benutzer beliebig gesetzt werden. Der voreingestellte Wert ist 1000. 5 Funktionen und Prozesse 5.1 Funktionen Jede Funktion muß zunächst deklariert werden. Diese Einschränkung wurde gewählt, um einen „single-pass“-Compiler für CoLa zu ermöglichen. Die Reihenfolge der Funktionen ist beliebig. Es muß lediglich die Deklaration vor der Definition und vor der ersten Verwendung stehen. type (i16 (i16 (i16 (i16 i16 num(16); aout)function bout)function cout)function tout)function anna(i16 ain1, i16 ain2); berta(i16 bin1, i16 bin2); caesar(i16 cin1, i16 cin2); toplevel(i16 tin1, i16 tin2); Bei der Deklaration werden einer Funktion ihre formalen Parameter zugeordnet. Es werden Ein- und Ausgangsparameter unterschieden. Eingangsparameter nehmen die Funktionsargumente auf. Sie dürfen innerhalb der Funktion nur auf der rechten Seite von Anweisungen stehen. Sie sind somit innerhalb der Funktion konstant. Die Übergabe der Eingangsparameter erfolgt „call-by-value“. Ausgangsparameter enthalten die Rückgabewerte einer Funktion. Sie dürfen nur auf der linken Seite einer Anweisung stehen. Werden die Rückgabewerte für weitere Berechnungen innerhalb der Funktion benötigt, müssen sie zunächst einer lokalen Variable zu gewiesen werden. Den Ausgangsparametern dürfen an unterschiedlichen Stellen der Funktion Werte zugewiesen werden. Dieses ist z.B. im Falle von bedingten Zuweisungen sinnvoll. Der Rückgabeparameter erhält seinen Wert erst beim Terminieren der Funktion („copy-out“). Diese Art der Parameterübergabe wird auch als Ergebnisübergabe („pass-by-result“) bezeichnet. Nachdem die Funktionen deklariert sind, kann das jeweilige Verhalten definiert werden: function anna ( aout := ain1 * 2 + ain2; ); function berta ( bout := anna (bin1, bin2) * 2; ); function caesar ( cout := berta(cin1, cin2) * 2; ); function toplevel ( tout := caesar(tin1, tin2) * 2; ); Seite 26 toplevel CoLa Referenz-Handbuch caesar berta anna Die Funktionsaufrufe erfolgen in diesem Beispiel verschachtelt. 5.2 Automaten Automaten werden von CoLa als spezielle Funktionen realisiert. Automaten werden analog zu Funktionen deklariert. Rechts vom Namen des Automaten stehen die Eingangsparameter, links die Ausgangsparameter (= Rückgabewerte). (num(32) raus)automat alpha(bool flag); Es können ausschließlich Moore-Automaten beschrieben werden. Ausgangsparameter dürfen somit nur von den Zuständen des Automaten und nicht direkt von den Eingangsparametern abhängen. Dieses hat zur Folge, daß den Ausgangsparametern nur zur Übersetzungszeit berechenbare Werte zugewiesen werden dürfen. Innerhalb eines Automat gibt es keine lokalen Variablen. Die logischen Ausdrücke zur Berechnung des Folgezustands bestehen aus logischen Verknüpfungen der Eingangsparameter. Jeder Automat besteht aus mehren Zuständen. Nach jedem Zustandsnamen steht ein Doppelpunkt. Zu jedem Zustand gehören ein oder mehrere Zustandsübergänge. Diese bestehen aus einer Bedingung und einem Folgezustand. Die Zustandsübergänge werden bis zur ersten erfüllten Bedingung sequentiell abgearbeitet. In dem dazugehörigen Folgezustand wird die Bearbeitung fortgesetzt. EINS 0 ZWEI 0 flag == true automat alpha ( raus := 0; eins: -> zwei; zwei: (flag == true) -> drei: -> eins; drei: raus := 1; -> eins; ); DREI 1 CoLa Referenz-Handbuch Seite 27 In diesem Beispiel wechselt der Automat im Normalfall zwischen den Zuständen 'eins' und 'zwei'. Nur wenn im Zustand 'zwei' die boolsche Variable flag wahr ist, wird in den Zustand 'drei' gewechselt. Einem Ausgangsparameter, in diesem Fall raus, kann ein Standardwert zugewiesen werden. Dieser gilt in allen Zuständen, in denen nicht explizit ein anderer Wert zugewiesen wird. Hier hat raus normalerweise den Wert '0'. Nur im Zustand 'drei' erhält er den Wert '1'. 5.3 Rekursive Funktionen Funktionsaufrufe können in CoLa rekursiv erfolgen. Die maximale Rekursionstiefe ist eine Compilervariable. Voreingestellt ist ein Wert von zehn rekursiven Aufrufen. Wird die maximale Rekursionstiefe zur Laufzeit überschritten, führt dieses zu einem Laufzeitfehler. Ein Compiler muß erkennen, ob ein rekursiver Aufruf vorliegt. Er begrenzt in diesem Fall die Anzahl der rekursiv aufgerufenen Instanzen einer Funktion auf die maximale Rekursionstiefe. Falls die Rekursion durch das gegenseitige Aufrufen von zwei oder mehr Funktionen entsteht, werden von jeder der beteiligten Funktionen die maximale Anzahl von Instanzen (= maximale Rekursionstiefe) erzeugt. 5.4 Parallele Ausführungen CoLa ermöglicht es, Anweisungen parallel auszuführen. Hierzu werden die Anweisungen nicht durch ein Semikolon ';', sondern durch einen Doppelpunkt ':' getrennt. b := 3 * a : c := 2 * a; In diesem Beispiel können die beiden Multiplikationen parallel ausgeführt werden. Es bleibt dem jeweiligem Compiler überlassen, ob er hieraus auch tatsächlich zwei parallel arbeitende Instruktionen generiert. Wenn die parallele Ausführung aufgrund von Datenabhängigkeiten unmöglich ist, muß der Compiler einen Fehler melden. Dieses wäre im folgenden Beispiel der Fall: b := 3 * a : c := 2 * b; Die Variable b erhält in der linken Zuweisung einen neuen Wert, während sie gleichzeitig in der rechten gelesen wird. Der Programmierer muß deshalb das gewünschte Verhalten deutlich machen. Entweder es soll der „alte“ Wert von b verwendet werden b_alt := b; b := 3 * a : c := 2 * b_alt; oder der neue Wert von b dient zur weiteren Berechnung: b := 3 * a; c := 2 * b; Dann ist aber, wie in dem vorstehenden Beispiel, eine parallele Berechnung nicht möglich. Die Multiplikationen müssen sequentiell ausgeführt werden. Ein ':' bindet stärker als ein ';', d.h. ein Semikolon ';' schließt einen Block von parallelen Anweisungen ab. Seite 28 CoLa Referenz-Handbuch 5.5 Prozesse Funktionsaufrufe können auf die gleiche Weise wie andere Berechnungen parallel ausgeführt werden. Es müssen ebenso eventuelle Datenabhängigkeiten berücksichtigt werden. Auf diese Weise lassen sich in CoLa einfach Prozesse beschreiben. function process1() ( ... ) function process2() ( ... ) function start ( process1() : process2(); ) Die Funktionen process1 und process2 werden parallel ausgeführt. Echte Prozesse werden aus Funktionen nur, wenn ihre Aufrufe in der Toplevel-Funktion erfolgen. Nur so werden sie permanent angestoßen. Im obigen Beispiel muß start somit die ToplevelFunktion sein. 5.6 Prozeßkommunikation Der Austausch von Werten zwischen Prozessen ist nicht direkt möglich. Folgendes Beispiel verdeutlicht dieses: function start ( num(16) a, b; a := process1(b) : b := process2(a); ) Der Compiler würde hier einen Fehler ausgeben. Aufgrund der Datenabhängigkeit ist eine parallele Ausführung der Zuweisung nicht gestattet. In CoLa ist ein Austausch von Daten während ein Prozeß läuft unmöglich. Um eine Kommunikation zu ermöglichen, muß jeder Prozeß eigene Variablen erhalten: function start ( num(16) a1, a2, b1, b2; a1 := process1(b1) : b2 := process2(a2); a2 := a1; b1 := b2; ) Wenn beide Prozesse ihre Ergebnisse fertig berechnet haben, werden diese an die Eingangsparameter zugewiesen. Danach werden die Prozesse neu angestoßen. In CoLa lassen sich somit ausschließlich synchrone Prozesse beschreiben. 6 Vordefinierte Funktionen In CoLa sind eine Reihe von Funktionen vordefiniert. Diese ermöglichen eine effiziente Umsetzung auf der jeweiligen Zielarchitektur. Bei den jeweiligen Funktionen sind die grundsätzlichen Typen der Ein- und Ausgangsparameter angegeben. Es ist die Aufgabe des Compilers, die genauen Bitbreiten der unterschiedlichen Parameter geeignet zu wählen. Die vordefinierten Funktionen sind also generische Funktionen. Die exakten Typen einer jeden Funktionsinstanz wählt der Compiler entsprechend des jeweiligen Kontextes. Zum jetzigen Zeitpunkt sind nur einige rudimentär Funktionen vorgesehen. Der Sprachumfang von CoLa kann bei Bedarf leicht um weitere Funktionen erweitert werden. 6.1 abs num abs( snum ) Die Funktion abs liefert den absoluten Wert einer vorzeichenbehafteten Zahl. Sie entfernt also das Vorzeichen einer Zahl. 6.2 cos snum cos( snum ) Die Funktion cos berechnet den Kosinus des Arguments. Die Rundung des Ergebnisses erfolgt nach dem Verfahren „round-to-nearest“. 6.3 int num int( num ) Die Funktion int liefert den ganzzahligen Anteil des Arguments. 6.4 sp snum sp( vector, vector ) Die Funktion sp multipliziert die beiden Argumente komponentenweise und summiert die einzelnen Produkte auf (Skalarprodukt). Auf den Typen der Komponenten der Vektoren müssen Multiplikation und Addition definiert sein. 6.5 max num max( vector ) Die Funktion max liefert den Index der Komponente des Arguments mit dem größten Wert aller Komponenten. Auf den Typen der Komponenten der Vektoren muß die Vergleichsoperation '>' definiert sein. Seite 30 CoLa Referenz-Handbuch 6.6 min num min( vector ) Die Funktion min liefert den Index der Komponente des Arguments mit dem kleinsten Wert aller Komponenten. Auf den Typen der Komponenten der Vektoren muß die Vergleichsoperation '<' definiert sein. 6.7 sin snum sin( snum ) Die Funktion sin berechnet den Sinus des Arguments. Die Rundung des Ergebnisses erfolgt nach dem Verfahren „round-to-nearest“. 6.8 sint snum sint( snum ) Die Funktion sint liefert den ganzzahligen Anteil des Arguments. 6.9 sum snum sum( vector ) Die Funktion sum liefert den aufsummierten Wert aller Komponenten des Arguments. Auf den Typen der Komponenten der Vektoren muß die Addition definiert sein. 7 Zeitbedingungen Zur Beschreibung von Echtzeitanforderungen können in CoLa unterschiedliche Zeitbedingungen formuliert werden. Feste Berechnungszeiten werden in CoLa mit dem Schlüsselwort rate spezifiziert. Sie können absolut oder relativ angegeben werden. Mit step können zeitabhängige Ausführungszeitpunkte definiert werden. 7.1 Absolute Zeitbedingungen Mit Hilfe einer absoluten Zeitbedingung wird einer Zuweisung eine feste Zeit, die ihr maximal zur Berechnung zur Verfügung steht, zugeordnet. Nach Ablauf dieser Zeitspanne muß das Ergebnis der Zuweisung vorliegen. function alpha ( b := beta(a) rate 1 ms; c := gamma(b) rate 2 ms; ) In diesem Beispiel ist die Berechnung der Funktionen beta und gamma somit nach insgesamt 3 ms beendet. Wird jetzt die Funktion alpha benutzt, kann sie maximal mit einer Rate von 3 ms aufgerufen werden. Wird sie mit einer höheren Rate aufgerufen, erzeugt der Compiler eine Fehlermeldung. Eine höhere Rate bedeutet hier und im folgenden, daß weniger Zeit für die Ausführung zur Verfügung steht. Der Wert für die Zeit ist zwar kleiner, dennoch spricht man von einer höheren Rate. Ebenso ist mit einer niedrigeren Rate gemeint, daß mehr Zeit zur Verfügung steht. Wird die Funktion alpha mit einer niedrigeren Rate aufgerufen, wird vom Compiler eine zusätzliche Wartezeit eingefügt. Wird also die Beispielfunktion mit einer Rate 10 ms aufgerufen, werden zunächst beta und gamma aufgerufen. Dann wird 7 ms gewartet, um anschließend die nächste Berechnung zu starten. Alternativ können die Zeitbedingungen weggelassen werden. Zur Verdeutlichung folgte ein leicht geändertes Beispiel: function alpha ( b := beta(a) rate 1 ms; c := gamma(b); ) Wird die Funktion alpha hier nun mit einer Rate von 3 ms aufgerufen, ändert sich nichts. beta terminiert nach 1 ms und gamma nach 2 ms. Erfolgt der Aufruf aber mit der Rate 10 ms stehen gamma 9 ms zur Berechnung des Ergebnisses zur Verfügung. Der Compiler hat somit mehr Freiheiten und kann möglicherweise eine billigere Lösung finden. 7.2 Relative Zeitbedingungen Manchmal kann es sinnvoll sein, als Rate keine absoluten Zeiten anzugeben, sondern nur einen prozentualen Anteil der zur Verfügung stehenden Zeit: function alpha ( Seite 32 CoLa Referenz-Handbuch b := beta(a) rate 0.5; c := gamma(b) rate 0.5; ) Wird die Funktion alpha jetzt mit einer Rate von 10 ms aufgerufen, muß sowohl beta als auch gamma nach 5 ms terminieren. Selbstverständlich kann wieder eine oder mehrere Raten weggelassen werden. Der Compiler wird sie dann passend ergänzen. Ist die Summe der relativen Rate innerhalb einer Funktion größer als 1, erzeugt der Compiler eine Fehlermeldung. Absolute und relative Zeitbedingungen können gemischt werden. Hierbei ist wichtig, daß die Summe der Raten der Teilberechnungen nicht größer als die insgesamt für die Funktion angegebene Rate wird. 7.3 Zeitbedingungen bei parallelen Instruktionen Bei Instruktionen, die parallel ausgeführt werden sollen, muß die Rate identisch oder nicht spezifiziert sein. function alpha ( b1 := beta(a1) rate 0.5 : b2 := beta(a1) rate 0.5; c := gamma(b1, b2) rate 0.5; ) In diesem Beispiel werden zwei parallel arbeitende Instanzen von beta erzeugt. Beiden wird 50% der für die Berechnung von alpha zur Verfügung stehenden Zeit zu gewiesen. Da beide Instanzen sowieso zur gleichen Zeit terminieren müssen, reicht es aus, wenn die Rate einmal angegeben wird: function alpha ( b1 := beta(a1) rate 0.5 : b2 := beta(a1); c := gamma(b1, b2); ) In der Praxis terminieren parallele Instruktionen natürlich nicht zur gleichen Zeit. Vielmehr muß die schnellere auf die langsamere warten. Es kann auch sein, daß beide Instruktionen warten müssen. Dies ist in diesem Beispiel der Fall, wenn beide Funktionsaufrufe bereits vor Ablauf der zur Verfügung stehenden Zeit terminieren. Auch bei der Funktion gamma kann die Rate in diesem Beispiel weggelassen werden, da in jedem Fall noch 50% der Berechnungszeit für die Ausführung der Berechnung übrig ist. 7.4 Zeitbedingungen für Verzweigungen und Schleifen Verzweigungen (bedingte Ausführungen) und Schleifen können ebenso wie Zuweisungen Raten zugeordnet werden. Im Falle einer Verzweigung gilt die Rate für alle Alternativen. Auch wenn kein Default-Fall angegeben wurde, gilt für diesen Fall die jeweilige Rate. Die Rate für eine Schleife legt die gesamte Ausführungszeit der Schleife fest. Dies bedeutet, daß für jeden Durchlauf der Schleife die Rate geteilt durch die maximale Anzahl der Schleifendurchläufe als Ausführungszeit zur Verfügung steht. Im Falle einer „reinen“ CoLa Referenz-Handbuch Seite 33 while-Schleife wird die mit Hilfe einer Compilervariablen spezifizierte maximale Wiederholungszahl zugrunde gelegt. 7.5 Ausführungszeitpunkte In CoLa ist es möglich, die Ausführung einer Funktion von einem bestimmten Zeitpunkt abhängig zu machen. Da in CoLa Funktionen wiederholt angestoßen werden, erfolgt die Festlegung der Zeitpunkte eines Funktionsaufrufs durch Angabe einer Schrittweite. Die Schrittweite wird mit Hilfe des Schlüsselwortes step angegeben. Auf step muß eine ganze positive Zahl folgen. Die absoluten Zeitpunkte eines Funktionsaufrufs sind vom Kontext abhängig. Zwei Funktionen, die an unterschiedlichen Stellen einer Systembeschreibung mit der gleichen Schrittweite spezifiziert wurden, können zu unterschiedlichen Zeiten und unterschiedlich häufig aufgerufen werden. Der Zeitpunkt des Aufrufs hängt auch davon ab, wann der Kontrollfluß die Stelle des Aufrufs erreicht. Die Schrittweiten sind also keineswegs absolute Werte im ganzen System. (int(8) out) function toplevel(int(8) in); function toplevel ( int(8) a, b, c; c := caesar(in) step 3; b := berta(in, c) step 2; out := anna(in, c, b); ) anna 3 anna 4 anna caesar step 3 2 berta step 2 anna step 1 1 berta caesar In diesem Beispiel werden in der Toplevel-Funktion die drei Funktionen anna, berta und caesar aufgerufen. Alle drei Aufrufe erfolgen mit einer unterschiedlichen Schrittweite. Wenn, wie im Fall der Funktion anna, keine Schrittweite angegeben wird, wird „step 1“ angenommen, d.h. die Funktion wird immer ausgeführt. „Immer“ bedeutet hier, daß bei jedem Aufruf der Funktion toplevel auch anna aufgerufen wird. Die Funktion berta wird beim 1, 3, 5, 7, ... Aufruf der Funktion toplevel angestoßen. Analog hierzu erfolgt der Aufruf von caesar an den Zeitpunkten 1, 4, 7, 10, ... . Seite 34 CoLa Referenz-Handbuch Manchmal ist es erforderlich, daß der Aufruf einer Funktion erst mit einer gewissen Verzögerung erfolgt. (int(8) out) function toplevel(int(8) in); function toplevel ( out := daniel(in) step 2; out := emil(in) step 2 delay 1; ) daniel step 2 1 emil 4 step 2 2 3 delay 1 In diesem Beispiel werden die Funktionen abwechselnd aufgerufen. Die Funktion daniel wird an den Zeitpunkten 1, 3, 5, ... aufgerufen. Die Funktion emil wird mit der gleichen Schrittweite aufgerufen. Der erste Aufruf erfolgt mit einer Verzögerung von einem Zeitschritt, so daß der Aufruf an den Zeitpunkten 2, 4, 6, ... erfolgt. daniel emil 8 Ausnahmen und Unterbrechungen Um robuste und fehlertolerante Systeme zu beschreiben, ist eine Ausnahmebehandlung (exception handling) notwendig. Diese ermöglicht die Reaktion auf unerwartete oder fehlerhafte Ereignisse. Im folgenden wird zwischen eingebauten und benutzerdefinierten Ausnahmen unterschieden. Alle eingebauten Ausnahmen sind Laufzeitfehler, d.h. Fehler die zur Übersetzungszeit nicht erkannt werden können. Ausnahmen werden innerhalb einer Funktion erzeugt und am Ende der Funktion abgefangen. Sie sind ein Spezialfall der Unterbrechungen. Unterbrechungen (interrupts) können auch außerhalb von Funktionen erzeugt werden. Sie müssen dann als Eingangsparameter der Funktion übergeben werden. 8.1 Abfangen von Unterbrechungen In CoLa können Behandlungsroutinen für Unterbrechungen an Funktionen assoziiert werden. Für jede Funktion kann so ein eigenes Verhalten zur Reaktion auf Ausnahmen definiert werden. Tritt in einer CoLa-Funktion eine Ausnahme auf, wird der entsprechende Abschnitt am Ende der Funktion zur Fehlerbehandlung aufgerufen. Grundsätzlich könnte eine Funktion nach der Behandlung einer Unterbrechung an der Stelle, an der sie unterbrochen wurde, fortgesetzt werden (Wiederaufnahmemodell) oder beendet werden (Terminierungsmodell). In CoLa wird das Terminierungsmodell verwendet. Ausnahmen können sich fortpflanzen. Wenn eine Funktion keine Routine zur Ausnahmebehandlung enthält, wird die Ausnahme an die darüber liegende Abstraktionsebene weitergereicht. 8.2 Laufzeitfehler In CoLa gibt es drei verschiedene Laufzeitfehler: Überschreiten der maximalen Rekursionstiefe (max_recursion_depth), Überschreiten der maximalen Schleifenanzahl (max_loop_runs), Division durch Null (division_by_zero). Für jeden Laufzeitfehler sind bereits Unterbrechungen deklariert, so daß der Programmierer diese direkt nutzen kann. Sie werden automatisch vom System signalisiert. (num(16) z) function teilen(num(16) a, num(16) b) ( z := a / b; ) catch division_by_zero ( z := 0; ) Wird die Funktion teilen mit b = 0 aufgerufen, so erzeugt das System eine division_by_zero Ausnahme. Diese wird abgefangen und dem Ausgangsparameter z wird eine Null zugewiesen. Seite 36 CoLa Referenz-Handbuch 8.3 Benutzerdefinierte Ausnahmen Der Entwerfer kann eigene Ausnahmen deklarieren und signalisieren. So könnte z.B. eine Ausnahme für den Fall einer Bereichsüberschreitungen erzeugt werden: (num(16) z) function summe(num(16) a, num(16) b) ( interrupt overflow; z := a + b; if (z > 999) ( raise overflow; ) ) catch overflow ( z := 999; ) Die Ausnahme overflow wird zunächst deklariert. Ist das Ergebnis der Addition größer als 999 wird sie signalisiert. Am Ende der Funktion summe wird die Ausnahme abgefangen und z der maximal mögliche Wert 999 zugewiesen. 8.4 Unterbrechungen Ausnahmen sind Ereignisse innerhalb einer Funktion, auf die eine angemessene Reaktion erfolgen muß. Auf Ereignisse, die hingegen außerhalb einer Funktion auftreten, kann mit einer Unterbrechung (interrupt) reagiert werden. Das Abfangen erfolgt anlog zum Abfangen einer Ausnahme. (num(32) z) function zaehlen(interrupt stop); function zaehlen ( z := 0; while true ( z := z + 1; ) ) catch stop ( ) catch max_loop_runs ( ) Die Funktion zaehlen erhöht z endlos um eins. Währenddessen können zwei unterschiedliche Unterbrechungen auftreten. Zum einen kann die externe Unterbrechung stop signalisiert werden. Zum anderen kann die maximale Anzahl der Schleifendurchläufe erreicht werden. In beiden Fällen wird die Funktion einfach beendet. Eine externe Unterbrechung kann auch von einer parallel gestarteten Funktion signalisiert werden: CoLa Referenz-Handbuch Seite 37 () function toplevel(); function toplevel( num(32) zahl; interrupt stop_zaehlen; z := zaehlen(stop_zaehlen) : stop_zaehlen := erzeuge_interrupt(); ) (interrupt stop) function erzeuge_interrupt(); function erzeuge_interrupt( ... raise stop; ... ) Die Deklaration einer Unterbrechung als Rückgabewert ermöglicht es, einer Funktion eine Unterbrechung nach außen zu signalisieren. Zu beachten ist, daß eine Unterbrechung sofort aktiv wird, wenn sie signalisiert wird. „Normale“ Rückgabewerte erhalten ihren Wert erst, wenn die Funktion terminiert. Die Zuweisung zu stop_zaehlen ist wichtig, um eine eindeutige Zuordnung der Unterbrechung zu erhalten. 9 Kurzreferenz 9.1 ':=' Syntax: <AssignExpression> ::= <PrimaryExpression> ':=' <ArithExpression> <RateStep> ';' Semantik: Variablen in CoLa erhalten mit Hilfe des Zuweisungsoperators ':=' einen Wert. 9.2 ':~' Syntax: <AssignExpression> ::= <PrimaryExpression> ':~' <ArithExpression> <RateStep> ';' Semantik: Variablen können auch mit Hilfe des Zuweisungsoperators ':~' einen neuen Wert erhalten. Hierbei wird ggf. eine Konvertierung der Bitbreiten vorgenommen. Dies kann zu Wertverlusten führen. 9.3 '==' / '!=' / '<' / '>=' / '>' / '<=' Syntax: <Relation> ::= '(' <Relation> ')' | <ArithExpression> '==' <ArithExpression> | <ArithExpression> '!=' <ArithExpression> | <ArithExpression> '<' <ArithExpression> | <ArithExpression> '>=' <ArithExpression> | <ArithExpression> '>' <ArithExpression> | <ArithExpression> '<=' <ArithExpression> Semantik: Mit Hilfe der Vergleichsoperatoren können Variablen verglichen werden. Das Ergebnis einer Vergleichsoperation ist vom Typ bool. Komplexe Typen werden komponentenweise verglichen. 9.4 '>>' / '<<' Syntax: <ShiftExpression> ::= Seite 40 CoLa Referenz-Handbuch <AdditiveExpression> | <ShiftExpression> '<<' <AdditiveExpression> | <ShiftExpression> '>>' <AdditiveExpression> <AssignExpression> ::= <PrimaryExpression> '<<' <RateStep> ';' | <PrimaryExpression> '>>' <RateStep> ';' Semantik: Der Operator '>>' bewirkt das bitweise Schieben des Werts einer Variablen nach rechts. Der Operator '<<' schiebt den Wert nach links. Wenn der Operator ohne Argument angewendet wird, wird der Wert der Variablen rotiert, d.h. der „rausfallende“ Wert wird auf der anderen Seite wieder hinein geschoben. Wird ein Argument angegeben, so wird sein Wert an Stelle dessen hinzugefügt. Der „rausfallende“ Wert wird verworfen. Die beiden Schiebeoperatoren können sowohl auf Variablen vom Typ num als auch vom Typ vector angewendet werden. Im ersten Fall werden einzelne Bits geschoben, im zweiten Fall werden die Elemente des Vektors parallel bitweise verschoben. 9.5 '#>' / '<#' Syntax: <ShiftExpression> ::= <AdditiveExpression> | <ShiftExpression> '<#' <AdditiveExpression> | <ShiftExpression> '#>' <AdditiveExpression> <AssignExpression> ::= <PrimaryExpression> '<#' <RateStep> ';' | <PrimaryExpression> '#>' <RateStep> ';' Semantik: Der Operator '#>' bewirkt das Schieben der Komponenten eines Vektors nach rechts. Der Operator '<#' schiebt die Komponenten nach links. Wenn der Operator ohne Argument angewendet wird, werden die Komponenten rotiert, d.h. der „rausfallende“ Wert wird auf der anderen Seite wieder hinein geschoben. Wird ein Argument angegeben, so wird sein Wert an Stelle dessen hinzugefügt. Der „rausfallende“ Wert wird verworfen. 9.6 '&' / '|' Syntax: <ArithExpression> <ShiftExpression> <ArithExpression> <ArithExpression> ::= | '&' <ShiftExpression> | '|' <ShiftExpression> CoLa Referenz-Handbuch Seite 41 Semantik: '&' und '|' gehören zu den arithmetischen Operatoren. Sie bewirken das die beiden Argumente bitweise „UND“ bzw. „ODER“ verknüpft werden. Beide können auch auf Vektoren angewendet werden. In diesem Fall werden die einzelnen Komponenten des Vektors „UND“ bzw. „ODER“ verknüpft. Das Ergebnis der Operation ist in diesem Fall wieder ein Vektor. 9.7 AND Syntax: <LogicExpression> ::= <LogicExpression> AND <Relation> Semantik: Der Operator 'and' gehört zu den logischen Operatoren. Er verknüpft zwei Argumente vom Typ bool gemäß der folgenden Wertetabelle: a false false true true b false true false true a and b false false false true 9.8 AUTOMAT Syntax: <AutomatDeclaration> ::= '(' <ParaList> ')' AUTOMAT IDENTIFIER '('<ParaList>')' ';' <AutomatName> ::= AUTOMAT IDENTIFIER <AutomatDefinition> ::= <AutomatName> '(' <AutomatBlock> ')' <ExceptionHandler> Semantik: Automaten werden analog zu Funktionen zunächst deklariert und dann definiert. Jeder Automat besteht aus einzelnen Zuständen. Die Zustände wiederum bestehen aus mehreren optionalen bedingten Zustandsübergängen und einem unbedingten Default-Übergang. 9.9 BOOL Syntax: <TypeSpecifier> ::= BOOL Seite 42 CoLa Referenz-Handbuch Semantik: Mit dem Schlüsselwort bool werden boolsche Variablen deklariert. Sie können die Werte 'true' und 'false' annehmen. Variablen vom Typ bool können implizit in Variablen vom Typ num(1) gewandelt werden. Der Wert 'true' wird in eine Eins und der Wert 'false' in eine Null gewandelt. 9.10 CHAR Syntax: <TypeSpecifier> ::= CHAR Semantik: Mit dem Schlüsselwort char werden Variablen, die ein ASCII-Zeichen aufnehmen können, deklariert. Variablen vom Typ char können implizit in Variablen vom Typ num(8) umgewandelt werden. 9.11 CONST Syntax: <ConstDeclaration> ::= CONST <VarDeclaration> ':=' <ConstExpressionSingle> Semantik: Mit const werden Variablen als konstant deklariert. Innerhalb der Deklaration wird ihr konstanter Wert festgelegt. 9.12 DELAY Syntax: <Delay> ::= DELAY INTVALUE Semantik: Mit Hilfe von delay werden Anweisungen bei ihrem ersten Aufruf um die hinter delay spezifizierten Zeiteinheiten verzögert. Wird kein delay angegeben wird „delay 0“ angenommen. 9.13 FUNCTION Syntax: <FuncDeclaration> ::= '('<ParaList>')' FUNCTION IDENTIFIER '('<ParaList>')' ';' CoLa Referenz-Handbuch Seite 43 <FuncName> ::= FUNCTION IDENTIFIER <FuncDefinition> ::= <FuncName> <Block> <ExceptionHandler> Semantik: Mit Hilfe des Schlüsselwortes function werden Funktionen sowohl deklariert als auch definiert. Bei der Deklaration werden die Ein- und Ausgangsparameter festgelegt. Bei der Definition wird ein Block aus einzelnen Anweisungen an die Funktion gebunden. Die Toplevel-Funktion, die den gleichen Namen wie die Datei hat, wird vom Laufzeitsystem wiederholt und permanent abgearbeitet. 9.14 IF / ELSE Syntax: <SelectionStatement> ::= IF '(' <LogicExpression> ')' <CreateBlock> <Block> | IF '(' <LogicExpression> ')' <CreateBlock> <Block> ELSE <CreateBlock> <Block> Semantik: Mit Hilfe des if / else Konstrukts werden, wie in gängigen Programmiersprachen, Anweisungen bedingt ausgeführt. Wird der logische Ausdruck nach dem if zu true ausgewertet, werden die folgenden Anweisungen ausgeführt. Anderenfalls werden die nach dem else stehenden Anweisungen ausgeführt. Die else Anweisung ist optional. 9.15 INTERRUPT Syntax: <TypeSpecifier> ::= INTERRUPT Semantik: Mit dem Schlüsselwort interrupt wird eine Unterbrechung deklariert. Die Unterbrechung wird mit dem Befehl raise ausgelöst und ist für eine Zeiteinheit aktiv. 9.16 LOOP / WHILE Syntax: <IterationStatement> ::= LOOP IDENTIFIER <Range> WHILE '(' <LogicExpression> ')' | LOOP IDENTIFIER <Range> | WHILE '(' <LogicExpression> ')' Semantik: Seite 44 CoLa Referenz-Handbuch In CoLa gibt es zwei Arten von Schleifen die loop- und die while-Schleife. Die loopSchleife deklariert eine Schleifenvariable und ein festes Intervall, das diese durchlaufen soll. Im Gegensatz hierzu wird die while-Schleife solange durchlaufen, wie der auf das while folgende logische Ausdruck zu true ausgewertet werden kann. Beide Schleifenarten können auch zu einer kombiniert werden. Die Schleife wird dann beendet, wenn das Ende des Intervalls erreicht ist oder die Bedingung hinter while nicht mehr wahr ist. 9.17 NOT Syntax: <LogicExpression> ::= NOT <Relation> Semantik: Der Operator 'not' gehört zu den logischen Operatoren. Er invertiert ein Argument vom Typ bool gemäß der folgenden Wertetabelle: a false true not a true false 9.18 NUM / SNUM Syntax: <TypeSpecifier> ::= NUM '(' INTVALUE ')' | NUM '(' INTVALUE ',' INTVALUE ')' | SNUM '(' INTVALUE ')' | SNUM '(' INTVALUE ',' INTVALUE ')' Semantik: Mit Hilfe von num und snum werden ganze Zahlen und Festkommazahlen repräsentiert. Es wird zwischen Werten ohne Vorzeichen (num) und Werten mit Vorzeichen (snum) unterschieden. Vor- und Nachkommastellen der Variablen werden durch ein Komma in der Deklaration getrennt: num (7,3) alpha; num (7,0) beta; num (7) gamma; Die Deklaration der Variablen beta und gamma ist äquivalent. Wenn die Anzahl der Nachkommastellen gleich Null ist, kann auf die Angabe verzichtet werden. CoLa Referenz-Handbuch Seite 45 9.19 OR Syntax: <LogicExpression> ::= <LogicExpression> OR <Relation> Semantik: Der Operator 'or' gehört zu den logischen Operatoren. Er verknüpft zwei Argumente vom Typ bool gemäß der folgenden Wertetabelle: a false false true true b false true false true a or b false true true true 9.20 RATE Syntax: <Rate> ::= RATE INTVALUE <Time> | RATE FPVALUE <Time> ::= MS | US | NS Semantik: Mit Hilfe von rate werden einzelnen Anweisungen Ausführungszeiten zugeordnet. Die Ausführungszeiten können als absolute Zeit in Milli-, Mikro- oder Nanosekunden angegeben werden, alternativ auch als relative Zeit, d.h. als prozentualer Anteil der insgesamt zur Verfügung stehenden Zeit. 9.21 RAISE / CATCH Syntax: <ExceptionHandler> ::= CATCH IDENTIFIER <CreateBlock> <Block> <ExceptionHandler> Semantik: Mit Hilfe von raise wird eine Unterbrechung ausgelöst. Sie ist genau eine Zeiteinheit aktiv. Auf catch folgt der Programmcode, der auf die Unterbrechung reagiert. Seite 46 CoLa Referenz-Handbuch 9.22 STEP Syntax: <Step> ::= STEP INTVALUE Semantik: Mit Hilfe von step werden Anweisungen nur zu dem hinter step spezifizierten Zeitpunkt ausgeführt. Wird kein step angegeben, wird „step 1“ angenommen, d.h. die Anweisung wird zu jedem Zeitpunkt angestoßen. 9.23 STRUCT Syntax: <TypeDefinition> ::= STRUCT IDENTIFIER '(' <StructList> ')' Semantik: Mit einem struct können Variablen zu einer Struktur zusammengefaßt werden. 9.24 SWITCH Syntax: <SelectionStatement> ::= <Switch> <CaseList> ')' <Switch> ::= SWITCH IDENTIFIER '(' <CaseList> ::= CASE <ConstExpressionSingle> <Block> <CaseList> | DEFAULT <Block> Semantik: In Abhängigkeit des Wertes der Variable nach switch wird der entsprechende Block hinter case ausgeführt. Paßt keiner der case-Anweisungen, so wird der Block nach default ausgeführt. Die Auswahlvariable kann einen beliebigen Typen haben. CoLa Referenz-Handbuch Seite 47 9.25 TRUE / FALSE Syntax: <ConstExpressionSingle> ::= TRUE | FALSE Semantik: Mit true und false werden die boolschen Werte repräsentiert. Sie können Variablen vom Typ bool zugewiesen werden oder mit Hilfe der logischen Operatoren zu komplexen logischen Ausdrücken kombiniert werden. Werden die boolschen Werte zu ganzzahligen Werten konvertiert, wird true zu 1 und false zu 0. 9.26 TYPE Syntax: <TypeDefinition> ::= TYPE IDENTIFIER <Type> Semantik: type gestattet die Definition von benutzerdefinierten Typen. Genaugenommen wird ein Alias auf einen Typ definiert, um kurze und aussagekräftige Bezeichner für Typen zu ermöglichen. CoLa unterscheidet Typen nicht anhand ihres Namen (Namesäquivalenz), sondern anhand ihrer Struktur (strukturelle Äquivalenz). 9.27 VECTOR Syntax: <Type> ::= VECTOR '(' INTVALUE ')' <Type> Semantik: Mit Hilfe von vector können mehrere Komponenten zu einem Array zusammengefaßt werden. Die einzelnen Komponenten dürfen sowohl vordefinierte Typen als auch benutzerdefinierte Typen sein. Alle Komponenten müssen allerdings den gleichen Typ haben. Um Komponenten von unterschiedlichem Typ zusammenzufassen kann struct verwendet werden. Auf einzelne Komponenten kann mit Hilfe der eckigen Klammern '[' und ']' zugegriffen werden. Seite 48 CoLa Referenz-Handbuch 9.28 XOR Syntax: <LogicExpression> ::= <LogicExpression> XOR <Relation> Semantik: Der Operator 'xor' gehört zu den logischen Operatoren. Er verknüpft zwei Argumente vom Typ bool gemäß der folgenden Wertetabelle: a false false true true b false true false true a xor b false true true false 10 Literaturverzeichnis [GAJSKI] Gajski, Daniel D.: „Silicon Compilation“, 450 Seiten, Reading, Mass. : Addison-Wesley, 1988 [LOUDEN] Louden, Kenneth C.: „Programmiersprachen : Grundlagen, Konzepte, Entwurf“, 1. Auflage, 810 Seiten, Bonn [u.a.] : Internat. Thomson Publ., 1994 [MARWEDEL] Marwedel, Peter: „Synthese und Simulation von VLSI-Systemen“, 196 Seiten, München [u.a.] : Hanser, 1993 [SCHNEIDER] Schneider, Hans-Jochen: „Lexikon der Informatik und Datenverarbeitung“, 3., aktualisierte und wesentl. erw. Auflage, 989 Seiten, München [u.a.] : Oldenbourg, 1991 [TEICH] Teich, Jürgen: „Digitale Hardware/Software-Systeme: Synthese und Optimierung“, 514 Seiten, Berlin [u.a.] : Springer, 1997 11 Anhang 11.1 Reservierte Wörter AND AUTOMAT BOOL CASE CATCH CHAR CONST DEFAULT DELAY ELSE FALSE FUNCTION IF INTERRUPT LOOP MS NEXTSTATE NOT NS NUM OR RAISE RATE SNUM STEP STRUCT SWITCH TO TRUE TYPE US VECTOR WHILE XOR 11.2 Vollständige Syntax <Start> ::= <Program> <Range> ::= '(' INTVALUE TO INTVALUE ')' Seite 52 CoLa Referenz-Handbuch <Rate> ::= RATE INTVALUE <Time> | RATE FPVALUE <Time> ::= MS | US | NS <Step> ::= STEP INTVALUE <Delay> ::= DELAY INTVALUE <RateStep> ::= [ <Rate> ] [ <Step> ] [ <Delay> ] <Program> ::= <FuncDeclarationList> <FuncDefinitionList> | <TypeDefinitionList> <FuncDeclarationList> <FuncDefinitionList> <FuncDeclarationList> ::= <FuncDeclarationList> <FuncDeclaration> | <FuncDeclarationList> <AutomatDeclaration> | <AutomatDeclaration> | <FuncDeclaration> <FuncDefinitionList> ::= <FuncDefinitionList> <FuncDefinition> | <FuncDefinitionList> <AutomatDefinition> | <AutomatDefinition> | <FuncDefinition> <FuncDeclaration> ::= '(' <ParaList> ')' FUNCTION IDENTIFIER '(' <ParaList> ')' ';' <FuncName> ::= FUNCTION IDENTIFIER <FuncDefinition> ::= <FuncName> <Block> <ExceptionHandler> <AutomatDeclaration> ::= '(' <ParaList> ')' AUTOMAT IDENTIFIER '(' <ParaList> ')' ';' <AutomatName> ::= AUTOMAT IDENTIFIER <AutomatDefinition> ::= <AutomatName> '(' <AutomatBlock> ')' <ExceptionHandler> CoLa Referenz-Handbuch <ExceptionHandler> ::= CATCH IDENTIFIER <CreateBlock> <Block> <ExceptionHandler> <TypeDefinitionList> ::= <TypeDefinitionList> <TypeDefinition> ';' | <TypeDefinition> ';' <TypeDefinition> ::= TYPE IDENTIFIER <Type> | STRUCT IDENTIFIER '(' <StructList> ')' <StructList> ::= <StructList> ',' <VarDeclaration> | <VarDeclaration> <ParaList> ::= <ParaListEx> <ParaListEx> ::= <VarDeclaration> | <ParaListEx> ',' <VarDeclaration> <VarDeclarationList> ::= <VarDeclarationList> <VarDeclarationLine> ';' | <VarDeclarationLine> ';' <VarDeclarationLine> ::= <VarDeclaration> <VarDeclarationEx> | <ConstDeclaration> <VarDeclarationEx> ::= <VarDeclarationEx> ',' IDENTIFIER <VarDeclaration> ::= <Type> IDENTIFIER | IDENTIFIER IDENTIFIER <PrimaryExpressionVector> ',' <ConstExpressionSingle> <ConstDeclaration> ::= CONST <VarDeclaration> ASSIGN <ConstExpressionSingle> <Type> ::= <TypeSpecifier> | VECTOR '(' INTVALUE ')' <Type> <TypeSpecifier> ::= BOOL | CHAR | NUM '(' INTVALUE ')' | NUM '(' INTVALUE ',' INTVALUE ')' | SNUM '(' INTVALUE ')' | Seite 53 Seite 54 CoLa Referenz-Handbuch SNUM '(' INTVALUE ',' INTVALUE ')' | INTERRUPT <Block> ::= '(' ')' | '(' <DataStatement> ')' | '(' <VarDeclarationList> <DataStatement> ')' <DataStatement> ::= <DataBlock> | <DataBlock> <ControlStatement> | <ControlStatement> <ControlStatement> ::= <ControlBlock> | <ControlBlock> <DataStatement> <DataBlock> ::= <DataBlock> <AssignExpression> | <AssignExpression> <ControlBlock> ::= <SelectionStatement> <RateStep> | <IterationStatement> <RateStep> <Block> <SelectionStatement> ::= IF '(' <LogicExpression> ')' <CreateBlock> <Block> | IF '(' <LogicExpression> ')' <CreateBlock> <Block> ELSE <CreateBlock> <Block> | <Switch> <CaseList> ')' <CreateBlock> ::= <Switch> ::= SWITCH IDENTIFIER '(' <CaseList> ::= CASE <ConstExpressionSingle> [ <CreateBlock> ] <Block> <CaseList> | DEFAULT [ <CreateBlock> ] <Block> <IterationStatement> ::= LOOP IDENTIFIER <Range> WHILE '(' <LogicExpression> ')' | LOOP IDENTIFIER <Range> | WHILE '(' <LogicExpression> ')' <AutomatBlock> ::= <AutomatAssign> <AutomatBlock> | <AutomatBody> <AutomatAssign> ::= <AssignExpression> CoLa Referenz-Handbuch Seite 55 <AutomatBody> ::= <AutomatBody> <AutomatState> | <AutomatState> <AutomatState> ::= <StateIdentifer> <StateAssignments> <StateIdentifer> ::= IDENTIFIER ':' <StateAssignments> ::= <AutomatTransition> | <AutomatAssign> <StateAssignments> <AutomatTransition> ::= <DefaultTransition> | <StandardTransition> <AutomatTransition> <StandardTransition> ::= '(' <LogicExpression> ')' NEXTSTATE IDENTIFIER ';' <DefaultTransition> ::= NEXTSTATE IDENTIFIER ';' <LogicExpression> <LogicExpression> <LogicExpression> <LogicExpression> NOT <Relation> | <Relation> ::= AND <Relation> | OR <Relation> | XOR <Relation> | <Relation> ::= '(' <Relation> ')' | <ArithExpression> EQ <ArithExpression> | <ArithExpression> NEQ <ArithExpression> | <ArithExpression> LESS <ArithExpression> | <ArithExpression> NLESS <ArithExpression> | <ArithExpression> GREATER <ArithExpression> | <ArithExpression> NGREATER <ArithExpression> <AssignExpression> ::= <PrimaryExpression> ASSIGN <ArithExpression> <RateStep> ';' | <PrimaryExpression> SL <RateStep> ';' | <PrimaryExpression> SR <RateStep> ';' <ArithExpression> <ShiftExpression> <ArithExpression> <ArithExpression> ::= | '&' <ShiftExpression> | '|' <ShiftExpression> <ShiftExpression> ::= Seite 56 CoLa Referenz-Handbuch <AdditiveExpression> | <ShiftExpression> SL <AdditiveExpression> | <ShiftExpression> SR <AdditiveExpression> <AdditiveExpression> ::= <MultExpression> | <AdditiveExpression> '+' <MultExpression> | <AdditiveExpression> '-' <MultExpression> <MultExpression> ::= <PrimaryExpression> | <MultExpression> '*' <PrimaryExpression> | <MultExpression> '/' <PrimaryExpression> <PrimaryExpression> ::= <PrimaryExpressionSingle> | '(' <PrimaryExpressionVector> ')' <ConstExpressionSingle> ::= INTVALUE | FPVALUE | TRUE | FALSE | CHARACTER <PrimaryExpressionSingle> ::= <SimpleAccess> <ExtAccess> | <ConstExpressionSingle> | '(' <ArithExpression> ')' <PrimaryExpressionVector> ::= <PrimaryExpressionVector> ',' <ConstExpressionSingle> | <ConstExpressionSingle> ',' <ConstExpressionSingle> <SimpleAccess> ::= IDENTIFIER | <ProcIdentifier> <ExpressionList> ')' <ExtAccess> ::= <ExtAccess> '[' <ArithExpression> ']' | <ExtAccess> '.' IDENTIFIER <ProcIdentifier> ::= IDENTIFIER '(' <ExpressionList> ::= <ExpressionList> ',' <ArithExpression> | <ArithExpression>