# Externe Routinen zu ARILEV1.D
# Compiler: TURBO-C
# Parameter-Übergabe: in Registern A0-A1,D0-D2, Rest auf dem Stack.
# Einstellungen: intCsize=16, intDsize=16.

#ifdef INCLUDED_FROM_C

  #define COPY_LOOPS
  #define FILL_LOOPS
  #define CLEAR_LOOPS
  #define LOG_LOOPS
  #define TEST_LOOPS
  #define ADDSUB_LOOPS
  #define SHIFT_LOOPS
  #define MUL_LOOPS
  #define DIV_LOOPS

#else

           .text

           .xdef mulu32_
           .xdef copy_loop_up,copy_loop_down,fill_loop_up,fill_loop_down
           .xdef clear_loop_up,clear_loop_down
           .xdef or_loop_up,xor_loop_up,and_loop_up,eqv_loop_up
           .xdef nand_loop_up,nor_loop_up,andc2_loop_up,orc2_loop_up
           .xdef not_loop_up
           .xdef and_test_loop_up,test_loop_up,compare_loop_up
           .xdef add_loop_down,addto_loop_down,inc_loop_down
           .xdef sub_loop_down,subx_loop_down,subfrom_loop_down,dec_loop_down
           .xdef neg_loop_down
           .xdef shift1left_loop_down,shiftleft_loop_down,shiftleftcopy_loop_down
           .xdef shift1right_loop_up,shiftright_loop_up,shiftrightsigned_loop_up,shiftrightcopy_loop_up
           .xdef mulusmall_loop_down,mulu_loop_down,muluadd_loop_down,mulusub_loop_down
           .xdef divu_loop_up,divucopy_loop_up

; extern struct { uint32 lo; uint32 hi; } mulu32_ (uint32 arg1, uint32 arg2);
; 2^32*hi+lo := arg1*arg2.
mulu32_:   ; Input in D0,D1, Output in D0,mulu32_high
           MOVE.L D3,A0
           MOVE.L D4,A1
           ; D0.L = 2^16*a+b, D1.L = 2^16*c+d -> Produkt
           ; (2^16*a+b)*(2^16*c+d) = 2^32*a*c + 2^16*(a*d+b*c) + b*d
           MOVE.L D0,D2
           SWAP D2      ; D2.W = a
           MOVE.L D1,D3
           SWAP D1      ; D1.W = c
           MOVE.L D1,D4
           MULU D2,D1   ; D1.L = a*c
           MULU D3,D2   ; D2.L = a*d
           MULU D0,D4   ; D4.L = b*c
           MULU D3,D0   ; D0.L = b*d
           CLR.L D3     ; Hilfsregister für Zero-Extend
           SWAP D2
           MOVE.W D2,D3
           ADD.L D3,D1  ; high16(a*d) zu D1.L addieren
           SWAP D4
           MOVE.W D4,D3
           ADD.L D3,D1  ; high16(b*c) zu D1.L addieren
           CLR.W D2
           ADD.L D2,D0  ; 2^16*low16(a*d) zu D0.L addieren
           BCC.S \1
           ADDQ.L #1,D1
    \1:    CLR.W D4
           ADD.L D4,D0  ; 2^16*low16(b*c) zu D0.L addieren
           BCC.S \2
           ADDQ.L #1,D1
    \2:    ; D0.L = lo, D1.L = hi fertig.
           MOVE.L D1,(mulu32_high) ; Adressierung?? Deklaration??
           MOVE.L A1,D4
           MOVE.L A0,D3
           RTS

; extern uintD* copy_loop_up (uintD* sourceptr, uintD* destptr, uintC count);
copy_loop_up: ; Input in A0,A1,D0.W, Output in A0
           BRA.S \2
    \1:      MOVE.W (A0)+,(A1)+
    \2:      DBF D0,\1
           MOVE.L A1,A0
           RTS

; extern uintD* copy_loop_down (uintD* sourceptr, uintD* destptr, uintC count);
copy_loop_down: ; Input in A0,A1,D0.W, Output in A0
           BRA.S \2
    \1:      MOVE.W -(A0),-(A1)
    \2:      DBF D0,\1
           MOVE.L A1,A0
           RTS

; extern uintD* fill_loop_up (uintD* destptr, uintC count, uintD filler);
fill_loop_up: ; Input in A0,D0.W,D1.W, Output in A0
           BRA.S \2
    \1:      MOVE.W D1,(A0)+
    \2:      DBF D0,\1
           RTS

; extern uintD* fill_loop_down (uintD* destptr, uintC count, uintD filler);
fill_loop_down: ; Input in A0,D0.W,D1.W, Output in A0
           BRA.S \2
    \1:      MOVE.W D1,-(A0)
    \2:      DBF D0,\1
           RTS

; extern uintD* clear_loop_up (uintD* destptr, uintC count);
clear_loop_up: ; Input in A0,D0.W, Output in A0
           BRA.S \2
    \1:      CLR.W (A0)+
    \2:      DBF D0,\1
           RTS

; extern uintD* clear_loop_down (uintD* destptr, uintC count);
clear_loop_down: ; Input in A0,D0.W, Output in A0
           BRA.S \2
    \1:      CLR.W -(A0)
    \2:      DBF D0,\1
           RTS

; extern void or_loop_up (uintD* xptr, uintD* yptr, uintC count);
or_loop_up: ; Input in A0,A1,D0.W, verändert D1
           BRA.S \2
    \1:      MOVE.W (A1)+,D1
             OR.W D1,(A0)+
    \2:      DBF D0,\1
           RTS

; extern void xor_loop_up (uintD* xptr, uintD* yptr, uintC count);
xor_loop_up: ; Input in A0,A1,D0.W, verändert D1
           BRA.S \2
    \1:      MOVE.W (A1)+,D1
             EOR.W D1,(A0)+
    \2:      DBF D0,\1
           RTS

; extern void and_loop_up (uintD* xptr, uintD* yptr, uintC count);
and_loop_up: ; Input in A0,A1,D0.W, verändert D1
           BRA.S \2
    \1:      MOVE.W (A1)+,D1
             AND.W D1,(A0)+
    \2:      DBF D0,\1
           RTS

; extern void eqv_loop_up (uintD* xptr, uintD* yptr, uintC count);
eqv_loop_up: ; Input in A0,A1,D0.W, verändert D1
           BRA.S \2
    \1:      MOVE.W (A1)+,D1
             EOR.W D1,(A0)
             NOT.W (A0)+
    \2:      DBF D0,\1
           RTS

; extern void nand_loop_up (uintD* xptr, uintD* yptr, uintC count);
nand_loop_up: ; Input in A0,A1,D0.W, verändert D1
           BRA.S \2
    \1:      MOVE.W (A1)+,D1
             AND.W D1,(A0)
             NOT.W (A0)+
    \2:      DBF D0,\1
           RTS

; extern void nor_loop_up (uintD* xptr, uintD* yptr, uintC count);
nor_loop_up: ; Input in A0,A1,D0.W, verändert D1
           BRA.S \2
    \1:      MOVE.W (A1)+,D1
             OR.W D1,(A0)
             NOT.W (A0)+
    \2:      DBF D0,\1
           RTS

; extern void andc2_loop_up (uintD* xptr, uintD* yptr, uintC count);
andc2_loop_up: ; Input in A0,A1,D0.W, verändert D1
           BRA.S \2
    \1:      MOVE.W (A1)+,D1
             NOT.W D1
             AND.W D1,(A0)+
    \2:      DBF D0,\1
           RTS

; extern void orc2_loop_up (uintD* xptr, uintD* yptr, uintC count);
orc2_loop_up: ; Input in A0,A1,D0.W, verändert D1
           BRA.S \2
    \1:      MOVE.W (A1)+,D1
             NOT.W D1
             OR.W D1,(A0)+
    \2:      DBF D0,\1
           RTS

; extern void not_loop_up (uintD* xptr, uintC count);
not_loop_up: ; Input in A0,D0.W
           BRA.S \2
    \1:      NOT.W (A0)+
    \2:      DBF D0,\1
           RTS

; extern boolean and_test_loop_up (uintD* xptr, uintD* yptr, uintC count);
and_test_loop_up: ; Input in A0,A1,D0.W, verändert D1, Output in D0.W=D0.L
           BRA.S \2
    \1:      MOVE.W (A0)+,D1
             AND.W (A1)+,D1
             BNE.S \3
    \2:      DBF D0,\1
           CLR.L D0
           RTS
    \3:    MOVEQ.L #1,D0
           RTS

; extern boolean test_loop_up (uintD* ptr, uintC count);
test_loop_up: ; Input in A0,D0.W, Output in D0.W=D0.L
           BRA.S \2
    \1:      TST.W (A0)+
             BNE.S \3
    \2:      DBF D0,\1
           CLR.L D0
           RTS
    \3:    MOVEQ.L #1,D0
           RTS

; extern signean compare_loop_up (uintD* xptr, uintD* yptr, uintC count);
compare_loop_up: ; Input in A0,A1,D0.W, Output in D0.W=D0.L
           BRA.S \2
    \1:      CMPM.W (A1)+,(A0)+
             BNE.S \3
    \2:      DBF D0,\1
           CLR.L D0
           RTS
    \3:    BLO.S \4
           MOVEQ.L #1,D0
           RTS
    \4:    MOVEQ.L #-1,D0
           RTS

; extern uintD add_loop_down (uintD* sourceptr1, uintD* sourceptr2, uintD* destptr, uintC count);
add_loop_down: ; Input in A0,A1,A2,D0.W, verändert D1,D2, Output in D0.W
           MOVE.L A2,-(SP)
           ANDI #%01110,CCR   ; X-Bit löschen
           BRA.S \2
    \1:      MOVE.W -(A0),D1
             MOVE.W -(A1),D2
             ADDX.W D2,D1
             MOVE.W D1,-(A2)
    \2:      DBF D0,\1
           SUBX.W D0,D0       ; -1 falls X gesetzt, 0 falls X gelöscht
           MOVE.L (SP)+,A2
           RTS

; extern uintD addto_loop_down (uintD* sourceptr, uintD* destptr, uintC count);
addto_loop_down: ; Input in A0,A1,D0.W, Output in D0.W
           ANDI #%01110,CCR   ; X-Bit löschen
           BRA.S \2
    \1:      ADDX.W -(A0),-(A1)
    \2:      DBF D0,\1
           SUBX.W D0,D0       ; -1 falls X gesetzt, 0 falls X gelöscht
           RTS

; extern uintD inc_loop_down (uintD* ptr, uintC count);
inc_loop_down: ; Input in A0,D0.W, Output in D0.W
           DBF D0,\1          ; simuliere gesetzten Carry
                              ; D0.W=-1 für Übertrag
           RTS
    \1:      ADDQ.W #1,-(A0)
             DBCC D0,\1       ; kein Carry -> Schleife abbrechen
           SUBX.W D0,D0       ; kein Carry -> D0.W=0, sonst D0.W=-1 für Übertrag
           RTS

; extern uintD sub_loop_down (uintD* sourceptr1, uintD* sourceptr2, uintD* destptr, uintC count);
sub_loop_down: ; Input in A0,A1,A2,D0.W, verändert D1,D2, Output in D0.W
           MOVE.L A2,-(SP)
           ANDI #%01110,CCR   ; X-Bit löschen
           BRA.S \2
    \1:      MOVE.W -(A0),D1
             MOVE.W -(A1),D2
             SUBX.W D2,D1
             MOVE.W D1,-(A2)
    \2:      DBF D0,\1
           SUBX.W D0,D0       ; -1 falls X gesetzt, 0 falls X gelöscht
           MOVE.L (SP)+,A2
           RTS

; extern uintD subx_loop_down (uintD* sourceptr1, uintD* sourceptr2, uintD* destptr, uintC count, uintD carry);
subx_loop_down: ; Input in A0,A1,A2,D0.W,D1.W, verändert D2, Output in D0.W
           MOVE.L A2,-(SP)
           ROXR.W #1,D1       ; X-Bit initialisieren
           BRA.S \2
    \1:      MOVE.W -(A0),D1
             MOVE.W -(A1),D2
             SUBX.W D2,D1
             MOVE.W D1,-(A2)
    \2:      DBF D0,\1
           SUBX.W D0,D0       ; -1 falls X gesetzt, 0 falls X gelöscht
           MOVE.L (SP)+,A2
           RTS

; extern uintD subfrom_loop_down (uintD* sourceptr, uintD* destptr, uintC count);
subfrom_loop_down: ; Input in A0,A1,D0.W, Output in D0.W
           ANDI #%01110,CCR   ; X-Bit löschen
           BRA.S \2
    \1:      SUBX.W -(A0),-(A1)
    \2:      DBF D0,\1
           SUBX.W D0,D0       ; -1 falls X gesetzt, 0 falls X gelöscht
           RTS

; extern uintD dec_loop_down (uintD* ptr, uintC count);
dec_loop_down: ; Input in A0,D0.W, Output in D0.W
           DBF D0,\1          ; simuliere gesetzten Carry
                              ; D0.W=-1 als Übertrag
           RTS
    \1:      SUBQ.W #1,-(A0)
             DBCC D0,\1       ; kein Carry -> Schleife abbrechen
           SUBX.W D0,D0       ; kein Carry -> D0.W=0, sonst D0.W=-1 als Übertrag
           RTS

; extern uintD neg_loop_down (uintD* ptr, uintC count);
neg_loop_down: ; Input in A0,D0.W, Output in D0.W
           ANDI #%01110,CCR   ; X-Bit löschen
           BRA.S \2
    \1:      NEGX.W -(A0)
    \2:      DBF D0,\1
           SUBX.W D0,D0       ; -1 falls X gesetzt, 0 falls X gelöscht
           RTS

; extern uintD shift1left_loop_down (uintD* ptr, uintC count);
shift1left_loop_down: ; Input in A0,D0.W, Output in D0.W
           ANDI #%01110,CCR   ; X-Bit löschen
           BRA.S \2
    \1:      ROXL.W -(A0)     ; Digit -(A0) um 1 Bit links schieben, X-Bit als Buffer
    \2:      DBF D0,\1
           SUBX.W D0,D0       ; -1 falls X gesetzt, 0 falls X gelöscht
           RTS

; extern uintD shiftleft_loop_down (uintD* ptr, uintC count, uintC i, uintD carry);
shiftleft_loop_down: ; Input in A0,D0.W,D1.W,D2.W, Output in D0.W
           MOVE.L D3,-(SP)
           ; A0 = ptr, D0.W = count, D1.W = i,
           ; D2.W = Schiebe-Übertrag (i Bits), D3.L = Schiebe-Akku
           BRA.S \2
    \1:      CLR.L D3
             MOVE.W -(A0),D3  ; D3.L = D3.W = neues Digit
             LSL.L D1,D3      ; um i Bits nach links schieben
             OR.W D2,D3       ; D3 enthält die letzten 16+i Bits
             MOVE.W D3,(A0)   ; 16 Bits ablegen
             SWAP D3
             MOVE.W D3,D2     ; neuen Übertrag bilden
    \2:      DBF D0,\1        ; Schleife D0.W mal durchlaufen
           MOVE.W D2,D0
           MOVE.L (SP)+,D3
           RTS

; extern uintD shiftleftcopy_loop_down (uintD* sourceptr, uintD* destptr, uintC count, uintC i);
shiftleftcopy_loop_down: ; Input in A0,A1,D0.W,D1.W, Output in D0.W
           MOVE.L D3,-(SP)
           CLR.W D2
           ; A0 = sourceptr, A1 = destptr, D0.W = count, D1.W = i,
           ; D2.W = Schiebe-Übertrag (i Bits), D3.L = Schiebe-Akku
           BRA.S \2
    \1:      CLR.L D3
             MOVE.W -(A0),D3  ; D3.L = D3.W = neues Digit
             LSL.L D1,D3      ; um i Bits nach links schieben
             OR.W D2,D3       ; D3 enthält die letzten 16+i Bits
             MOVE.W D3,-(A1)  ; 16 Bits ablegen
             SWAP D3
             MOVE.W D3,D2     ; neuen Übertrag bilden
    \2:      DBF D0,\1        ; Schleife D0.W mal durchlaufen
           MOVE.W D2,D0
           MOVE.L (SP)+,D3
           RTS

; extern uintD shift1right_loop_up (uintD* ptr, uintC count, uintD carry);
shift1right_loop_up: ; Input in A0,D0.W,D1.W, Output in D0.W
           ROXR.W #1,D1       ; X-Bit löschen oder setzen, je nach D1.W
           BRA.S \2
    \1:      ROXR.W (A0)+     ; Digit (A0)+ um 1 Bit rechts schieben, X-Bit als Buffer
    \2:      DBF D0,\1
           SUBX.W D0,D0       ; -1 falls X gesetzt, 0 falls X gelöscht
           RTS

; extern uintD shiftright_loop_up (uintD* ptr, uintC count, uintC i);
shiftright_loop_up: ; Input in A0,D0.W,D1.W, Output in D0.W
           MOVE.L D3,-(SP)
           ; A0 = ptr, D0.W = count, D1.W = i,
           ; D2.L = Schiebe-Übertrag (i Bits), D3.L = Schiebe-Akku
           CLR.L D2           ; Übertrag = 0
           BRA.S \2
    \1:      ; A0 = Aufwärtszähler Adresse, D0.W = Herabzähler, D1.W = i,
             ; D2.L = Schiebe-Übertrag (obere i Bits, restliche 32-i Bits sind 0)
             ; D3.L = Schiebe-Akku
             CLR.L D3
             MOVE.W (A0),D3   ; neue Daten
             SWAP D3          ; nach Bit 31..16(D3), D3.W = 0
             LSR.L D1,D3      ; Bits 31-i..16-i(D3) sind die neuen Daten
             OR.L D3,D2       ; Bits 31..16-i(D3) sind die bisherigen Daten
             SWAP D2          ; untere 16 Bit ergeben neuen Übertrag,
             MOVE.W D2,(A0)+  ; obere 16 Bit werden abgespeichert
             CLR.W D2         ; D2.L = neuer Übertrag
    \2:      DBF D0,\1        ; Schleife D0.W mal durchlaufen
           SWAP D2
           MOVE.W D2,D0
           MOVE.L (SP)+,D3
           RTS

; extern uintD shiftrightsigned_loop_up (uintD* ptr, uintC count, uintC i);
shiftrightsigned_loop_up: ; Input in A0,D0.W,D1.W, Output in D0.W
           MOVE.L D3,-(SP)
           ; A0 = ptr, D0.W = count, D1.W = i,
           ; D2.L = Schiebe-Übertrag (i Bits), D3.L = Schiebe-Akku
           MOVE.W (A0),D2     ; erstes Digit
           EXT.L D2           ; Vorzeichenbit nach Bit 31..16(D2)
           CLR.W D2           ; Rest von D2.L löschen
           LSR.L D1,D2        ; D2.W enthält in seinen oberen i Bits das Vorzeichen
           SWAP D2            ; Übertrag mit i Vorzeichenbits initialisiert
           BRA.S \2
    \1:      ; A0 = Aufwärtszähler Adresse, D0.W = Herabzähler, D1.W = i,
             ; D2.L = Schiebe-Übertrag (obere i Bits, restliche 32-i Bits sind 0)
             ; D3.L = Schiebe-Akku
             CLR.L D3
             MOVE.W (A0),D3   ; neue Daten
             SWAP D3          ; nach Bit 31..16(D3), D3.W = 0
             LSR.L D1,D3      ; Bits 31-i..16-i(D3) sind die neuen Daten
             OR.L D3,D2       ; Bits 31..16-i(D3) sind die bisherigen Daten
             SWAP D2          ; untere 16 Bit ergeben neuen Übertrag,
             MOVE.W D2,(A0)+  ; obere 16 Bit werden abgespeichert
    \2:      CLR.W D2         ; D2.L = neuer Übertrag
             DBF D0,\1        ; Schleife D0.W mal durchlaufen
           SWAP D2
           MOVE.W D2,D0
           MOVE.L (SP)+,D3
           RTS

; extern uintD shiftrightcopy_loop_up (uintD* sourceptr, uintD* destptr, uintC count, uintC i, uintD carry);
shiftrightcopy_loop_up: ; Input in A0,A1,D0.W,D1.W,D2.W, Output in D0.W
           MOVE.L D3,-(SP)
           ; A0 = ptr, D0.W = count, D1.W = i,
           ; D2.L = Schiebe-Übertrag (i Bits), D3.L = Schiebe-Akku
           SWAP D2            ; carry nach D2.HW
           CLR.W D2           ; Rest von D2.L löschen
           LSR.L D1,D2        ; D2.W enthält in seinen oberen i Bits das Vorzeichen
           SWAP D2            ; Übertrag mit i Vorzeichenbits initialisiert
           BRA.S \2
    \1:      ; A0,A1 = Aufwärtszähler Adresse, D0.W = Herabzähler, D1.W = i,
             ; D2.L = Schiebe-Übertrag (obere i Bits, restliche 32-i Bits sind 0)
             ; D3.L = Schiebe-Akku
             CLR.L D3
             MOVE.W (A0)+,D3  ; neue Daten
             SWAP D3          ; nach Bit 31..16(D3), D3.W = 0
             LSR.L D1,D3      ; Bits 31-i..16-i(D3) sind die neuen Daten
             OR.L D3,D2       ; Bits 31..16-i(D3) sind die bisherigen Daten
             SWAP D2          ; untere 16 Bit ergeben neuen Übertrag,
             MOVE.W D2,(A1)+  ; obere 16 Bit werden abgespeichert
    \2:      CLR.W D2         ; D2.L = neuer Übertrag
             DBF D0,\1        ; Schleife D0.W mal durchlaufen
           SWAP D2
           MOVE.W D2,D0
           MOVE.L (SP)+,D3
           RTS

; extern uintD mulusmall_loop_down (uintD digit, uintD* ptr, uintC len, uintD newdigit);
mulusmall_loop_down: # Input in D0.W,A0,D1.W,D2.W, Output in D0.W
           MOVE.L D3,-(SP)
           EXT.L D2           ; carry
           BRA.S \2
    \1:      MOVE.W -(A0),D3  ; nächstes Digit
             MULU D0,D3       ; mit digit multiplizieren
             ADD.L D3,D2      ; und zum bisherigen Carry addieren. Kein Überlauf!
             MOVE.W D2,(A0)   ; Low-Digit ablegen
             CLR.W D2
             SWAP D2          ; High-Digit gibt neuen Carry
    \2:      DBF D1,\1
           MOVE.W D2,D0       ; letzter Carry
           MOVE.L (SP)+,D3
           RTS

; extern void mulu_loop_down (uintD digit, uintD* sourceptr, uintD* destptr, uintC len);
mulu_loop_down: ; Input in D0.W,A0,A1,D1.W
           MOVE.L D3,-(SP)
           CLR.L D2           ; carry
           BRA.S \2
    \1:      MOVE.W -(A0),D3  ; nächstes Digit
             MULU D0,D3       ; mit digit multiplizieren
             ADD.L D3,D2      ; und zum bisherigen Carry addieren
             MOVE.W D2,-(A1)  ; Low-Digit ablegen
             CLR.W D2
             SWAP D2          ; High-Digit gibt neuen Carry
    \2:      DBF D1,\1
           MOVE.W D2,-(A1)    ; letzten Carry ablegen
           MOVE.L (SP)+,D3
           RTS

; extern uintD muluadd_loop_down (uintD digit, uintD* sourceptr, uintD* destptr, uintC len);
muluadd_loop_down: ; Input in D0.W,A0,A1,D1.W, benutzt D2,D3,D4, Output in D0.W
#if 1
           MOVE.L D3,-(SP)
           SUB.L D2,D2        ; carry := 0, X-Bit löschen, D2.HW stets =0
           BRA.S \2
    \1:      MOVE.W -(A0),D3  ; nächstes Digit
             MULU D0,D3       ; mit digit multiplizieren
             ADDX.L D2,D3     ; und bisherigen Carry und X-Bit addieren
             ADD.W D3,-(A1)   ; Low-Digit zum dest-Digit addieren, X als Übertrag
             SWAP D3
             MOVE.W D3,D2     ; High-Digit gibt neuen Carry
    \2:      DBF D1,\1
           MOVE.W D2,D0       ; letzten Carry und
           SWAP D2            ; 0.W und
           ADDX.W D2,D0       ; letztes X-Bit addieren
           MOVE.L (SP)+,D3
           RTS
#else
           MOVEM.L D3-D4,-(SP)
           CLR.L D2           ; carry
           CLR.L D4           ; D4.HW stets =0
           BRA.S \2
    \1:      MOVE.W -(A0),D3  ; nächstes Digit
             MULU D0,D3       ; mit digit multiplizieren
             ADD.L D3,D2      ; und zum bisherigen Carry addieren
             MOVE.W -(A1),D4  ; nächstes dest-Digit
             ADD.L D4,D2      ; dazuaddieren
             MOVE.W D2,(A1)   ; Low-Digit ablegen
             CLR.W D2
             SWAP D2          ; High-Digit gibt neuen Carry
    \2:      DBF D1,\1
           MOVE.W D2,D0       ; letzten Carry als Ergebnis
           MOVEM.L (SP)+,D3-D4
           RTS
#endif

#if 0
; extern void mulu_2loop_down (uintD* sourceptr1, uintC len1,
;                              uintD* sourceptr2, uintC len2,
;                              uintD* destptr, uintC len);
mulu2_loop_down: ; Input in A0,D0.W,A1,D1.W,4(SP),D2.W
           MOVEM.L A2-A5/D3-D5,-(SP)
           MOVE.L 32(SP),A2
           ; A0 = sourceptr1, D0.W = len1,
           ; A1 = sourceptr2, D1.W = len2,
           ; A2 = destptr, D2.W = len
           CMP.W D0,D1
           BHS.S \0
           EXG D1,D0
           EXG A1,A0
    \0:    ; jetzt ist len1<=len2
           ; erst D2.W+2 Nulldigits ablegen:
           MOVE.L A2,A3
           MOVE.W D2,D3
           BRA.S \2
    \1:      CLR.W -(A3)
    \2:      DBF D3,\1
           CLR.L -(A3)
           ; A3+4/D2.W/A2 ist die Ergebnis-UDS
           ; Unsigned multiplizieren:
           ; Überträge werden sofort nach dem Erzeugen im Speicher
           ; durchgeschoben. (Das geschieht recht selten - im Durchschnitt nur
           ; jedes vierte Mal - und dauert nicht lang,
           ; beschleunigt aber den inneren Schleifenkern enorm.)
           ; Unverändert bleibt A1 in source2.
           ; Äußere Schleife zählt mit D0.W, A0 in source1, A2 in dest.
           ; Innere Schleife zählt mit D3.W, A3 in source2, A4 in dest.
           ; Ganz innere Schleife zählt mit A5 in dest.
           ; D4, D5 temporäre Daten.
           BRA.S \7
    \3:      MOVE.W D1,D3
             MOVE.L A1,A3
             SUBQ.L #2,A2
             MOVE.L A2,A4
             MOVE.W -(A0),D4
             ; Innere Schleife:
             ; D4 = Multiplikator-Ziffer, D3.W mal wird
             ; jeweils -2(A3).W * D4 zu (A4).W addiert, Überträge darunter.
             ; Benutzt A3,D3,A4,D4, verändert D5,A5
             BRA.S \6
    \4:        MOVE.W D4,D5
               MULU -(A3),D5 ; D5.L := D5.W * -(A3).W
               SUBQ.L #2,A4 ; nächstes Zielwort ansteuern
               ADD.L D5,(A4) ; Wort zu 2(A4).W addieren, Übertrag zu (A4).W
               BCC.S \6
               ; Übertrag nach links propagieren:
               MOVE.L A4,A5
    \5:          ADD.W #1,-(A5)
                 BCS.S \5
    \6:        DBF D3,\4
             ; Innere Schleife beendet.
    \7:      DBF D0,\3
           MOVEM.L (SP)+,A2-A5/D3-D5
           RTS
#endif

; extern uintD mulusub_loop_down (uintD digit, uintD* sourceptr, uintD* destptr, uintC len);
mulusub_loop_down: ; Input in D0.W,A0,A1,D1.W, benutzt D2,D3,D4, Output in D0.W
           MOVE.L D3,-(SP)
           SUB.L D2,D2        ; carry := 0, X-Bit löschen, D2.HW stets =0
           BRA.S \2
    \1:      MOVE.W -(A0),D3  ; nächstes Digit
             MULU D0,D3       ; mit digit multiplizieren
             ADDX.L D2,D3     ; und bisherigen Carry und X-Bit addieren
             SUB.W D3,-(A1)   ; Low-Digit vom dest-Digit subtrahieren, X als Übertrag
             SWAP D3
             MOVE.W D3,D2     ; High-Digit gibt neuen Carry
    \2:      DBF D1,\1
           CLR.W D0
           ADDX.W D2,D0       ; letzter Carry und letztes X-Bit
           MOVE.L (SP)+,D3
           RTS

; extern uintD divu_loop_up (uintD digit, uintD* ptr, uintC len);
divu_loop_up: # Input in D0.W,A0,D1.W, Output in D0.W
           CLR.L D2           ; Rest D2.HW := 0
           BRA.S \2
    \1:      MOVE.W (A0),D2   ; nächst-niedriges Digit mit Rest kombinieren
             DIVU D0,D2       ; und durch digit dividieren
             MOVE.W D2,(A0)+  ; Quotient ablegen, Rest in D2.HW
    \2:      DBF D1,\1
           SWAP D2
           MOVE.W D2,D0       ; Rest
           RTS

; extern uintD divucopy_loop_up (uintD digit, uintD* sourceptr, uintD* destptr, uintC len);
divucopy_loop_up: # Input in D0.W,A0,A1,D1.W, Output in D0.W
           CLR.L D2           ; Rest D2.HW := 0
           BRA.S \2
    \1:      MOVE.W (A0)+,D2  ; nächst-niedriges Digit mit Rest kombinieren
             DIVU D0,D2       ; und durch digit dividieren
             MOVE.W D2,(A1)+  ; Quotient ablegen, Rest in D2.HW
    \2:      DBF D1,\1
           SWAP D2
           MOVE.W D2,D0       ; Rest
           RTS

           .end

#endif

