multiplikation8.asm

Aus C64-Wiki
Zur Navigation springenZur Suche springen


 ;####################################################################
 ;# Programm:      8-Bit-Multiplikation
 ;# Dateiname:     multiplikation8.asm
 ;#
 ;# Assembler:     ACME
 ;# Assemblierung: acme -f cbm -o mul8.prg multiplikation8.asm
 ;#
 ;# Laden mit:     LOAD"mul8.prg",8,1
 ;#
 ;# Speicher:      Belegt den Bereich $c000 bis $c032
 ;#
 ;# Aufruf mit:    jsr $c000; die beiden zu multiplizierenden
 ;#                Werte müssen im X- und Y-Register stehen, das
 ;#                Ergebnis wird im A-Register zurück geliefert.
 ;#                Ein gesetztes Carry-Flag signalisiert einen
 ;#                Fehler.
 ;#
 ;# Quelltext:     * Kleinschreibung (bis auf Kommentare)
 ;#                * nur Leerzeichen, keine Tabulatoren
 ;#                * Labels immer in eigener Zeile
 ;#                * Befehle zwei Zeichen eingerückt
 ;#                * Kommentare i.d.R. nach den Befehlen
 ;#
 ;# Beschreibung:  Die Routine multipliziert zwei 8-Bit-Werte
 ;#                miteinander. Der Wertebereich ist auf 0 bis 255
 ;#                beschränkt; wird er überschritten, löst dies einen
 ;#                Fehler aus.
 ;#                
 ;#                Zum Algorithmus:
 ;#                
 ;#                N. Wirth hat in seinem Buch "Compilerbau" als
 ;#                Beispiel für die dort verwendete Sprache "PL/0"
 ;#                (eine stark abgespeckte Variante von Pascal)
 ;#                eine Multiplikations-Routine verwendet:
 ;#                
 ;#                  procedure multiply;
 ;#                  var a, b;
 ;#                  begin
 ;#                    a := x;
 ;#                    b := y;
 ;#                    z := 0;
 ;#                    while b > 0 do
 ;#                    begin
 ;#                      if odd b then z := a + z;
 ;#                      a := a * 2;
 ;#                      b := b div 2
 ;#                    end
 ;#                  end;
 ;#                
 ;#                Der in dem genannten Buch enthaltene Compiler
 ;#                erzeugt aus der dieser Routine einen P-Code,
 ;#                der als Vorlage für das nachfolgende Assembler-
 ;#                Programm diente.
 ;#                
 ;#                Um sicher zu stellen, dass es bei einem Überlauf
 ;#                (Ergebnis ist oder wird größer als 255) nicht zu
 ;#                falschen Ergebnissen kommt, wird bei der Addition
 ;#                und der Multiplikation (shift left) eine Fehler-
 ;#                kontrolle über das Carry-Flag durchgeführt und die
 ;#                Berechnung bei zu großen Werten mit einem Fehler
 ;#                abgebrochen.
 ;#                
 ;####################################################################
 
 
 ; -- Startadresse --
 
   *=$c000
 
 
 ;####################################################################
 ;#
 ;# Speicherstellen
 ;#
 ;####################################################################
 
   !addr a = $69   ; Zeropage-Adressen des Accum#2
   !addr b = $6a
   !addr z = $6b
 
 
 ;####################################################################
 ;#
 ;# Hauptroutine
 ;#
 ;####################################################################
 
 ; -- mul8 --
 
 ; Die Werte im X- und Y-Register werden multipliziert
 ; und das Ergebnis in den Akku geschrieben;
 ; ein gesetztes Carry-Flag zeigt einen Fehler an
 ; (Ergebnis ist/wird größer als 255); in diesem Fall
 ; wird das Ergebnis auf 255 gesetzt.
 
 mul8
   stx a
   sty b
   lda #0
   sta z
 
   ; while b > 0 do
 -
   lda b
   beq +++  ; Abbruchbedingung b = 0
 
   ; if odd b then z := a + z
   lsr
   bcc ++   ; b ist gerade (Bit 0 nicht gesetzt)
   clc      ; a + z
   lda a
   adc z
   bcc +
   lda #$ff ; a + z ist größer 255
   sec
   rts
 +
   sta z    ; Ergebnis von a + z speichern
 
 ++
   ; Wenn b gleich 1 ist, ist dies der letzte Durchgang
   ; der Schleife. Daher wird hier die Schleife vorzeitig
   ; verlassen, damit die Multiplikation a * 2, deren
   ; Ergebnis dann ohnehin verworfen würde, keinen
   ; Fehler mehr auslösen kann (was passieren würde,
   ; wenn a in diesem Moment größer als 127 wäre).
   lda b
   cmp #1
   beq +++  ; Abbruchbedingung b = 1
 
   ; a := a * 2; b := b div 2
   asl a    ; a * 2
   bcc +
   lda #$ff ; a * 2 ist größer 255
   sec
   rts
 +
   lsr b    ; b div 2
 
   jmp -
 
 +++
   lda z    ; Ergebnis im Akku
   clc      ; kein Fehler aufgetreten
   rts