 Ŀ
            Die Assemblersprache des 6805 fuer absolute Newbies            
 

 Um das Listing des Betriebssystem zu verstehen und um die Faehigkeiten des
 Mikrokontrollersystems voll auszunutzen ist es sinnvoll die Assemblersprache
 zu beherrschen. Aus diesem Grund moechte ich in dieser Rubrik allen Leuten
 die bisher noch nie etwas mit der Assemblersprache und mit systemnaher
 Programmierung zu tun hatten eine kleine Einfuehrung zum Erlernen dieser
 nuetzlichen Sprache geben. Ich gehe davon aus, dass die Bedienung der DOS-
 IDE und das Programmieren des CCBASIC-Chips in BASIC keine Probleme
 bereitet.

 Ein Mikrokontroller wie der CCBASIC-Chip besteht intern aus vielen
 Baugruppen: I/O-Ports, A/D-, D/A-Wandler, die serielle Schnittstelle und
 Timer sorgen fuer eine Verbindung zur Aussenwelt; RAM, ROM und EEPROM dienen
 zum Speichern von Daten (Zahlen). Zum Steuern des Datenflusses zwischen
 diesen Baugruppen wird eine CPU benoetigt.

 Die dem CCBASIC-Chip zugrundeliegende CPU (MC6805) ist ein relativ einfacher
 Baustein. Wem das etwas sagt: Die CPU in diesem System besitzt weniger
 Register und weniger Befehle als die CPU die im guten alten C64 beheimatet
 war (das war die 6502'er CPU, ebenfalls von Motorola hergestellt).

 Zum Speichern von Daten innerhalb der CPU werden Register benutzt. Der
 MC6805 besitzt nur zwei Register: den Akkumulator und das Index-Register.
 Beide haben eine Breite von acht Bit, sie koennen somit jeweils nur ein Byte
 speichern. Die Breite der Register ist von grosser Bedeutung, denn sie sind
 in fast allen Aktionen die eine CPU ausfuehren kann verwickelt.

 Gesteuert wird die CPU ueber ein sogenanntes Maschinenspracheprogramm. Wie
 bei jeder Programmiersprache, so gibt es auch in der Maschinensprache
 Befehle, die bestimmen was zu tun ist. Die Befehle in dieser Sprache
 bestehen aber nur aus Zahlen die innerhalb des Adressraums der CPU abgelegt
 werden. Wenn ein Programm ablaeuft holt die CPU einen Befehl (eine Zahl) aus
 dem Speicher und fuehrt den Befehl aus. Mit dieser Befehlsausfuehrung wird
 (bis auf wenige Ausnahmen) solange weitergemacht, bis jemand dem
 Mikrokontroller den Strom 'abdreht.

 Um ein Maschinenspracheprogramm zu schreiben muesste man nun also den
 Speicher des Mikrokontrollers mit lauter Zahlen fuellen und diese Zahlen
 anschliessend von der CPU ausfuehren lassen. Weil nun aber nicht jeder
 Mensch saemtliche Zahlen saemtlicher Befehle im Kopf hat, wurde eine
 Zwischensprache, die sogenannte Assemblersprache eingefuehrt, in der die
 einzelnen Befehle der CPU nicht mehr durch Zahlen, sondern durch relativ
 leicht verstaendliche englische Worte oder Abkuerzungen symbolisiert werden.
 Zum Beispiel wird durch "lda $50" ein Befehl symbolisiert, mit dem ein Byte
 von Adresse $50 (das $ steht fuer eine Hexadezimalzahl) aus dem
 Arbeitsspeicher in das Akkumulator-Register der CPU geladen wird (engl.:
 "Load Accumulator"). Fuer die CPU besteht dieser Befehl nach wie vor nur aus
 Zahlen (naemlich $a6 und $50), so das ein Assemblerprogramm erst in die
 Zahlen die die CPU versteht uebersetzt werden muss bevor es ausgefuehrt
 werden kann. Diese Umwandlungsarbeit wird durch einen sogenannten Assembler
 vollzogen.

 Der Begriff "Assembler" wird haeufig unterschiedlich benutzt. Fuer manche
 ist Assembler das Programm zum Uebersetzen; fuer andere ist Assembler gleich
 der Assemblersprache. Es sind also beide Definitionen gebraeuchlich.

 Dieser Sammlung liegt ein Assembler bei. Er wurde von Frank A. Vorstenbosch
 von der Firma Kingswood Software entwickelt. Um mit diesem Assembler eigene
 Programme zu schreiben sollte das Assemblerprogramm mit dem Editor der DOS-
 IDE geschrieben und dannach assembliert, d.h. uebersetzt werden. Das
 ausfuehrbare Maschinenspracheprogramm liegt dann bereits in dem vom CCBASIC-
 Compiler benoetigten S19-Format vor.

 Als einfaches, erstes Beispiel hier ein Programm mit dem der Inhalt einer
 Bytevariablen veraendert werden kann. Um ein Maschinenspracheprogramm zum
 CCBASIC-Chip zu uebertragen ist ein BASIC-Programm notwendig.


                            Hier das BASIC-Programm:
            (in der DOS-IDE eingeben und unter FIRST.BAS speichern)

   define variable byte[1]  ' Bytevariable deklarieren

   #start                   ' #start ist ein BASIC-Label

   variable=123             ' der Variablen wird der Wert 123 zugewiesen
   print variable           ' der Wert der Variablen wird ausgegeben
   sys &h101                ' das Maschinenspracheprogramm wird gestartet
   print variable           ' der Wert der Variablen wird wieder ausgegeben

   syscode "first.s19"      ' assembliertes Programm einbinden


                        Und hier das Assemblerprogramm:
       (ebenfalls in der DOS-IDE eingeben und unter FIRST.ASM speichern)

     org $101               ; das Maschinenspracheprogramm beginnt an
                            ; Adresse $101 (erste EEPROM-Adresse)

   start:                   ; start: ist ein Maschinensprache-Label

     ldx #$a1               ; Index-Register mit dem Wert $a1 laden
     lda #77                ; Akkumulator-Register mit dem Wert 77 laden
     sta ,x                 ; Akkumulatorinhalt auf Adresse die im Index-
                            ; Register steht speichern (auf Adresse $a1)
     rts                    ; Ruecksprung zum BASIC (hinter den SYS-Befehl)


 Bei der Eingabe des Assemblerprogramms muss beachtet werden, dass vor
 "start:" KEIN Leerzeichen stehen darf. Vor jeder anderen Zeile MUSS ein
 (oder mehrere) Leerzeichen stehen, denn alle Zeilen vor denen kein
 Leerzeichen steht werden vom Assembler als Label angesehen (vgl. #start im
 CCBASIC-Dialekt). Die beiden Label "start" im BASIC- als auch im
 Assemblerprogramm dienen nur zur Verdeutlichung und koennen auch weggelassen
 werden.

 Bevor das BASIC-Programm compiliert werden kann muss erst das Assembler-
 Programm assembliert werden. Guenstigerweise kann das direkt aus der DOS-IDE
 heraus geschehen. Dafuer muss allerdings erst der Assembler in der IDE
 eingebunden werden. Wie das geht wird in dieser Textdatei weiter unten, bei
 "Entwickeln von Assemblerprogrammen in der DOS-IDE" erklaert. Falls der
 Assembler noch nicht in die IDE eingebunden wurde, bitte erst dort
 weiterlesen.

 Nun aber zurueck zu unserem ersten Beispiel. Nachdem das Assemblerprogramm
 assembliert wurde, kann das BASIC-Programm wie ueblich compiliert, und dann
 zum CCBASIC-Chip uebertragen werden. Wird das Programm gestartet,
 uebertraegt der Mikrokontroller die Werte 123 und 77 ueber die serielle
 Schnittstelle zum PC.

 In dem Programm haben wir von der Tatsache gebrauch gemacht, dass die 24
 Byte, die dem BASIC-Programmierer zum Speichern von Variablen zur Verfuegung
 stehen, im Speicher ab Adresse $a1 bis Adresse $b8 abgelegt sind. Immer wenn
 ein Assemblerprogramm Werte von Speicherzellen aendert die in diesem
 Adressbereich liegen hat das Auswirkungen auf BASIC-Variablen.

 Maschinenspracheprogramme muessen immer auf diese Art und Weise in ein
 BASIC-Programm eingebunden (mittels SYSCODE), aufgerufen (mit SYS) und
 beendet (mit RTS) werden.

 Das zweite Beispiel zeigt, wie ein Maschinenspracheprogramm einen Wert an
 eine beliebige BASIC-Variable zurueckliefern kann.

                            Hier das BASIC-Programm:
            (in der DOS-IDE eingeben und unter SECOND.BAS speichern)

   define variable word
   
   variable = rueckgabe
   print variable
   end
   
   syscode "second.s19"
   
   #rueckgabe
     sys &h101
   return


                  Und hier das zugehoerige Assemblerprogramm:
       (ebenfalls in der DOS-IDE eingeben und unter SECOND.ASM speichern)

     org $101
   
     lda #$30      ;Akkumulator mit dem Wert $30 laden
     sta $91       ;Akku auf Speicherstelle $91 speichern
     lda #$39      ;Akkumulator mit dem Wert $39 laden
     sta $92       ;Akku auf Speicherstelle $92 speichern
   
     rts


 Um Rechenergebnisse zwischenzuspeichern benutzt der BASIC-Interpreter einen
 Stack der bei Adresse $91 beginnt und bis $9e reicht. Es handelt sich um
 einen sogenannten LIFO-Stack (Last In First Out), d.h. das Word das zuletzt
 auf den Stack gespeichert (gepusht) wurde wird beim naechsten Laden zuerst
 vom Stack heruntergeholt (gepoppt). Das zuletzt auf den Stack gepushte Word
 wird haeufig auch als "Top-Of-Stack" gezeichnet und liegt beim CCBASIC-Chip
 auf den Adressen $91 und $92. Bei der Wertzuweisung in Zeile 3 des BASIC-
 Programms wird das "Top-Of-Stack"-Word vom Stack gepoppt und in der
 Variablen abgespeichert, so das ein Maschinenspracheprogramm einfach nur den
 gewuenschten Rueckgabewert in den Adressen $91 und $92 ablegen muss. Weitere
 Informationen zur Belegung anderer Speicherbereiche befinden sich uebrigens
 in der Textdatei ADRESSEN.TXT.

 Klar, diese einfachen Maschinenspracheprogramme hauen niemanden vom Hocker.
 Das gleiche Ergebnis haette mit wesentlich weniger Aufwand in BASIC
 programmiert werden koennen. Allerdings ist es in der Regel immer so, dass
 Assemblerprogramme, die einen bestimmten Zweck erfuellen, laenger und
 umstaendlicher zu programmieren sind als BASIC-Programme. Der Vorteil von
 Maschinenspracheprogrammen liegt in der hoeheren Ausfuehrungsgeschwindigkeit
 und dem Umstand, dass in dieser Sprache die Moeglichkeiten der CPU und aller
 anderen Baugruppen im Mikrokontroller wirklich voll ausgeschoeft werden
 koennen.

 Im dritten und letzten Beispiel benutzen wir eine Betriebssystemroutine um
 uns das Leben leichter zu machen. Das Maschinenspracheprogramm uebertraegt
 eine ASCII-Codetabelle (von Zeichen 32 bis 127) ueber die serielle
 Schnittstelle zum PC. Das Basicprogramm dient hier einzig und allein zum
 Aufruf des Maschinenspracheprogramms.


                            Hier das BASIC-Programm:
            (in der DOS-IDE eingeben und unter THIRD.BAS speichern)

   sys &h101
   syscode "third.s19"


                        Und hier das Assemblerprogramm:
       (ebenfalls in der DOS-IDE eingeben und unter THIRD.ASM speichern)

     org $101
   
     lda #32                ; Akkumulator mit dem Wert 32 laden
     sta $a1                ; Akku auf Speicherstelle $a1 speichern
   loop:                    ; loop ist ein Label (hier ein Sprungziel)
     tax                    ; Index-Register mit Akku-Inhalt laden
     jsr $0c77              ; Inhalt des Index-Registers ueber die
                            ; serielle Schnittstelle senden
     inc $a1                ; Wert auf Adresse $a1 um eins erhoehen
     lda $a1                ; Akku mit Inhalt der Adresse $a1 laden
     cmp #127               ; vergleiche Akku-Inhalt mit der Zahl 127
     bls loop               ; springe nach loop, wenn Akku-Inhalt
                            ; kleiner oder gleich 127 ist, sonst mache
                            ; mit dem naechsten Befehl nach "bls" weiter
   
     ldx #$0d               ; lade Index-Register mit dem Wert 13
     jsr $0c77              ; und ueber serielle Schnittstelle senden
     ldx #$0a               ; lade Index-Register mit dem Wert 10
     jsr $0c77              ; und ueber serielle Schnittstelle senden
   
     rts


 Dieses Beispiel enthaelt eine Schleife, vergleichbar mit einer BASIC-
 FOR-NEXT-Schleife in der eine Bytevariable von 32 bis 127 hochgezaehlt wird.
 Der Inhalt des Schleifenzaehlers wird mittels einer Betriebssystemroutine
 die an der Adresse $0c77 beginnt ueber die serielle Schnittstelle (RS232)
 ausgegeben. Die Routine benoetigt als Uebergabe im Index-Register den Wert
 der ueber die RS232 als Byte ausgegeben werden soll. So oder aehnlich werden
 die meisten Systemroutinen aufgerufen. Der "jsr"-Befehl entspricht ziemlich
 genau dem "SYS"-Befehl im BASIC. Die Adressen und Aufrufparameter weiterer
 Betriebssystemroutinen kann dem ROM-Listing (in der Textdatei CCBASROM.TXT)
 entnommen werden.

 Der "bls loop"-Befehl stellt in unserem kleinen Assemblerkurs eine echte
 Neuerung dar. Waehrend alle bisher benutzten Befehle sequentiell (d.h. der
 Reihe nach) ausgefuehrt wurden, ist es mit diesem Befehl zum ersten Mal
 moeglich Programmbereiche in Abhaengigkeit einer Bedingung zu ueberspringen
 oder wiederholt auszufuehren. Man spricht von bedingten Sprungbefehlen, mit
 denen IF..THEN Abfragen realisiert werden koennen. Der Befehlssatz der
 6805'er CPU enthaelt insgesamt 30 dieser in fast jedem Assemblerprogramm
 anzutreffenden Befehle.

 Tja, und wenn man es genau betrachtet sind damit eigentlich die
 grundlegendsten Themenbereiche zur Programmierung des CCBASIC-Chips in
 Maschinensprache behandelt worden. Natuerlich war das nur eine kleine
 Einfuehrung in diese Programmiersprache, doch wer Intresse hat kann sich ja
 anhand des ROM-Listing oder der Datei DI05.MNE (dort werden alle 256 Befehle
 des 6805 in englischer Sprache erklaert) weiterbilden. Eigentlich ist die
 Programmierung des 6805 nicht sehr kompliziert, was wohl auch daran liegt
 das diese CPU eben nur zwei Register besitzt, die zudem nur acht Bit lang
 sind. Man kommt garnicht 'drumherum fast jede benoetigte Byte-, und sowieso
 jede Wordvariable im Arbeitsspeicher (RAM) zwischenzuspeichern.

 Weitere Informationen zur CPU und deren Besonderheiten - gerade im Vergleich
 zu anderen CPUs - befindet sich in der Datei MC68HC05.TXT.


 Ŀ
             Entwickeln von Assemblerprogrammen in der DOS-IDE             
 

 Mit der DOS-IDE lassen sich perfekt Assemblerprogramme entwickeln. Dafuer
 muss der dieser Sammlung beiliegende Assembler AS05.EXE allerdings erst in
 der IDE eingebunden werden. Das geschieht im Menupunkt "Tools" im "Option"-
 Menu. Hier stehen die Programmnamen der verschiedenen Hilfsprogramme der IDE
 und deren Aufrufparameter. Im Requester muss unter Assembler/Programm
 "$CCEPATH$\AS05.EXE" und unter Assembler/Parameter "-s -lnul $NOSWAP$
 $EDNAMEFULL$" eingegeben werden (beides bitte ohne Gaensefuesschen). Nach
 einem Druck auf OK sollte der Assembler nun bei jedem editierten
 Assemblerprogramm ueber das Menu "Entwicklung" aufrufbar sein;
 vorrausgesetzt die Datei AS05.EXE wurde in das selbe Verzeichnis kopiert in
 dem sich auch CCE.EXE befindet.

 Dieser Sammlung liegt zusaetzlich die Datei CCE.TOK bei. Wenn diese Datei
 ebenfalls in das CCE-Verzeichnis kopiert wird (das alte CCE.TOK wird
 ueberschrieben), unterstuetzt der Editor der IDE nun nicht nur bei BASIC-,
 sondern auch bei Assemblerprogrammen Syntaxhighlightning.

 Noch ein wichtiger Hinweis: Der Assembler braucht hinter der letzter Zeile
 eines Programms unbedingt einen Carriage Return plus Line Feed, also
 unbedingt darauf achten, dass hinter dem letzten Befehl eines Programms die
 Return-Taste gedrueckt wird. Sonst wird u.U. das letzte RTS einfach
 ignoriert (!).
