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