BIT $hhll

Aus C64-Wiki
Wechseln zu: Navigation, Suche
Begriffsklärung Der Titel dieses Artikels ist mehrdeutig. Bit (Begriffsklärung).


Mnemonic: BIT $hhll
Opcode: $2C
Operand(en): $ll $hh
Anzahl der Bytes: 3
Befehlsgruppe: Arithmetik- und Logikbefehl
Adressierung: absolut
Beeinflusste Flags im Statusregister:
Negative-Flag
Overflow-Flag
Zero-Flag
Taktzyklen: 4


Der Assembler-Befehl BIT $hhll macht eine bitweise UND-Verknüpfung mit dem Inhalt der Speicherzelle $hhll.
Das Ergebnis wird nicht wie bei dem Befehl AND $hhll in den Akkumulator geschrieben, sondern nur die Flaggen (Zero-Flag, Negativ-Flag und Overflow-Flag) beeinflusst.
Dieser Befehl ideal zum Abfragen einzelner Bits (siehe Beispiel 1) und im Vergleich zu einer Kombination aus LDA $hhll und AND #$nn hinsichtlich Speicherbedarf und Ausführungszeit effizienter, wenn auf das Eintreten eines Ereignisses in einer Warteschleife gewartet wird.
Eine weitere trickreiche Einsatzmöglichkeit des BIT-Befehls ist das Überspringen von Befehlen, indem zwei Byte lange Befehle als Parameter versteckt werden und dabei gewährleistet ist, dass dabei der BIT-Befehl sich neutral verhält, also sonst keine Register (abgesehen vom Statusregister) verändert, wie im Beispiel 2 gezeigt wird.

Der BIT-Befehl besteht aus 2 Teilen:

  1. Zunächst werden die Bits 7 und 6 der Speicherzelle $hhll ins Negativ-Flag und das Overflow-Flag übertragen,
  2. dann wird eine bitweise UND-Verknüpfung zwischen dem Akkumulator und dem Inhalt der Speicherzelle $hhll durchgeführt, wodurch nun das Zero-Flag beeinflusst wird, also gesetzt ist, wenn es das Ergebnis 0 ergab.

Es ist somit möglich, dass sich nach der Ausführung des Befehls alle drei genannten Flaggen verändert haben und sogar alle drei gesetzt sind. Im Gegensatz dazu kann beim Assemblerbefehl AND $hhll das Negative-Flag und das Zero-Flag niemals gleichzeitig gesetzt sein, da ein negatives Ergebnis nicht gleichzeitig 0 sein kann.

Funktionsprinzip

Ass befehl 2c.gif

Bedeutung der Buchstaben im Befehl

BIT BIT test
Teste Bits

Beispiele

Beispiel 1

Abfragen einzelner Bits:

; Diese Programm ist eine einfache Joystick-Abfrage des Controlports 2.
; Joystick auf/ab = Rahmenfarbe +/-
; Joystick links/rechts = Hintergrundfarbe +/-
; Feuerknopf = Ende
; Programmstart mit SYS 49152

*=$c000   ; Startadresse des Programms

start    lda $02
         cmp $dc00      ; Port auf CIA1, Port A
         beq start      ; bleibe solange in Schleife bis sich Joystick-Register ändert.

abfrage  lda $dc00      ; neuen Wert in Speicherzelle 2 zwischenspeichern.
         sta $02		

         lda #%00000001 ; Joystick-Bewegung "auf" maskieren 
         bit $dc00      ; bitweise UND-Verknüpfung der Adresse 56320, aktiv wenn Bit = 0
         bne weiter1    ; wenn Bewegung nicht nach oben --> keine Erhöhung der Rahmenfarbe 
         inc $d020      ; Rahmenfarbe + 1

weiter1  lda #%00000010 ; Joystick-Bewegung "ab" maskieren 
         bit $dc00      ; bitweise UND-Verknüpfung der Adresse 56320, aktiv wenn Bit = 0
         bne weiter2    ; wenn Bewegung nicht nach unten --> keine Verminderung der Rahmenfarbe 
         dec $d020      ; Rahmenfarbe - 1

weiter2  lda #%00000100 ; Joystick-Bewegung "links" maskieren 
         bit $dc00      ; bitweise UND-Verknüpfung der Adresse 56320, aktiv wenn Bit = 0
         bne weiter3    ; wenn Bewegung nicht nach links --> keine Erhöhung der Hintergrundfarbe 
         inc $d021      ; Hintergrundfarbe + 1

weiter3  lda #%00001000 ; Joystick-Bewegung "rechts" maskieren  
         bit $dc00      ; bitweise UND-Verknüpfung der Adresse 56320, aktiv wenn Bit = 0
         bne weiter4    ; wenn Bewegung nicht nach rechts --> keine Verminderung der Hintergrundfarbe
         dec $d021      ; Hintergrundfarbe - 1

weiter4  lda #%00010000 ; Feuerknopf-Bit maskieren 
         bit $dc00      ; bitweise UND-Verknüpfung der Adresse 56320, aktiv wenn Bit = 0
         bne start      ; wenn Feuerknopf nicht gedrückt --> verzweige zum Start 
         rts            ; Rücksprung ins BASIC

Speicherauszug:

.c000	 a5 02		lda $02		
.c002	 cd 00 dc	cmp $dc00
.c005	 f0 f9		beq $c000
.c007	 ad 00 dc	lda $dc00
.c00a	 85 02		sta $02		
.c00c	 a9 01		lda #$01	
.c00e	 2c 00 dc	bit $dc00
.c011	 d0 03		bne $c016
.c013	 ee 20 d0	inc $d020
.c016	 a9 02		lda #$02	
.c018	 2c 00 dc	bit $dc00
.c01b	 d0 03		bne $c020
.c01d	 ce 20 d0	dec $d020
.c020	 a9 04		lda #$04	
.c022	 2c 00 dc	bit $dc00
.c025	 d0 03		bne $c02a
.c027	 ee 21 d0	inc $d021
.c02a	 a9 08		lda #$08	
.c02c	 2c 00 dc	bit $dc00
.c02f	 d0 03		bne $c034
.c031	 ce 21 d0	dec $d021
.c034	 a9 10		lda #$10	
.c036	 2c 00 dc	bit $dc00
.c039	 d0 c5		bne $c000
.c03b	 60		rts

Vergleich des 1. Beispielprogramms mit BASIC:

100 IF A=PEEK(56320) THEN 100
110 A=PEEK(56320)

200 IF (A AND 1) <> 0 THEN 300
210 POKE 53280, (PEEK(53280)+1) AND 255

300 IF (A AND 2) <> 0 THEN 400
310 POKE 53280, (PEEK(53280)-1) AND 255

400 IF (A AND 4) <> 0 THEN 500
410 POKE 53281, (PEEK(53281)+1) AND 255

500 IF (A AND 8) <> 0 THEN 600
510 POKE 53281, (PEEK(53281)-1) AND 255

600 IF (A AND 16) <> 0 THEN 100

Beispiel 2

Zweckentfremdung von BIT: Platzsparendes Überspringen von nachfolgenden Befehlen mit zwei Byte Länge. Hierbei wird die eigentliche Funktionalität des Befehls gar nicht genutzt, vielmehr wird er als eine Art Drei-Byte-NOP benutzt. Prinzipiell lässt sich hierfür auch z.B. der illegale Opcode $0c benutzen (der in der Tat ein NOP $hhll ist und anders als BIT $hhll keine Nebeneffekte auf Flaggen hat). In der Praxis findet sich jedoch meist BIT, nicht zuletzt, um die Portabilität zu anderen 6502-CPU-Varianten (z.B. 65C02 oder 65C816) zu gewährleisten, die die illegalen Opcodes nicht kennen.

; Dieses Programm zeigt das Überspringen von Befehlen mit Hilfe des BIT-Befehls.
; Statt der $2Cs ließe sich auch z.B. ein JMP Out oder BNE Out einfügen, beides braucht jedoch mehr Platz.
; Nach dem Start mit SYS 49152 wird der Bildschirm gelöscht und die Zeichenfolge !***! ausgegeben.

*=$c000   ; Startadresse des Programms

BSOUT = $ffd2

start        jsr Clrscr        ; Bildschirm löschen
             jsr Rufzeichen    ; ! ausgeben
             jsr Stern         ; * ausgeben
             jsr Stern         ; * ausgeben
             jsr Stern         ; * ausgeben
             jsr Rufzeichen    ; ! ausgeben                            
             rts               ; Rücksprung ins BASIC

; ----- Unterprogramm -----

Stern        lda #'*'          ; Stern ausgeben        (Befehlsfolge: lda #'*'  bit $21a9  bit $93a9  jsr $ffd2  rts)
             .byte $2c         ; Opcode für BIT $hhll
             
Rufzeichen   lda #'!'          ; Rufzeichen ausgeben   (Befehlsfolge: lda #'!'  bit $93a9  jsr $ffd2  rts)
             .byte $2c         ; Opcode für BIT $hhll
             
Clrscr       lda #147          ; Bildschirm löschen
                             
Out          jsr BSOUT         ; Zeichen am Bildschirm ausgeben       
             rts               ; Rücksprung

Speicherauszug:

.c000 20 19 c0  jsr $c019
.c003 20 16 c0  jsr $c016
.c006 20 13 c0  jsr $c013
.c009 20 13 c0  jsr $c013
.c00c 20 13 c0  jsr $c013
.c00f 20 16 c0  jsr $c016
.c012 60        rts

.c013 a9 2a     lda #$2a
>c015 2c        .byte $2c
.c016 a9 21     lda #$21
>c018 2c        .byte $2c
.c019 a9 93     lda #$93
.c01b 20 d2 ff  jsr $ffd2
.c01e 60        rts

Aus CPU-Sicht werden die folgenden Befehle ausgeführt:

; ...nach einem jsr $c013:
.c013 a9 2a      lda #$2a
.c015 2c a9 21   bit $21a9   ; BIT "verdeckt" a9 21 = lda #$21
.c018 2c a9 93   bit $93a9   ; BIT "verdeckt" a9 93 = lda #$93
.c01b 20 d2 ff   jsr $ffd2
.c01e 60         rts

; ...nach einem jsr $c016:
.c016 a9 21      lda #$21
.c018 2c a9 93   bit $93a9   ; BIT "verdeckt" a9 93 = lda #$93
.c01b 20 d2 ff   jsr $ffd2
.c01e 60         rts

Links