Erstellt: 10. März 2013 (zuletzt geändert: 28. November 2018)

Schalt mich ein, schalt mich aus

Und oder nicht?

C64 Studio, AMCE & TASM

Die boolschen Befehle werden häufig genutzt, um einzelne Bits zu setzen oder zu löschen. Schaut euch am besten nochmal die Boolsche Algebra an, falls ihr nicht mehr genau vor Augen habt, wie UND und ODER funktionieren.

Wir testen die Boolschen-Befehle in einem neuen, kleinen Beispiel.

Wir werden nun bei den ersten 240 Zeichen auf dem BS jedes zweite invertieren. Wer möchte kann als kleine Übung das Programm ja später so ändern, dass das Programm sich auf den gesamten Bildschirm bezieht. Invertieren bedeutet nichts Anderes, als Zeichen- und Hingrundfarbe zu vertauschen. Wer sich mal Bild-1 und Bild-2 beim Char-ROM ansieht, dem wird jetzt bestimmt etwas auffallen. Das zweite Bild zeigt exakt die gleichen Zeichen, die auch schon auf dem ersten zu sehen sind, nur invertiert. Uns als Binär-Profis sollte bei einem Blick auf die Nummern der einzelnen Zeichen noch etwas ins Auge stechen (Autsch!).

Nehmen wir als Beispiel mal das Zeichen für die Ziffer 7, dies hat in der normalen Darstellung die Nr. 55 / $37 und invertiert die Nr. 183 / $b7 im Zeichensatz.

normal....:  55 = $37 = %00110111
invertiert: 183 = $b7 = %10110111

Jetzt sollte allen klar sein, dass man zum invertierten Zeichen kommt, wenn man einfach das höchste Bit setzt. Das seht ihr ja auch in den beiden Bildern beim Char-ROM, da alle normalen Zeichen im 1. Bild von Nr. 0-127 zu finden sind, die invertierten aber von Nr. 128 bis 255 im zweiten Bild.

Oder

Wir brauchen nun also ein Programm, dass für jedes Zeichen das höchste Bit setzt.

;*** Variablen
SCREENRAM = $03ff       ;Start des Bildschirmspeichers
ORAMASK   = %10000000

;*** Startadresse BASIC-Zeile
*=$0801
 !byte $0c,$08,$e2,$07,$9e,$20,$32,$30,$36,$32,$00,$00,$00

;*** Start des Assemblerprogrammes
 ldy #$f0               ;die ersten 240 Zeichen

loop_ora
 lda SCREENRAM,y        ;Zeichen in den Akku

Beim Turbo Assembler könnt ihr keine Unterstriche wie bei loop_ora verwenden, lasst diese einfach weg und schreibt die Labelbezeichnungen direkt zusammen. Denkt auch weiterhin daran, dass die Label dort max. 15 Zeichen lang sein dürfen.

Hier ist nichts Spektakuläres zu sehen, einzig die neue Variable ORAMASK. In unserer Schleife direkt hinter loop_ora laden wir erstmal das Zeichen in den Akku, dass sich an der Adresse SCRENNRAM plus Y-Register (absolute Y-indizierte Adressierung) befindet.

 ora #ORAMASK           ;ODER-Verknüpfung des Akkus mit mit unserer Maske

ORA: OR with Accumulator (bitweises ODER mit dem Akku)
ORA Akku ($09, 2B, 2T, NZ)
Hier führen wir jetzt mit ORA eine bitweise ODER-Verknüpfung mit dem Akku und unserer ORAMASK durch. Das Ergebnis landet dann wieder im Akkumulator. Ist das Ergebnis 0, dann wird das Z-Flag gesetzt, sollte Bit-7 auf eins stehen, dann wird das N-Flag gesetzt.
Beim ODER wird ein Bit immer dann zu 1, wenn entweder das erste oder das zweite oder beide beteiligten Bits eine 1 aufweisen:

    %0101
ORA %0011
    =====
    %0111

ORA wird daher verwendet, um gezielt einzelne Bits zu setzen, dazu läßt man in seiner Maske alle Bits, die man nicht ändern möchte auf 0 und setzt nur die Bits auf 1 die man auf jeden Fall auf 1 setzen will. Deshalb ist in unserer Maske nur Bit-7 auf 1 gesetzt worden, alle anderen sind 0.

Im Detail sieht das für unser Zeichen 7, wenn es im Akku liegt, so aus:

Akku:  %00110111
          ORA
Maske: %10000000
       =========
Akku:  %10110111

Voiala, wir haben das Zeichen 183, das der invertierten Darstellung der entspricht.

 sta SCREENRAM,y        ;Zeichen auf der 1. Page des BS-Speichers ausgeben

 dey                    ;Y-Register verringern und gleich nochmal, da
 dey                    ;wir nur jedes 2. Zeichen invertieren wollen
 bne loop_ora           ;solange nicht 0 wieder zum loop_ora springen

 rts                    ;Zurück zum BASIC

Anschließend schreiben wir den geänderten Akku-Inhalt wieder zurück an unsere Position auf dem BS, verringern das Y-Register zweimal fürs übernächste Zeichen und springen solange zu loop_ora zurück, bis das Z-Flag gesetzt ist. Zum Ende gehts zurück ins Basic.

Nach einem Start sollte euer BS ungefähr so aussehen:

Von den ersten 240 Zeichen, jedes 2. invertiert

Nun wollen wir unsere Invertierung wieder rückgängig machen. Dazu verwenden wir diesmal die Möglichkeit aus Basic heraus direkt an die gewünschte Stelle in unserem Programm zuspringen. Vom Prinzip her machen wir das schon bei jedem Programmstart. Unsere Programme beginnen bekanntlich mit der Zeile: 2018 SYS 2062
Diesen SYS-Befehl können wir natürlich auch direkt eingeben, also statt RUN einfach SYS 2062. Ändern wir unser Programm und probieren es mal.

Und

Gebt bitte am Sourcebeginn, hinter ORAMASK , eine neue Variable ein:

ANDMASK   = %01111111

Fügt dann hinter unser bisheriges Programm (Ausschnitt ist unten zur Orientierung markiert), die nächsten Zeilen ein:

 ...
 bne loop_ora           ;solange nicht 0 wieder zum loop_ora springen

 rts                    ;Zurück zum BASIC

*=$1000 ;(4096)
 ldy #$f0               ;wieder nur die ersten 240 Zeichen

loop_and
 lda SCREENRAM,y        ;Zeichen in den Akku

Etwas irritiert könntet ihr jetzt durch *=$1000 sein. Eigentlich benutzen wir dies ja, um die Startadresse für unser Programm festzulegen (bisher fast immer *=$0801). Auch wenn es nicht wirklich benötigt wird, teilen wir hier dem Assembler mit, dass die nächsten Befehle an der Speicherstelle $1000 oder 4096 dezimal beginnen sollen. Falls ihr neue Adressen angebt, passt besser auf, dass sich diese nicht überschneiden. Das C64 Studio wirft einen Fehler, sollte dies der Fall sein. Bei ACME gibt es eine Warnung, die ja unterdrückt werden können. Der Turbo Assembler nimmt eure Angabe ohne weitere Hinweise / Warnungen an. Wir benutzen dies nur um eine schönere Einsprungadresse für unsere neue Funktion zu erhalten.

 and #ANDMASK           ;UND-Verknüpfung des Akkus mit mit unserer Maske

AND: AND with Accumulator (bitweises UND mit dem Akku)
AND Akku ($29, 2B, 2T, NZ)
Auch wenn wir das AND schon hatten, wiederhole das hier der Vollständigkeit nochmal. Wir führen jetzt mit AND eine bitweise UND-Verknüpfung mit dem Akku und unserer ANDMASK durch. Das Ergebnis landet dann wieder im Akkumulator. Ist das Ergebnis Null, dann wird das Zero-Flag gesetzt, sollte Bit-7 auf 1 stehen, dann wird das N-Flag gesetzt.
Beim AND wird ein Bit immer dann zu 1, wenn das erste und das zweite Bit eine 1 aufweist:

    %0101
AND %0011
    =====
    %0001

AND verwenden wir, um gezielt einzelne Bits zu löschen, dazu läßt man in seiner Maske alle Bits, die man nicht ändern möchte auf 1 und setzt nur die Bits auf 0, die man auf jeden Fall löschen will. Daher ist in unserer Maske nur Bit-7 auf 0 gesetzt worden, alle Anderen sind 1.

Und jetzt nochmal für unser invertiertes Zeichen , wenn es im Akku liegt:

Akku:  %10110111
          AND
Maske: %01111111
       =========
Akku:  %00110111

Schon haben wir wieder das Zeichen 55, das der normalen Darstellung der 7 entspricht.

 sta SCREENRAM,y        ;Zeichen auf der 1. Page des BS-Speichers ausgeben

 dey                    ;Y-Register verringern (jetzt nur einmal)
 bne loop_and           ;solange nicht 0 wieder zum loop_and springen

 rts                    ;Zurück zum BASIC

Der Rest entspricht dem Block von eben, nur das wir hier einfach mal alle 240 Zeichen anfassen. Es gibt absichtlich nur ein dey, um zu zeigen, dass sich wirklich nur unsere invertierten Zeilen ändern.

Wenn ihr das Progamm nun startet, gibt es zunächst keinen Unterschied zu eben. Gebt jetzt aber mal SYS 4096 ein, drückt RETURN und schon ist die Invertierung verschwunden. Wir springen damit direkt zum Beginn unserer neuen Routine, die ja hinter *=$1000 beginnt. Mit RUN könnt ihr natürlich wieder die Invertierung vornehmen.

Manuell hin- und herschalten.
Exklusives Oder

Abschließend möchten wir jetzt unsere Invertierung invertieren 😉 . Wir wollen also innerhalb der ersten 240 Zeichen alle normalen invertiert darstellen und alle invertierten normal. Dazu könnten wir in unserer Schleife, das in den Akku geladene Zeichen prüfen und dann zur jeweiligen Verknüpfung springen.
Die Routine würde dann so aussehen (bitte am Programmende einfügen!):

*=$2000 ;(8192)
;*** Start des Assemblerprogrammes
 ldy #$f0               ;die ersten 240 Zeichen

loop_onoff
 lda SCREENRAM,y        ;Zeichen in den Akku und

Bis auf unsere neue Startadresse *=$2000 ist alles wie gehabt.

 bmi donormal           ;wenn Bit-7 (Invers) gesetzt ist, zu donormal: springen

BMI: Branch if MInus (springe wenn Minus)
BMI relativ ($30, 2B, 2-4T, <keine>)
Mit BMI verzweigen wir zur angegebenen Adresse, wenn nach der letzten Aktion das „Minuszeichen“ gesetzt ist. Es wird also einfach geprüft, ob das Negativ-Flag = 1 ist. Wie von den anderen bedingten Sprüngen gewohnt, werden 2 Taktzyklen benötigt, wenn nicht gesprungen wird, 3TZ beim Sprung und sogar 4TZ falls der Sprung über eine Pagegrenze geht.
Wir überprüfen hier unser eben in den Akku geladenes Zeichen. Ist es bereits invertiert, dann ist das Bit-7 ja gesetzt und wir springen zu donormal, um die Invertierung aufzuheben, wenn es aktuell nicht invertiert ist invertieren wir es mit dem nächsten Befehl…

 ora #ORAMASK           ;sonst ODER-Verknüpfung für Invers
 jmp charout            ;weiter zur Ausgabe

donormal
 and #ANDMASK           ;UND-Verknüpfung für 'normal'

charout
 sta SCREENRAM,y        ;Zeichen auf der 1. Page des BS-Speichers ausgeben

 dey                    ;Y-Register verringern
 bne loop_onoff         ;solange nicht 0 wieder zum loop_onoff springen

 rts                    ;Zurück zum BASIC

Wenn wir invertieren mussten, springen wir nach dem ORA direkt zu charout, müssen wir die Invertierung aufheben, landen wir nach dem BMI bei donormal und löschen mit dem AND unsere Invertierung. Anschließen wird das Zeichen wieder ausgegeben usw. (alles wieder wie eben).

Startet das Programm und es erscheint wieder unsere gestreifte Darstellung. Mit SYS 4096 könnt ihr diese wieder rückgängig machen. Gebt ihr nach dem RUN aber die Startadresse SYS 8192 ein, wird der obere Bereich des Bildschrims inveriert. Bei jedem Aufruf (einfach mit dem Cursor wieder auf den SYS-Befehl gehen und RETURN drücken) ändert sich unsere Anzeige. Probiert das ruhig mal mit der gestreiften und der blanken Darstellung (nach SYS 4096) aus.

OK, dass habe ich jetzt nur eingebaut, um mal den BMI-Befehl zu verwenden und nochmal zu zeigen, dass es viele Lösungsmöglichkeiten gibt. Wir können das Problem auch viel eleganter lösen. Es gibt nämlich einen Befehl, der es uns ermöglicht die Umschaltung zwischen invertiert und normal automatisch vorzunehmen. Gebt die nächsten Zeilen direkt hinter dem Block mit dem BMI-Befehl von eben, also wieder am Ende unseres Sourcecodes ein.

;(8213)
start_eor
 ldy #$f0               ;die ersten 240 Zeichen durchgehen

loop_eor
 lda SCREENRAM,y        ;Zeichen in den Akku

Dieses Mal verzichten wir auf eine neue Startadresse, daher ist es sehr wichtig, dass die vorherige Routine unverändert von euch übernommen wurde, sonst stimmt die im Kommentar ;(8213) angezeigte Startadresse nicht! Der Rest ist mittlerweile kalter Kaffee für uns.

 eor #ORAMASK           ;Exklusiv-ODER-Verknüpfung Akku mit mit unserer Maske

EOR: Exclusiv OR with Accumulator (bitweises exklusives ODER mit dem Akku)
EOR Akku ($49, 2B, 2T, NZ)
Wow, etwas ganz exklusives… EOR arbeitet fast wie ORA. Wir verwenden hier auch unsere ORAMASK und das Ergebnis landet wieder im Akku. Ist das Ergebnis negativ (also Bit-7 gesetzt), dann wird das Negativ-Flag gesetzt, sollte das Ergebnis Null sein, wird das Z-Flag gesetzt.
Beim EOR wird ein Bit nur dann zu 1, wenn ausschließlich das erste oder das zweite Bit eine 1 aufweist:

    %0101
EOR %0011
    =====
    %0110

EOR wird häufig zum Umschalten von einzelnen Bits verwendet. Dazu setzen wir in unserer Maske alle Bits, die Umgeschaltet werden sollen auf 1 und die anderen auf 0.

Für unser Zeichen 7 im Akku, sähe das dann so aus:

Akku:    %00110111
            EOR
Maske:   %10000000
         =========
Akku:    %10110111
nächstes    EOR
Maske:   %10000000
         =========
Akku:    %00110111

Wie ihr seht, schalten wir mit jedem EOR immer das 7-Bit um, die anderen bleiben unverändert.

 sta SCREENRAM,y        ;Zeichen auf der 1. Page des BS-Speichers ausgeben
 dey                    ;Y-Register verringern
 bne loop_eor           ;solange nicht 0 wieder zum loop_eor springen

 jmp start_eor          ;für Endlosschleife zu start_eor springen

Wir fabrizieren hier eine Endlosschleife (also obacht beim Start, ggf. vorher speichern), um mal wieder unsere Anfälligkeit für schnelle Bildwechsel zu prüfen.

Zur Sicherheit hier wieder das komplette Programm:

;*** Variablen
SCREENRAM = $03ff       ;Start des Bildschirmspeichers
ORAMASK   = %10000000
ANDMASK   = %01111111

;*** Startadresse BASIC-Zeile
*=$0801
 !byte $0c,$08,$e2,$07,$9e,$20,$32,$30,$36,$32,$00,$00,$00

;*** Start des Assemblerprogrammes
 ldy #$f0               ;die ersten 240 Zeichen

loop_ora
 lda SCREENRAM,y        ;Zeichen in den Akku
 ora #ORAMASK           ;ODER-Verknüpfung des Akkus mit mit unserer Maske
 sta SCREENRAM,y        ;Zeichen auf der 1. Page des BS-Speichers ausgeben

 dey                    ;Y-Register verringern und gleich nochmal, da
 dey                    ;wir nur jedes 2. Zeichen invertieren wollen
 bne loop_ora           ;solange nicht 0 wieder zum loop_ora springen

 rts                    ;Zurück zum BASIC
 

*=$1000 ;(4096)
 ldy #$f0               ;wieder nur die ersten 240 Zeichen

loop_and
 lda SCREENRAM,y        ;Zeichen in den Akku
 and #ANDMASK           ;UND-Verknüpfung des Akkus mit mit unserer Maske
 sta SCREENRAM,y        ;Zeichen auf der 1. Page des BS-Speichers ausgeben

 dey                    ;Y-Register verringern (jetzt nur einmal)
 bne loop_and           ;solange nicht 0 wieder zum loop_and springen

 rts                    ;Zurück zum BASIC


*=$2000 ;(8192)
;*** Start des Assemblerprogrammes
 ldy #$f0               ;die ersten 240 Zeichen

loop_onoff
 lda SCREENRAM,y        ;Zeichen in den Akku und
 bmi donormal           ;wenn Bit-7 (Invers) gesetzt ist, zu donormal: springen
 ora #ORAMASK           ;sonst ODER-Verknüpfung für Invers
 jmp charout            ;weiter zur Ausgabe

donormal
 and #ANDMASK           ;UND-Verknüpfung für 'normal'

charout
 sta SCREENRAM,y        ;Zeichen auf der 1. Page des BS-Speichers ausgeben

 dey                    ;Y-Register verringern
 bne loop_onoff         ;solange nicht 0 wieder zum loop_onoff springen

 rts                    ;Zurück zum BASIC

;(8213)
start_eor
 ldy #$f0               ;die ersten 240 Zeichen durchgehen

loop_eor
 lda SCREENRAM,y        ;Zeichen in den Akku
 eor #ORAMASK           ;Exklusiv-ODER-Verknüpfung Akku mit mit unserer Maske
 sta SCREENRAM,y        ;Zeichen auf der 1. Page des BS-Speichers ausgeben
 dey                    ;Y-Register verringern
 bne loop_eor           ;solange nicht 0 wieder zum loop_eor springen

 jmp start_eor          ;für Endlosschleife zu start_eor springen

Ein Start zeigt unser Streifenmuster, mit SYS 8213 springt ihr aber in die Endlosschleife mit dem EOR-Befehl und alles flackert…

Endlosschleife mit EOR

Eine Bemerkung am Rande, wenn ihr jetzt einen RESET (z. B. mit ALT+R bei Vice) auslöst und dann SYS 8213 eingebt. Läuft unser Programm wieder an. Also merke, der Speicher wird bei einem RESET nicht gelöscht / initialisiert (jedenfalls nicht alles, Teilbereiche werden schon verändert!).

Wer sich die Boolsche Algebra angesehen hat, der fragt sich jetzt bestimmt wo denn der NOT-Befehl bleibt. Den gibt es zwar unter BASIC, aber nicht im Assembler. Macht noch ein paar Übungen mit den drei boolschen Befehlen und ihr kommt sicher auf die Lösung. Hilfreich könnte es evtl. sein, unser Programm aus dem letzten Beitrag Mit dem Rechner rechnen so anzupassen, dass auch die boolschen Befehle getestet werden können.

Weitere Adressierungsarten

Es folgt wieder die endlos erscheinende Liste, der alternativen Adressierungsarten. Da AND, ORA und EOR identische Adressierungsarten besitzen, werden die jeweils am Stück behandelt.

 ora $0821

ORA absolut ($0D, 3B, 4T, NZ)

 and $0821

AND absolut ($2D, 3B, 4T, NZ)

 eor $0821

EOR absolut ($4D, 3B, 4T, NZ)
Eine Verknüpfung mit dem Akku und dem Byte, dass an der absoluten Adresse zu finden ist.

 

 ora $0821,x

ORA absolut X-indiziert ($1D, 3B, 4-5T, NZ)

 and $0821,x

AND absolut X-indiziert ($3D, 3B, 4-5T, NZ)

 eor $0821,x

EOR absolut X-indiziert ($5D, 3B, 4-5T, NZ)
Eine Verknüpfung mit dem Akku und dem Byte, dass an der absoluten Adresse plus dem X-Register zu finden ist. Beim überschreiten einer Page-Grenze wird ein extra Taktzyklus fällig.

 

 ora $0821,y

ORA absolut Y-indiziert ($19, 3B, 4-5T, NZ)

 and $0821,y

AND absolut Y-indiziert ($39, 3B, 4-5T, NZ)

 eor $0821,y

EOR absolut Y-indiziert ($59, 3B, 4-5T, NZ)
Wie eben, nur mit dem Y-Register.

 

 ora $fb

ORA Zero-Page ($05, 2B, 3T, NZ)

 and $fb

AND Zero-Page ($25, 2B, 3T, NZ)

 eor $fb

EOR Zero-Page ($45, 2B, 3T, NZ)

 ora $fb,x

ORA Zero-Page X-indiziert ($15, 2B, 4T, NZ)

 and $fb,x

AND Zero-Page X-indiziert ($35, 2B, 4T, NZ)

 eor $fb,x

EOR Zero-Page X-indiziert ($55, 2B, 4T, NZ)

 ora ($fb,x)

ORA indirekt X-indiziert ($01, 2B, 6T, NZ)

 and ($fb,x)

AND indirekt X-indiziert ($21, 2B, 6T, NZ)

 eor ($fb,x)

EOR indirekt X-indiziert ($41, 2B, 6T, NZ)

 ora ($fb),y

ORA indirekt Y-nach-indiziert ($11, 2B, 5-6T, NZ)

 and ($fb),y

AND indirekt Y-nach-indiziert ($31, 2B, 5-6T, NZ)

 eor ($fb),y

EOR indirekt Y-nach-indiziert ($51, 2B, 5-6T, NZ)
Bei Überschreitung einer Page-Grenze wird wieder ein extra Takt benötigt.


Abschließend für alle, die immer noch über den fehlenden NOT-Befehl grübeln, hier ist die Lösung (in unser Programm aus Mit dem Rechner rechnen eingebettet):

CHROUT    = $ffd2        ;Jump-Table Adr.: Zeichenausgabe
SETCURSOR = $fff0        ;Jump-Table Adr.: get/set cursor pos
TEXTADR   = $fb          ;Zero-Page-Adr. für den Text
BINPOS    = $05          ;Spalte in der unsere Ausgabe beginnt
N1        = %10101010    ;erste Zahl / Maske
N2        = %11111111    ;zweite Zahl / Maske

;*** Startadresse BASIC-Zeile
*=$0801
 !byte $0b,$08,$e2,$07,$9e,$20,$32,$30,$36,$32,$00,$00, $00

;*** Start des Assemblerprogrammes
 cld                     ;D-Flag zur Sicherheit löschen
 jsr showmask            ;Hauptmaske anzeigen

 lda #$05                ;#$01 = Addition | #$02 = Subtraktion |
                         ;#$03 = AND | #$04 = ORA | #$05 = EOR

 jsr showoperator        ;Operant anzeigen 

;*** rechnen
 lda #N1                 ;1. Zahl in den Akku

 eor #N2                 ;Durch eine Maske mit lauter einsen, erreichen wir
                         ;beim eor dass, was sonst mit NOT geschieht:
                         ;1 wird 0 und 0 wird 1

 jsr result              ;Ergebnis ausgeben 

 rts                     ;zurück zum BASIC

 
;************************************************************
;*** Das Ergebnis ausgeben
;************************************************************
;*** Übergabe: A = Ergebnis der Operation
;************************************************************
;*** Rückgabe: -
;************************************************************
;*** ändert:   A,X,Y,SR
;************************************************************
result
 php                    ;Flags für Anzeige auf den Stack 
 ;*** Ergebnis im Akku ausgeben
 ldx #$0b
 ldy #BINPOS
 jsr binaryout

 ;*** Flags ausgeben
 pla
 ldx #$0b
 ldy #BINPOS+10
 jsr binaryout

 rts

 
;************************************************************
;*** Operator ausgeben
;************************************************************
;*** Übergabe: A = Nr. des Operanten
;************************************************************
;*** Rückgabe: -
;************************************************************
;*** ändert:   X,Y,SR und A (durch Unterprogramme)
;************************************************************
showoperator
 cmp #$01
 bne showoperatornext_1
 lda #<textadd
 sta TEXTADR
 lda #>textadd
 sta TEXTADR+1
 jmp showoperatortextout

showoperatornext_1
 cmp #$02
 bne showoperatornext_2
 lda #<textsub
 sta TEXTADR
 lda #>textsub
 sta TEXTADR+1
 jmp showoperatortextout

showoperatornext_2
 cmp #$03
 bne showoperatornext_3
 lda #<textand
 sta TEXTADR
 lda #>textand
 sta TEXTADR+1
 jmp showoperatortextout

showoperatornext_3
 cmp #$04
 bne showoperatornext_4
 lda #<textora
 sta TEXTADR
 lda #>textora
 sta TEXTADR+1
 jmp showoperatortextout

showoperatornext_4
 cmp #$05
 bne showoperatornext_5
 lda #<texteor
 sta TEXTADR
 lda #>texteor
 sta TEXTADR+1
 jmp showoperatortextout

showoperatornext_5
 rts

showoperatortextout 
 ldx #$09
 ldy #$01
 jsr textout

 rts

 
;************************************************************
;*** Unsere Maske ausgeben
;************************************************************
;*** Übergabe: -
;************************************************************
;*** Rückgabe: -
;************************************************************
;*** ändert:   A,X,Y,SR
;************************************************************
showmask
 ;BS löschen        
 lda #$93
 jsr CHROUT

 ;1. Zahl ausgeben
 lda #N1
 ldx #$08
 ldy #BINPOS
 jsr binaryout

 ;2. Zahl ausgeben
 lda #N2
 ldx #$09
 ldy #BINPOS
 jsr binaryout
 
 ;Überschrift für Flags
 lda #<textflags
 sta TEXTADR
 lda #>textflags
 sta TEXTADR+1

 ldx #$0a
 ldy #BINPOS+11
 jsr textout

 ;========= ausgeben 
 lda #<textline
 sta TEXTADR
 lda #>textline
 sta TEXTADR+1

 ldx #$0a
 ldy #BINPOS
 jsr textout

 rts

 
;************************************************************
;*** Beliebigen Text ausgeben (null-terminiert)
;************************************************************
;*** Übergabe: X = Zeile in der die Ausgabe beginnt
;***           Y = Spalte in der die Ausgabe beginnt
;***           TEXTADR = An dieser Zero-Page-Adresse wird die
;***                     Adresse des Textes erwartet.
;***           Das Textende wird durch $00 gekennzeichnet!
;************************************************************
;*** Rückgabe: -
;************************************************************
;*** ändert:   A,X,Y,SR
;************************************************************
textout
 clc                     ;C=0 für set / C=1 für get Cursor      
 jsr SETCURSOR           ;Jump-Table: get/set cursor
 ldy #$00                ;Pos. im Text

textcharin 
 lda (TEXTADR),Y         ;Aktuelles Zeichen in den Akku laden
 beq textdone            ;wenn 0 dann sind wir fertig
 jsr CHROUT              ;Jump-Table: Zeichenausgeben
 iny                     ;X erhöhen, für nächstes Zeichen
 jmp textcharin          ;und wieder hochspringen

textdone                 ;Ziel, sobald wir eine 0 haben
 rts                     ;zurück zum Aufrufer (jsr textout)

;*** unsere Texte
textadd
 !text "  +"
 !byte $00

textsub
 !text "  -"
 !byte $00

textand
 !text "AND"
 !byte $00

textora
 !text "ORA"
 !byte $00

texteor
 !text "EOR"
 !byte $00

textflags
 !text "NV-BDIZC"
 !byte $00

textline
 !text "========="
 !byte $00

 
;************************************************************
;*** Den Inhalt des Akkus als Binärzahl auf dem BS ausgeben
;************************************************************
;*** Übergabe: A = Zahl, die ausgegeben wird
;***           X = Zeile in der die Ausgabe beginnt
;***           Y = Spalte in der die Ausgabe beginnt
;************************************************************
;*** Rückgabe: -
;************************************************************
;*** ändert:   X,Y,SR
;************************************************************
binaryout
 pha                     ;Akku auf dem Stack merken (wg. SETCURSOR)
 clc                     ;C=0 für set / C=1 für get Cursor
 jsr SETCURSOR           ;Jump-Table: get/set cursor
 lda #"%"                ;Prozent-Zeichen in den Akku
 jsr CHROUT              ;und ausgeben
 pla                     ;Akku wieder vom Stack holen
 pha                     ;und direkt nochmal merken (für Rücksprung)

 ldy #$07                ;Schleife rückwärts von Bit 7-0

binoutloop
 ldx #"0"                ;Zeichen "0" ins X-Register
 asl                     ;Akku nach <-links verschieben
 bcc out                 ;Wenn es eine 0 ist, direkt zur Ausgabe,
 inx                     ;sonst erhöhen, damit wir eine 1 haben.
out                     ;Sprungziel, wenn wir eine 0 haben
 pha                     ;Akku merken, wird überschrieben (CHROUT)
 txa                     ;X -> Akku; Zeichen in den Akku
 jsr CHROUT              ;Jump-Table: Zeichenausgeben
 pla                     ;Akku fürs nächste Bit wiederholen
 dey                     ;Schleife runterzählen
 bpl binoutloop          ;bis 8-Bit verarbeitet sind -> binoutloop
 pla                     ;sonst, den Akku wiederherstellen

 rts                     ;und zurück zum Aufrufer (jsr binaryout)

 
;************************************************************
;*** Den Inhalt des Akkus als Hexzahl auf dem BS ausgeben
;************************************************************
;*** Übergabe: A = Zahl, die ausgegeben wird
;***           X = Zeile in der die Ausgabe beginnt
;***           Y = Spalte in der die Ausgabe beginnt
;************************************************************
;*** Rückgabe: -
;************************************************************
;*** ändert:   X,Y,SR
;************************************************************
hexout
 pha                     ;Akku auf dem Stack merken (wg. SETCURSOR)
 clc                     ;C=0 für set / C=1 für get Cursor
 jsr SETCURSOR           ;Jump-Table: get/set cursor
 lda #"$"                ;Dollar-Zeichen in den Akku
 jsr CHROUT              ;und ausgeben
 pla                     ;Akku wiederherstellen
 pha                     ;und merken bis zum Rücksprung
 pha                     ;gleich nochmal wg. LSR und CHROUT
 lsr                     ;jetzt msb -> ins lsb verschieben
 lsr                     ;dafür 4* LSR
 lsr
 lsr
 tax                     ;Akku ins X-Register,
 lda possiblehexchars,x  ;das Zeichen fürs obere Nibble holen
 jsr CHROUT              ;und auszugeben
 pla                     ;Akku vom Stack holen
 and #$0F                ;oberes Nibble ausmaskieren
 tax                     ;Akku wieder nach X
 lda possiblehexchars,x  ;das Zeichen fürs untere Nibble holen
 jsr CHROUT              ;und wieder ausgeben
 pla                     ;Ursprünglichen Akkuwert vom Stack holen

 rts                     ;und zurück zum Aufrufer (jsr hexout)

;*** die Hex-Ziffern
possiblehexchars
 !text "0123456789ABCDEF"

Beachtet beim Turbo Assembler wieder, die Besonderheiten, z. B. max. 15 Zeichen für die Label und keine Unterstriche!


Schrott!!Naja...Geht so...Ganz gut...SUPER! (9 Bewertungen | Ø 4,89 von 5 | 97,78%)

Loading...


ZurückWeiter

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Captcha
captcha
Reload

Protected by WP Anti Spam