division8.asm

Aus C64-Wiki
Zur Navigation springenZur Suche springen


 ;####################################################################
 ;# Programm:      8-Bit-Division
 ;# Dateiname:     division8.asm
 ;#
 ;# Assembler:     ACME
 ;# Assemblierung: acme -f cbm -o div8.prg division8.asm
 ;#
 ;# Laden mit:     LOAD"div8.prg",8,1
 ;#
 ;# Speicher:      Belegt den Bereich $c000 bis $c052
 ;#
 ;# Aufruf mit:    jsr $c000; die beiden zu dividierenden
 ;#                Werte müssen im X- und Y-Register stehen, der
 ;#                Quotient (x div y) wird im A-Register und der
 ;#                Rest (x mod y) im X-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 dividiert zwei 8-Bit-Werte Der
 ;#                Wertebereich ist auf 0 bis 255 beschränkt.
 ;#                Der Versuch, durch null zu teilen, 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 Divisions-Routine verwendet:
 ;#                
 ;#                  procedure devide;
 ;#                  var q, r, w ;
 ;#                  begin
 ;#                    r := x;
 ;#                    q := 0;
 ;#                    w := y;
 ;#                    while w <= r do
 ;#                      w := 2 * w;
 ;#                    while w > y do
 ;#                    begin
 ;#                      q := 2 * q;
 ;#                      w := w / 2;
 ;#                      if w <= r then
 ;#                      begin
 ;#                        r := r - w;
 ;#                        q := q + 1;
 ;#                      end
 ;#                    end ;
 ;#                    write (q, r);
 ;#                  end ;
 ;#                
 ;#                Der in dem genannten Buch enthaltene Compiler
 ;#                erzeugt aus der dieser Routine einen PCode,
 ;#                der als Vorlage für das nachfolgende Assembler-
 ;#                Programm diente.
 ;#                
 ;#                Die Variable w benötigt 9 Bits, daher gibt es
 ;#                bei den Speicherstellen hierfür einen low- und
 ;#                high-Wert. Das 9. Bit ist aber nur kurzzeitig
 ;#                in Verwendung, da in der zweiten Schleife w
 ;#                gleich wieder durch zwei geteilt wird. Daher
 ;#                können die Berechnungen alle in 8 Bit laufen.
 ;#                Nur bei Vergleichen muss das 9. Bit von w mit
 ;#                berücksichtigt werden.
 ;#                
 ;#                Das Assembler-Programm kontrolliert am Anfang
 ;#                noch, ob eine Division durch null versucht wird.
 ;#                
 ;####################################################################
 
 
 ; -- Startadresse --
 
   *=$c000
 
 
 ;####################################################################
 ;#
 ;# Speicherstellen
 ;#
 ;####################################################################
 
   !addr r = $69   ; Zeropage-Adressen des Accum#2
   !addr q = $6a
   !addr y = $6b
   !addr wlow =  $6c
   !addr whigh = $6d
 
 divmod8
   cpy #0
   bne +
   lda #$ff        ; Division mit null
   sec
   rts
 
 +
   stx r
   sty y
   sty wlow
   lda #0
   sta q
   sta whigh
 
   ; while w <= r do
 -
   lda whigh
   bne ++          ; Abbruchbedingung 1: w > 255
   lda wlow
   cmp r
   beq +           ; w = r (kein Abbruch)
   bcs ++          ; Abbruchbedingung 2: w > r
 +
   asl wlow        ; w = 2 * w
   rol whigh
   jmp -
 ++
   ; while w > y do
 -
   lda whigh
   bne +           ; w > 255 (kein Abbruch)
   lda wlow
   cmp y
   beq ++          ; Abbruchbedingung 1: w = y
   bcc ++          ; Abbruchbedingung 2: w < y
 +
   asl q           ; q = q * 2 (keine Fehlerkontrolle nötig)
   lsr whigh       ; w = w div 2
   ror wlow
 
   ; if w <= r then
 
   lda wlow
   cmp r
   beq +           ; w = r (ist gültig)
   bcs -           ; w > r; Nach diesem Block ist das Ende der
                   ; Schleife erreicht, so dass von hier aus auch
                   ; direkt zum Schleifenanfang gesprungen werden
                   ; kann.
 +
   sec
   lda r           ; r = r - w
   sbc wlow
   sta r
   inc q           ; q = q + 1
 
   jmp -
 
 ++
   lda q           ; Quotient (x div y) steht in A
   ldx r           ; Rest (x mod y) steht in X
   clc             ; kein Fehler aufgetreten
   rts