# Externe Routinen zu ARILEV1.D
# Prozessor: 80386 im native mode
# Assembler-Syntax: GNU oder SUN, Moves von links nach rechts
# Compiler: GNU-C oder SUN-C
# Parameter-Übergabe: auf dem Stack 4(%esp),8(%esp),...
# Register: %eax,%edx,%ecx dürfen stets verändert werden, alles andere retten.
# Ergebnis-Übergabe: in %eax
# Einstellungen: intCsize=32, intDsize=32.

# Bruno Haible 14.8.1992
# Zum Teil abgeschrieben von Bernhard Degels "v-i386.s"

#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

  #ifdef _MSC_VER
    #include "asmi386.h"
    #undef ALIGN
    #define ALIGN
    extern unsigned long mulu32_high;
    extern unsigned long divu_32_rest;
  #else
    #ifdef ASM_UNDERSCORE
      #if defined(__STDC__) || defined (__cplusplus)
        #define C(entrypoint) _##entrypoint
      #else
        #define C(entrypoint) _/**/entrypoint
      #endif
    #else
      #define C(entrypoint) entrypoint
    #endif
    #ifdef ASM_UNDERSCORE
      #if defined(__STDC__) || defined (__cplusplus)
        #define L(label) L##label
      #else
        #define L(label) L/**/label
      #endif
    #else
      #if defined(__STDC__) || defined (__cplusplus)
        #define L(label) .L##label
      #else
        #define L(label) .L/**/label
      #endif
    #endif
    #if defined(ASM_UNDERSCORE) || defined(COHERENT) /* defined(__EMX__) || defined(__GO32__) || defined(linux) || defined(__386BSD__) || defined(__NetBSD__) || defined(COHERENT) || ... */
      # GNU-Assembler oder MWC-Assembler
      #define repz     repe
      #define shcl     %cl,
    #else /* defined(sun) || ... */
      # SUN-Assembler oder Consensys-Assembler
      #define jecxz    orl %ecx,%ecx ; jz
      #define shcl
    #endif
    # Alignment. Note that some assemblers need ".align 3,0x90" whereas other
    # assemblers don't like this syntax. So we put in the "nop"s by hand.
    #if defined(ASM_UNDERSCORE) && !defined(__CYGWIN32__)
      # BSD syntax assembler
      #define ALIGN  .align 3
    #else
      # ELF syntax assembler
      #define ALIGN  .align 8
    #endif
  #endif
  #if defined(__EMX__)
    # Direction-Flag ist defaultmäßig gelöscht
    #define dir0start
    #define dir0end
    #define dir1start  std
    #define dir1end    cld
  #elif 1
    # Wir gehen auf Nummer sicher.
    #define dir0start  cld
    #define dir0end
    #define dir1start  std
    #define dir1end    cld
  #else
    # Direction-Flag darf nach Belieben modifiziert werden
    #define dir0start  cld
    #define dir0end
    #define dir1start  std
    #define dir1end
  #endif

            .text

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

#ifndef __GNUC__ /* mit GNU-C machen wir mulu32() als Macro, der inline multipliziert */

# extern struct { uint32 lo; uint32 hi; } mulu32_ (uint32 arg1, uint32 arg2);
# 2^32*hi+lo := arg1*arg2.
            ALIGN
            .globl C(mulu32_)
C(mulu32_:)
            movl    4(%esp),%eax    # arg1
            mull    8(%esp)         # %edx|%eax := arg1 * arg2
            movl    %edx,C(mulu32_high) # %edx = hi abspeichern
            ret                     # %eax = lo als Ergebnis

#endif

#ifndef __GNUC__ /* mit GNU-C machen wir divu_6432_3232() als Macro, der inline dividiert */

# extern struct { uint32 q; uint32 r; } divu_6432_3232_ (uint32 xhi, uint32 xlo, uint32 y);
# x = 2^32*xhi+xlo = q*y+r schreiben. Sei bekannt, daß 0 <= x < 2^32*y .
            ALIGN
            .globl C(divu_6432_3232_)
C(divu_6432_3232_:)
            movl    4(%esp),%edx
            movl    8(%esp),%eax
            divl    12(%esp)       # x = %edx|%eax durch dividieren
            movl    %edx,C(divu_32_rest) # Rest %edx = r abspeichern
            ret                    # Quotient %eax = q als Ergebnis

#endif

# extern uintD* copy_loop_up (uintD* sourceptr, uintD* destptr, uintC count);
            ALIGN
C(copy_loop_up:)
            movl    %edi,%edx       # %edi retten
            movl    %esi,%eax       # %esi retten
            movl    4(%esp),%esi    # %esi = sourceptr
            movl    8(%esp),%edi    # %edi = destptr
            movl    12(%esp),%ecx   # %ecx = count
            dir0start
            rep ; movsl             # %ecx mal aufwärts (%edi) := (%esi)
            dir0end
            movl    %eax,%esi       # %esi zurück
            movl    %edi,%eax       # %edi als Ergebnis
            movl    %edx,%edi       # %edi zurück
            ret

# extern uintD* copy_loop_down (uintD* sourceptr, uintD* destptr, uintC count);
            ALIGN
C(copy_loop_down:)
            movl    %edi,%edx       # %edi retten
            movl    %esi,%eax       # %esi retten
            movl    4(%esp),%esi    # %esi = sourceptr
            movl    8(%esp),%edi    # %edi = destptr
            movl    12(%esp),%ecx   # %ecx = count
            leal    -4(%esi),%esi
            leal    -4(%edi),%edi
            dir1start
            rep ; movsl             # %ecx mal abwärts (%edi) := (%esi)
            dir1end
            movl    %eax,%esi       # %esi zurück
            leal    4(%edi),%eax    # %edi als Ergebnis
            movl    %edx,%edi       # %edi zurück
            ret

# extern uintD* fill_loop_up (uintD* destptr, uintC count, uintD filler);
            ALIGN
C(fill_loop_up:)
            movl    %edi,%edx       # %edi retten
            movl    4(%esp),%edi    # %edi = destptr
            movl    8(%esp),%ecx    # %ecx = count
            movl    12(%esp),%eax   # %eax = filler
            dir0start
            rep ; stosl             # %ecx mal aufwärts (%edi) := %eax
            dir0end
            movl    %edi,%eax       # %edi als Ergebnis
            movl    %edx,%edi       # %edi zurück
            ret

# extern uintD* fill_loop_down (uintD* destptr, uintC count, uintD filler);
            ALIGN
C(fill_loop_down:)
            movl    %edi,%edx       # %edi retten
            movl    4(%esp),%edi    # %edi = destptr
            movl    8(%esp),%ecx    # %ecx = count
            movl    12(%esp),%eax   # %eax = filler
            leal    -4(%edi),%edi
            dir1start
            rep ; stosl             # %ecx mal abwärts (%edi) := %eax
            dir1end
            leal    4(%edi),%eax    # %edi als Ergebnis
            movl    %edx,%edi       # %edi zurück
            ret

# extern uintD* clear_loop_up (uintD* destptr, uintC count);
            ALIGN
C(clear_loop_up:)
            movl    %edi,%edx       # %edi retten
            movl    4(%esp),%edi    # %edi = destptr
            movl    8(%esp),%ecx    # %ecx = count
            xorl    %eax,%eax       # %eax = 0
            dir0start
            rep ; stosl             # %ecx mal aufwärts (%edi) := %eax
            dir0end
            movl    %edi,%eax       # %edi als Ergebnis
            movl    %edx,%edi       # %edi zurück
            ret

# extern uintD* clear_loop_down (uintD* destptr, uintC count);
            ALIGN
C(clear_loop_down:)
            movl    %edi,%edx       # %edi retten
            movl    4(%esp),%edi    # %edi = destptr
            movl    8(%esp),%ecx    # %ecx = count
            leal    -4(%edi),%edi
            xorl    %eax,%eax       # %eax = 0
            dir1start
            rep ; stosl             # %ecx mal abwärts (%edi) := %eax
            dir1end
            leal    4(%edi),%eax    # %edi als Ergebnis
            movl    %edx,%edi       # %edi zurück
            ret

# extern void or_loop_up (uintD* xptr, uintD* yptr, uintC count);
            ALIGN
C(or_loop_up:)
            pushl   %esi            # %esi retten
            movl    8(%esp),%edx    # %edx = xptr
            movl    12(%esp),%esi   # %esi = yptr
            movl    16(%esp),%ecx   # %ecx = count
            subl    %edx,%esi
            jecxz   L(olu2)         # %ecx = 0 ?
L(olu1:)      movl    (%edx,%esi),%eax # *yptr
              orl     %eax,(%edx)      # *xptr |= ...
              leal    4(%edx),%edx     # xptr++, yptr++
              decl    %ecx
              jnz     L(olu1)
L(olu2:)    popl    %esi            # %esi zurück
            ret

# extern void xor_loop_up (uintD* xptr, uintD* yptr, uintC count);
            ALIGN
C(xor_loop_up:)
            pushl   %esi            # %esi retten
            movl    8(%esp),%edx    # %edx = xptr
            movl    12(%esp),%esi   # %esi = yptr
            movl    16(%esp),%ecx   # %ecx = count
            subl    %edx,%esi
            jecxz   L(xlu2)         # %ecx = 0 ?
L(xlu1:)      movl    (%edx,%esi),%eax # *yptr
              xorl    %eax,(%edx)      # *xptr ^= ...
              leal    4(%edx),%edx     # xptr++, yptr++
              decl    %ecx
              jnz     L(xlu1)
L(xlu2:)    popl    %esi            # %esi zurück
            ret

# extern void and_loop_up (uintD* xptr, uintD* yptr, uintC count);
            ALIGN
C(and_loop_up:)
            pushl   %esi            # %esi retten
            movl    8(%esp),%edx    # %edx = xptr
            movl    12(%esp),%esi   # %esi = yptr
            movl    16(%esp),%ecx   # %ecx = count
            subl    %edx,%esi
            jecxz   L(alu2)         # %ecx = 0 ?
L(alu1:)      movl    (%edx,%esi),%eax # *yptr
              andl    %eax,(%edx)      # *xptr &= ...
              leal    4(%edx),%edx     # xptr++, yptr++
              decl    %ecx
              jnz     L(alu1)
L(alu2:)    popl    %esi            # %esi zurück
            ret

# extern void eqv_loop_up (uintD* xptr, uintD* yptr, uintC count);
            ALIGN
C(eqv_loop_up:)
            pushl   %esi            # %esi retten
            movl    8(%esp),%edx    # %edx = xptr
            movl    12(%esp),%esi   # %esi = yptr
            movl    16(%esp),%ecx   # %ecx = count
            subl    %edx,%esi
            jecxz   L(elu2)         # %ecx = 0 ?
L(elu1:)      movl    (%edx),%eax      # *xptr
              xorl    (%edx,%esi),%eax # ^ *yptr
              notl    %eax             # ~(...)
              movl    %eax,(%edx)      # =: *xptr
              leal    4(%edx),%edx     # xptr++, yptr++
              decl    %ecx
              jnz     L(elu1)
L(elu2:)    popl    %esi            # %esi zurück
            ret

# extern void nand_loop_up (uintD* xptr, uintD* yptr, uintC count);
            ALIGN
C(nand_loop_up:)
            pushl   %esi            # %esi retten
            movl    8(%esp),%edx    # %edx = xptr
            movl    12(%esp),%esi   # %esi = yptr
            movl    16(%esp),%ecx   # %ecx = count
            subl    %edx,%esi
            jecxz   L(nalu2)        # %ecx = 0 ?
L(nalu1:)     movl    (%edx),%eax      # *xptr
              andl    (%edx,%esi),%eax # & *yptr
              notl    %eax             # ~(...)
              movl    %eax,(%edx)      # =: *xptr
              leal    4(%edx),%edx     # xptr++, yptr++
              decl    %ecx
              jnz     L(nalu1)
L(nalu2:)   popl    %esi            # %esi zurück
            ret

# extern void nor_loop_up (uintD* xptr, uintD* yptr, uintC count);
            ALIGN
C(nor_loop_up:)
            pushl   %esi            # %esi retten
            movl    8(%esp),%edx    # %edx = xptr
            movl    12(%esp),%esi   # %esi = yptr
            movl    16(%esp),%ecx   # %ecx = count
            subl    %edx,%esi
            jecxz   L(nolu2)        # %ecx = 0 ?
L(nolu1:)     movl    (%edx),%eax      # *xptr
              orl     (%edx,%esi),%eax # | *yptr
              notl    %eax             # ~(...)
              movl    %eax,(%edx)      # =: *xptr
              leal    4(%edx),%edx     # xptr++, yptr++
              decl    %ecx
              jnz     L(nolu1)
L(nolu2:)   popl    %esi            # %esi zurück
            ret

# extern void andc2_loop_up (uintD* xptr, uintD* yptr, uintC count);
            ALIGN
C(andc2_loop_up:)
            pushl   %esi            # %esi retten
            movl    8(%esp),%edx    # %edx = xptr
            movl    12(%esp),%esi   # %esi = yptr
            movl    16(%esp),%ecx   # %ecx = count
            subl    %edx,%esi
            jecxz   L(aclu2)        # %ecx = 0 ?
L(aclu1:)     movl    (%edx,%esi),%eax # *yptr
              notl    %eax             # ~ *yptr
              andl    %eax,(%edx)      # *xptr &= ...
              leal    4(%edx),%edx     # xptr++, yptr++
              decl    %ecx
              jnz     L(aclu1)
L(aclu2:)   popl    %esi            # %esi zurück
            ret

# extern void orc2_loop_up (uintD* xptr, uintD* yptr, uintC count);
            ALIGN
C(orc2_loop_up:)
            pushl   %esi            # %esi retten
            movl    8(%esp),%edx    # %edx = xptr
            movl    12(%esp),%esi   # %esi = yptr
            movl    16(%esp),%ecx   # %ecx = count
            subl    %edx,%esi
            jecxz   L(oclu2)        # %ecx = 0 ?
L(oclu1:)     movl    (%edx,%esi),%eax # *yptr
              notl    %eax             # ~ *yptr
              orl     %eax,(%edx)      # *xptr |= ...
              leal    4(%edx),%edx     # xptr++, yptr++
              decl    %ecx
              jnz     L(oclu1)
L(oclu2:)   popl    %esi            # %esi zurück
            ret

# extern void not_loop_up (uintD* xptr, uintC count);
            ALIGN
C(not_loop_up:)
            movl    4(%esp),%edx    # %edx = xptr
            movl    8(%esp),%ecx    # %ecx = count
            jecxz   L(nlu2)         # %ecx = 0 ?
            nop ; nop ; nop ; nop ; nop ; nop
L(nlu1:)      notl    (%edx)           # ~= *xptr
              leal    4(%edx),%edx     # xptr++
              decl    %ecx
              jnz     L(nlu1)
L(nlu2:)    ret

# extern boolean and_test_loop_up (uintD* xptr, uintD* yptr, uintC count);
            ALIGN
C(and_test_loop_up:)
            pushl   %esi            # %esi retten
            movl    8(%esp),%edx    # %edx = xptr
            movl    12(%esp),%esi   # %esi = yptr
            movl    16(%esp),%ecx   # %ecx = count
            jecxz   L(atlu2)        # %ecx = 0 ?
            subl    %edx,%esi
L(atlu1:)     movl    (%edx,%esi),%eax # *yptr
              andl    (%edx),%eax      # *xptr & ...
              jnz     L(atlu3)
              leal    4(%edx),%edx     # xptr++, yptr++
              decl    %ecx
              jnz     L(atlu1)
L(atlu2:)   xorl    %eax,%eax       # Ergebnis 0
L(atlu3:)   popl    %esi            # %esi zurück
            ret

# extern boolean test_loop_up (uintD* ptr, uintC count);
            ALIGN
C(test_loop_up:)
            movl    %edi,%edx       # %edi retten
            movl    4(%esp),%edi    # %edi = ptr
            movl    8(%esp),%ecx    # %ecx = count
            xorl    %eax,%eax       # %eax = 0
            dir0start
            repz ; scasl            # Falls %ecx > 0:
                                    # %ecx mal aufwärts (%edi) testen
                                    # und weiterschleifen, falls Z, d.h. (%edi)=0.
            dir0end
            # Noch ist %eax = 0.
            jz      L(tlu1)         # alles =0 -> Ergebnis 0
            incl    %eax            # Ergebnis 1
L(tlu1:)    movl    %edx,%edi       # %edi zurück
            ret

# extern signean compare_loop_up (uintD* xptr, uintD* yptr, uintC count);
            ALIGN
C(compare_loop_up:)
            movl    %esi,%edx       # %esi retten
            movl    %edi,%eax       # %edi retten
            movl    4(%esp),%esi    # %esi = xptr
            movl    8(%esp),%edi    # %edi = yptr
            movl    12(%esp),%ecx   # %ecx = count
            dir0start
            repz ; cmpsl            # Falls %ecx > 0:
                                    # %ecx mal aufwärts (%edi) und (%esi) vergleichen
                                    # und weiterschleifen, falls Z, d.h. (%edi)=(%esi).
            dir0end
            # Flags -> Ergebnis:
            # Z,NC -> bis zum Schluß (%esi)-(%edi) = 0 -> x=y -> Ergebnis 0
            # NZ,C -> schließlich (%esi)-(%edi) < 0 -> x<y -> Ergebnis -1
            # NZ,NC -> schließlich (%esi)-(%edi) > 0 -> x>y -> Ergebnis +1
            movl    %eax,%edi       # %edi zurück
            movl    %edx,%esi       # %esi zurück
            jbe     L(cmlu1)        # "be" = Z oder C
            movl    $1,%eax         # Ergebnis +1
            ret
L(cmlu1:)   sbbl    %eax,%eax       # Ergebnis -1 (falls C) oder 0 (falls NC)
            ret

# extern uintD add_loop_down (uintD* sourceptr1, uintD* sourceptr2, uintD* destptr, uintC count);
            ALIGN
C(add_loop_down:)
            pushl   %esi            # %esi retten
            pushl   %edi            # %edi retten
            movl    12(%esp),%edx   # %edx = sourceptr1
            movl    16(%esp),%esi   # %esi = sourceptr2
            movl    20(%esp),%edi   # %edi = destptr
            movl    24(%esp),%ecx   # %ecx = count
            subl    %edi,%edx
            subl    %edi,%esi
            orl     %ecx,%ecx       # %ecx = 0 ?, Carry löschen
            jz      L(ald2)
L(ald1:)      leal    -4(%edi),%edi   # sourceptr1--, sourceptr2--, destptr--
              movl    (%edx,%edi),%eax # *sourceptr1
              adcl    (%esi,%edi),%eax # + *sourceptr2 + carry
              movl    %eax,(%edi)     # =: *destptr, neuen Carry behalten
              decl    %ecx
              jnz     L(ald1)
L(ald2:)    sbbl    %eax,%eax      # Ergebnis := - Carry
            popl    %edi           # %edi zurück
            popl    %esi           # %esi zurück
            ret

# extern uintD addto_loop_down (uintD* sourceptr, uintD* destptr, uintC count);
            ALIGN
C(addto_loop_down:)
            pushl   %edi            # %edi retten
            movl    8(%esp),%edx    # %edx = sourceptr
            movl    12(%esp),%edi   # %edi = destptr
            movl    16(%esp),%ecx   # %ecx = count
            subl    %edi,%edx
            orl     %ecx,%ecx       # %ecx = 0 ?, Carry löschen
            jz      L(atld2)
L(atld1:)     leal    -4(%edi),%edi   # sourceptr--, destptr--
              movl    (%edx,%edi),%eax # *sourceptr
              adcl    %eax,(%edi)     # + *destptr + carry =: *destptr, neuer Carry
              decl    %ecx
              jnz     L(atld1)
L(atld2:)   sbbl    %eax,%eax       # Ergebnis := - Carry
            popl    %edi            # %edi zurück
            ret

# extern uintD inc_loop_down (uintD* ptr, uintC count);
            ALIGN
C(inc_loop_down:)
            movl    4(%esp),%edx    # %edx = ptr
            movl    8(%esp),%ecx    # %ecx = count
            jecxz   L(ild2)         # %ecx = 0 ?
L(ild1:)      leal    -4(%edx),%edx
              addl    $1,(%edx)       # (*ptr)++
              jnc     L(ild3)         # kein Carry -> fertig
              decl    %ecx
              jnz     L(ild1)
L(ild2:)    movl    $1,%eax         # Ergebnis := 1
            ret
L(ild3:)    xorl    %eax,%eax       # Ergebnis := 0
            ret

# extern uintD sub_loop_down (uintD* sourceptr1, uintD* sourceptr2, uintD* destptr, uintC count);
            ALIGN
C(sub_loop_down:)
            pushl   %esi            # %esi retten
            pushl   %edi            # %edi retten
            movl    12(%esp),%edx   # %edx = sourceptr1
            movl    16(%esp),%esi   # %esi = sourceptr2
            movl    20(%esp),%edi   # %edi = destptr
            movl    24(%esp),%ecx   # %ecx = count
            subl    %edi,%edx
            subl    %edi,%esi
            orl     %ecx,%ecx       # %ecx = 0 ?, Carry löschen
            jz      L(sld2)
L(sld1:)      leal    -4(%edi),%edi   # sourceptr1--, sourceptr2--, destptr--
              movl    (%edx,%edi),%eax # *sourceptr1
              sbbl    (%esi,%edi),%eax # - *sourceptr2 - carry
              movl    %eax,(%edi)     # =: *destptr, neuen Carry behalten
              decl    %ecx
              jnz     L(sld1)
L(sld2:)    sbbl    %eax,%eax      # Ergebnis := - Carry
            popl    %edi           # %edi zurück
            popl    %esi           # %esi zurück
            ret

# extern uintD subx_loop_down (uintD* sourceptr1, uintD* sourceptr2, uintD* destptr, uintC count, uintD carry);
            ALIGN
C(subx_loop_down:)
            pushl   %esi            # %esi retten
            pushl   %edi            # %edi retten
            movl    12(%esp),%edx   # %edx = sourceptr1
            movl    16(%esp),%esi   # %esi = sourceptr2
            movl    20(%esp),%edi   # %edi = destptr
            movl    24(%esp),%ecx   # %ecx = count
            jecxz   L(sxld2)        # %ecx = 0 ?
            subl    %edi,%edx
            subl    %edi,%esi
            movl    28(%esp),%eax   # carry, 0 oder -1
            addl    %eax,%eax       # Bit 31 davon in den Carry
            nop ; nop
L(sxld1:)     leal    -4(%edi),%edi   # sourceptr1--, sourceptr2--, destptr--
              movl    (%edx,%edi),%eax # *sourceptr1
              sbbl    (%esi,%edi),%eax # - *sourceptr2 - carry
              movl    %eax,(%edi)     # =: *destptr, neuen Carry behalten
              decl    %ecx
              jnz     L(sxld1)
            sbbl    %eax,%eax      # Ergebnis := - Carry
            popl    %edi           # %edi zurück
            popl    %esi           # %esi zurück
            ret
L(sxld2:)   movl    28(%esp),%eax  # Ergebnis := carry
            popl    %edi           # %edi zurück
            popl    %esi           # %esi zurück
            ret

# extern uintD subfrom_loop_down (uintD* sourceptr, uintD* destptr, uintC count);
            ALIGN
C(subfrom_loop_down:)
            pushl   %edi            # %edi retten
            movl    8(%esp),%edx    # %edx = sourceptr
            movl    12(%esp),%edi   # %edi = destptr
            movl    16(%esp),%ecx   # %ecx = count
            subl    %edi,%edx
            orl     %ecx,%ecx       # %ecx = 0 ?, Carry löschen
            jz      L(sfld2)
L(sfld1:)     leal    -4(%edi),%edi   # sourceptr--, destptr--
              movl    (%edx,%edi),%eax # *sourceptr
              sbbl    %eax,(%edi)     # *destptr - *sourceptr - carry =: *destptr, neuer Carry
              decl    %ecx
              jnz     L(sfld1)
L(sfld2:)   sbbl    %eax,%eax       # Ergebnis := - Carry
            popl    %edi            # %edi zurück
            ret

# extern uintD dec_loop_down (uintD* ptr, uintC count);
            ALIGN
C(dec_loop_down:)
            movl    4(%esp),%edx    # %edx = ptr
            movl    8(%esp),%ecx    # %ecx = count
            jecxz   L(dld2)         # %ecx = 0 ?
L(dld1:)      leal    -4(%edx),%edx
              subl    $1,(%edx)       # (*ptr)--
              jnc     L(dld3)         # kein Carry -> fertig
              decl    %ecx
              jnz     L(dld1)
L(dld2:)    movl    $-1,%eax        # Ergebnis := -1
            ret
L(dld3:)    xorl    %eax,%eax       # Ergebnis := 0
            ret

# extern uintD neg_loop_down (uintD* ptr, uintC count);
            ALIGN
C(neg_loop_down:)
            movl    4(%esp),%edx    # %edx = ptr
            movl    8(%esp),%ecx    # %ecx = count
            # erstes Digit /=0 suchen:
            jecxz   L(nld2)         # %ecx = 0 ?
L(nld1:)      leal    -4(%edx),%edx
              negl    (%edx)
              jnz     L(nld3)
              decl    %ecx
              jnz     L(nld1)
L(nld2:)    xorl    %eax,%eax       # Ergebnis := 0
            ret
            nop ; nop ; nop ; nop ; nop ; nop
L(nld3:)    # erstes Digit /=0 gefunden, ab jetzt gibt's Carrys
            # alle anderen Digits invertieren:
            decl    %ecx
            jz      L(nld5)
L(nld4:)      leal    -4(%edx),%edx
              notl    (%edx)
              decl    %ecx
              jnz     L(nld4)
L(nld5:)    movl    $-1,%eax        # Ergebnis := -1
            ret

# extern uintD shift1left_loop_down (uintD* ptr, uintC count);
            ALIGN
C(shift1left_loop_down:)
            movl    4(%esp),%edx    # %edx = ptr
            movl    8(%esp),%ecx    # %ecx = count
            orl     %ecx,%ecx       # %ecx = 0 ?, Carry löschen
            jz      L(s1lld2)
            nop ; nop ; nop ; nop
L(s1lld1:)    leal    -4(%edx),%edx   # ptr--
              rcll    $1,(%edx)       # *ptr und Carry um 1 Bit links rotieren
              decl    %ecx
              jnz     L(s1lld1)
L(s1lld2:)  sbbl    %eax,%eax       # Ergebnis := - Carry
            ret

# extern uintD shiftleft_loop_down (uintD* ptr, uintC count, uintC i, uintD carry);
            ALIGN
C(shiftleft_loop_down:)
            pushl   %edi            # %edi retten
            pushl   %ebx            # %ebx retten
            movl    12(%esp),%edi   # %edi = ptr
            movl    16(%esp),%edx   # %edx = count
            movl    20(%esp),%ecx   # %cl = i
            orl     %edx,%edx       # count = 0 ?
            jz      L(slld4)
            # erstes Digit shiften:
            leal    -4(%edi),%edi
            movl    (%edi),%eax     # Digit in %eax halten
            movl    %eax,%ebx       # und in %ebx rechnen:
            shll    %cl,%ebx        # um i Bits links shiften
            orl     24(%esp),%ebx   # und die unteren i Bits eintragen
            movl    %ebx,(%edi)     # und wieder ablegen
            # Letztes Digit in %eax.
            decl    %edx
            jz      L(slld2)
            nop ; nop ; nop ; nop
L(slld1:)     # weiteres Digit shiften:
              leal    -4(%edi),%edi
              movl    (%edi),%ebx
              shldl   shcl %eax,(%edi) # (%edi) um %cl=i Bits links shiften, %eax von rechts reinshiften
              # Letztes Digit in %ebx.
              decl    %edx
              jz      L(slld3)
              # weiteres Digit shiften:
              leal    -4(%edi),%edi
              movl    (%edi),%eax
              shldl   shcl %ebx,(%edi) # (%edi) um %cl=i Bits links shiften, %ebx von rechts reinshiften
              # Letztes Digit in %eax.
              decl    %edx
              jnz     L(slld1)
L(slld2:)   movl    %eax,%ebx
L(slld3:)   xorl    %eax,%eax       # %eax := 0
            shldl   shcl %ebx,%eax  # %eax := höchste %cl=i Bits von %ebx
            popl    %ebx            # %ebx zurück
            popl    %edi            # %edi zurück
            ret
L(slld4:)   movl    24(%esp),%eax   # %eax := carry
            popl    %ebx            # %ebx zurück
            popl    %edi            # %edi zurück
            ret

# extern uintD shiftleftcopy_loop_down (uintD* sourceptr, uintD* destptr, uintC count, uintC i);
            ALIGN
C(shiftleftcopy_loop_down:)
            pushl   %esi            # %esi retten
            pushl   %edi            # %edi retten
            pushl   %ebx            # %ebx retten
            movl    16(%esp),%esi   # %esi = sourceptr
            movl    20(%esp),%edi   # %edi = destptr
            movl    24(%esp),%edx   # count
            movl    28(%esp),%ecx   # %cl = i
            orl     %edx,%edx       # count = 0 ?
            jz      L(slcld4)
            subl    %edi,%esi
            # erstes Digit shiften:
            leal    -4(%edi),%edi   # sourceptr--, destptr--
            movl    (%edi,%esi),%ebx # *sourceptr in %ebx halten
            movl    %ebx,%eax       # und in %eax rechnen:
            shll    %cl,%eax        # um i Bits links shiften, rechts Nullen rein
            movl    %eax,(%edi)     # und als *destptr ablegen
            # Letztes Digit in %ebx.
            negb    %cl             # %cl = 32-i
            decl    %edx
            jz      L(slcld2)
L(slcld1:)    # weiteres Digit shiften:
              leal    -4(%edi),%edi   # sourceptr--, destptr--
              movl    (%edi,%esi),%eax # nächstes Digit nach %eax
              shrdl   shcl %eax,%ebx  # %ebx um %cl=32-i Bits rechts shiften, %eax von links reinshiften
              movl    %ebx,(%edi)     # %ebx als *destptr ablegen
              # Letztes Digit in %eax.
              decl    %edx
              jz      L(slcld3)
              # weiteres Digit shiften:
              leal    -4(%edi),%edi   # sourceptr--, destptr--
              movl    (%edi,%esi),%ebx # nächstes Digit nach %ebx
              shrdl   shcl %ebx,%eax  # %eax um %cl=32-i Bits rechts shiften, %ebx von links reinshiften
              movl    %eax,(%edi)     # %eax als *destptr ablegen
              # Letztes Digit in %ebx.
              decl    %edx
              jnz     L(slcld1)
L(slcld2:)  movl    %ebx,%eax
L(slcld3:)  shrl    %cl,%eax        # %eax um 32-i Bits nach rechts shiften
            popl    %ebx            # %ebx zurück
            popl    %edi            # %edi zurück
            popl    %esi            # %esi zurück
            ret
L(slcld4:)  xorl    %eax,%eax       # %eax := 0
            popl    %ebx            # %ebx zurück
            popl    %edi            # %edi zurück
            popl    %esi            # %esi zurück
            ret

# extern uintD shift1right_loop_up (uintD* ptr, uintC count, uintD carry);
            ALIGN
C(shift1right_loop_up:)
            movl    4(%esp),%edx    # %edx = ptr
            movl    8(%esp),%ecx    # %ecx = count
            movl    12(%esp),%eax   # %eax = carry (0 oder -1)
            jecxz   L(s1rld3)       # %ecx = 0 ?
            addl    %eax,%eax       # Carry := Bit 31 von carry
L(s1rld1:)    rcrl    $1,(%edx)       # *ptr und Carry um 1 Bit rechts rotieren
              leal    4(%edx),%edx    # ptr++
              decl    %ecx
              jnz     L(s1rld1)
L(s1rld2:)  sbbl    %eax,%eax       # Ergebnis := - Carry
L(s1rld3:)  ret

# extern uintD shiftright_loop_up (uintD* ptr, uintC count, uintC i);
            ALIGN
C(shiftright_loop_up:)
            pushl   %edi            # %edi retten
            pushl   %ebx            # %ebx retten
            movl    12(%esp),%edi   # %edi = ptr
            movl    16(%esp),%edx   # %edx = count
            movl    20(%esp),%ecx   # %cl = i
            orl     %edx,%edx       # count = 0 ?
            jz      L(srlu4)
            # erstes Digit shiften:
            movl    (%edi),%eax     # Digit in %eax halten
            movl    %eax,%ebx       # und in %ebx rechnen:
            shrl    %cl,%ebx        # um i Bits rechts shiften
            movl    %ebx,(%edi)     # und wieder ablegen
            # Letztes Digit in %eax.
            decl    %edx
            jz      L(srlu2)
            nop ; nop ; nop
L(srlu1:)     # weiteres Digit shiften:
              leal    4(%edi),%edi
              movl    (%edi),%ebx
              shrdl   shcl %eax,(%edi) # (%edi) um %cl=i Bits rechts shiften, %eax von links reinshiften
              # Letztes Digit in %ebx.
              decl    %edx
              jz      L(srlu3)
              # weiteres Digit shiften:
              leal    4(%edi),%edi
              movl    (%edi),%eax
              shrdl   shcl %ebx,(%edi) # (%edi) um %cl=i Bits rechts shiften, %ebx von links reinshiften
              # Letztes Digit in %eax.
              decl    %edx
              jnz     L(srlu1)
L(srlu2:)   movl    %eax,%ebx
L(srlu3:)   xorl    %eax,%eax       # %eax := 0
            shrdl   shcl %ebx,%eax  # %eax := niedrigste %cl=i Bits von %ebx, als Bits 31..32-i
            popl    %ebx            # %ebx zurück
            popl    %edi            # %edi zurück
            ret
L(srlu4:)   xorl    %eax,%eax       # %eax := 0
            popl    %ebx            # %ebx zurück
            popl    %edi            # %edi zurück
            ret

# extern uintD shiftrightsigned_loop_up (uintD* ptr, uintC count, uintC i);
            ALIGN
C(shiftrightsigned_loop_up:)
            pushl   %edi            # %edi retten
            pushl   %ebx            # %ebx retten
            movl    12(%esp),%edi   # %edi = ptr
            movl    16(%esp),%edx   # %edx = count
            movl    20(%esp),%ecx   # %cl = i
            # erstes Digit shiften:
            movl    (%edi),%eax     # Digit in %eax halten
            movl    %eax,%ebx       # und in %ebx rechnen:
            sarl    %cl,%ebx        # um i Bits rechts shiften, Vorzeichen vervielfachen
            movl    %ebx,(%edi)     # und wieder ablegen
            # Letztes Digit in %eax.
            decl    %edx
            jz      L(srslu2)
L(srslu1:)    # weiteres Digit shiften:
              leal    4(%edi),%edi
              movl    (%edi),%ebx
              shrdl   shcl %eax,(%edi) # (%edi) um %cl=i Bits rechts shiften, %eax von links reinshiften
              # Letztes Digit in %ebx.
              decl    %edx
              jz      L(srslu3)
              # weiteres Digit shiften:
              leal    4(%edi),%edi
              movl    (%edi),%eax
              shrdl   shcl %ebx,(%edi) # (%edi) um %cl=i Bits rechts shiften, %ebx von links reinshiften
              # Letztes Digit in %eax.
              decl    %edx
              jnz     L(srslu1)
L(srslu2:)  movl    %eax,%ebx
L(srslu3:)  xorl    %eax,%eax       # %eax := 0
            shrdl   shcl %ebx,%eax  # %eax := niedrigste %cl=i Bits von %ebx, als Bits 31..32-i
            popl    %ebx            # %ebx zurück
            popl    %edi            # %edi zurück
            ret

# extern uintD shiftrightcopy_loop_up (uintD* sourceptr, uintD* destptr, uintC count, uintC i, uintD carry);
            ALIGN
C(shiftrightcopy_loop_up:)
            pushl   %esi            # %esi retten
            pushl   %edi            # %edi retten
            pushl   %ebx            # %ebx retten
            movl    16(%esp),%esi   # %esi = sourceptr
            movl    20(%esp),%edi   # %edi = destptr
            movl    24(%esp),%edx   # count
            movl    28(%esp),%ecx   # %cl = i
            negb    %cl             # 32-i
            movl    32(%esp),%eax   # %eax = carry
            orl     %edx,%edx       # count = 0 ?
            jz      L(srcld3)
            subl    %edi,%esi
            # erstes Digit shiften:
            movl    (%edi,%esi),%ebx # *sourceptr in %ebx halten
            shldl   shcl %ebx,%eax  # carry um %cl=32-i Bits links shiften, dabei *sourceptr rein
            movl    %eax,(%edi)     # und als *destptr ablegen
            # Letztes Digit in %ebx.
            decl    %edx
            jz      L(srcld2)
L(srcld1:)    # weiteres Digit shiften:
              leal    4(%edi),%edi    # sourceptr++, destptr++
              movl    (%edi,%esi),%eax # nächstes Digit nach %eax
              shldl   shcl %eax,%ebx  # %ebx um %cl=32-i Bits links shiften, %eax von rechts reinshiften
              movl    %ebx,(%edi)     # %ebx als *destptr ablegen
              # Letztes Digit in %eax.
              decl    %edx
              jz      L(srcld3)
              # weiteres Digit shiften:
              leal    4(%edi),%edi    # sourceptr++, destptr++
              movl    (%edi,%esi),%ebx # nächstes Digit nach %ebx
              shldl   shcl %ebx,%eax  # %eax um %cl=32-i Bits links shiften, %ebx von rechts reinshiften
              movl    %eax,(%edi)     # %eax als *destptr ablegen
              # Letztes Digit in %ebx.
              decl    %edx
              jnz     L(srcld1)
L(srcld2:)  movl    %ebx,%eax
L(srcld3:)  shll    %cl,%eax        # %eax um 32-i Bits nach links shiften
            popl    %ebx            # %ebx zurück
            popl    %edi            # %edi zurück
            popl    %esi            # %esi zurück
            ret

# extern uintD mulusmall_loop_down (uintD digit, uintD* ptr, uintC len, uintD newdigit);
            ALIGN
C(mulusmall_loop_down:)
            pushl   %ebp            # %ebp retten
            pushl   %edi            # %edi retten
            pushl   %ebx            # %ebx retten
            movl    16(%esp),%ebx   # %ebx = digit
            movl    20(%esp),%edi   # %edi = ptr
            movl    24(%esp),%ecx   # %ecx = len
            movl    28(%esp),%ebp   # %ebp = carry := newdigit
            movl    %ecx,%eax
            negl    %eax            # %eax = -len
            jz      L(msld2)
            leal    -4(%edi,%eax,4),%edi # %edi = &ptr[-1-len]
            nop ; nop ; nop
L(msld1:)     movl    (%edi,%ecx,4),%eax # *ptr
              mull    %ebx               # %edx|%eax := digit * *ptr
              addl    %ebp,%eax          # carry und Low-Teil des Produktes addieren
              movl    $0,%ebp
              adcl    %edx,%ebp          # Übertrag zum High-Teil %edx dazu, gibt neuen carry
              movl    %eax,(%edi,%ecx,4) # Low-Teil als *ptr ablegen
              decl    %ecx               # count--, ptr--
              jnz     L(msld1)
L(msld2:)   movl    %ebp,%eax       # Ergebnis := letzter Übertrag
            popl    %ebx            # %ebx zurück
            popl    %edi            # %edi zurück
            popl    %ebp            # %ebp zurück
            ret

# extern void mulu_loop_down (uintD digit, uintD* sourceptr, uintD* destptr, uintC len);
            ALIGN
C(mulu_loop_down:)
            pushl   %ebp            # %ebp retten
            pushl   %edi            # %edi retten
            pushl   %esi            # %esi retten
            pushl   %ebx            # %ebx retten
            movl    20(%esp),%ebx   # %ebx = digit
            movl    24(%esp),%esi   # %esi = sourceptr
            movl    28(%esp),%edi   # %edi = destptr
            movl    32(%esp),%ecx   # %ecx = len
            movl    %ecx,%eax
            notl    %eax            # %eax = -1-len
            leal    (%esi,%eax,4),%esi # %esi = &sourceptr[-1-len]
            leal    (%edi,%eax,4),%edi # %edi = &destptr[-1-len]
            xorl    %ebp,%ebp       # %epb = carry := 0
L(muld1:)     movl    (%esi,%ecx,4),%eax # *sourceptr
              mull    %ebx               # %edx|%eax := digit * *sourceptr
              addl    %ebp,%eax          # carry und Low-Teil des Produktes addieren
              movl    $0,%ebp
              adcl    %edx,%ebp          # Übertrag zum High-Teil %edx dazu, gibt neuen carry
              movl    %eax,(%edi,%ecx,4) # Low-Teil als *destptr ablegen
              decl    %ecx               # count--, sourceptr--, destptr--
              jnz     L(muld1)
            movl    %ebp,(%edi)     # letzten Übertrag ablegen
            popl    %ebx            # %ebx zurück
            popl    %esi            # %esi zurück
            popl    %edi            # %edi zurück
            popl    %ebp            # %ebp zurück
            ret

# extern uintD muluadd_loop_down (uintD digit, uintD* sourceptr, uintD* destptr, uintC len);
            ALIGN
C(muluadd_loop_down:)
            pushl   %ebp            # %ebp retten
            pushl   %edi            # %edi retten
            pushl   %esi            # %esi retten
            pushl   %ebx            # %ebx retten
            movl    20(%esp),%ebx   # %ebx = digit
            movl    24(%esp),%esi   # %esi = sourceptr
            movl    28(%esp),%edi   # %edi = destptr
            movl    32(%esp),%ecx   # %ecx = len
            movl    %ecx,%eax
            notl    %eax            # %eax = -1-len
            leal    (%esi,%eax,4),%esi # %esi = &sourceptr[-1-len]
            leal    (%edi,%eax,4),%edi # %edi = &destptr[-1-len]
            xorl    %ebp,%ebp       # %epb = carry := 0
L(muald1:)    movl    (%esi,%ecx,4),%eax # *sourceptr
              mull    %ebx               # %edx|%eax := digit * *sourceptr
              addl    %ebp,%eax          # carry und Low-Teil des Produktes addieren
              movl    $0,%ebp
              adcl    %ebp,%edx          # Übertrag zum High-Teil %edx dazu
              addl    %eax,(%edi,%ecx,4) # Low-Teil zu *destptr addieren
              adcl    %edx,%ebp          # zweiten Übertrag zu %edx addieren, gibt neuen carry
              decl    %ecx               # count--, sourceptr--, destptr--
              jnz     L(muald1)
            movl    %ebp,%eax       # Ergebnis := letzter Übertrag
            popl    %ebx            # %ebx zurück
            popl    %esi            # %esi zurück
            popl    %edi            # %edi zurück
            popl    %ebp            # %ebp zurück
            ret

# extern uintD mulusub_loop_down (uintD digit, uintD* sourceptr, uintD* destptr, uintC len);
            ALIGN
C(mulusub_loop_down:)
            pushl   %ebp            # %ebp retten
            pushl   %edi            # %edi retten
            pushl   %esi            # %esi retten
            pushl   %ebx            # %ebx retten
            movl    20(%esp),%ebx   # %ebx = digit
            movl    24(%esp),%esi   # %esi = sourceptr
            movl    28(%esp),%edi   # %edi = destptr
            movl    32(%esp),%ecx   # %ecx = len
            movl    %ecx,%eax
            notl    %eax            # %eax = -1-len
            leal    (%esi,%eax,4),%esi # %esi = &sourceptr[-1-len]
            leal    (%edi,%eax,4),%edi # %edi = &destptr[-1-len]
            xorl    %ebp,%ebp       # %epb = carry := 0
L(musld1:)    movl    (%esi,%ecx,4),%eax # *sourceptr
              mull    %ebx               # %edx|%eax := digit * *sourceptr
              addl    %ebp,%eax          # carry und Low-Teil des Produktes addieren
              movl    $0,%ebp
              adcl    %ebp,%edx          # Übertrag zum High-Teil %edx dazu
              subl    %eax,(%edi,%ecx,4) # Low-Teil von *destptr subtrahieren
              adcl    %edx,%ebp          # zweiten Übertrag zu %edx addieren, gibt neuen carry
              decl    %ecx               # count--, sourceptr--, destptr--
              jnz     L(musld1)
            movl    %ebp,%eax       # Ergebnis := letzter Übertrag
            popl    %ebx            # %ebx zurück
            popl    %esi            # %esi zurück
            popl    %edi            # %edi zurück
            popl    %ebp            # %ebp zurück
            ret

# extern uintD divu_loop_up (uintD digit, uintD* ptr, uintC len);
            ALIGN
C(divu_loop_up:)
            pushl   %edi            # %edi retten
            pushl   %ebx            # %ebx retten
            movl    12(%esp),%ebx   # %ebx = digit
            movl    16(%esp),%edi   # %edi = ptr
            movl    20(%esp),%ecx   # %ecx = len
            xorl    %edx,%edx       # %edx = Rest := 0
            jecxz   L(dlu2)         # %ecx = 0 ?
L(dlu1:)      movl    (%edi),%eax     # nächstes Digit *ptr
              divl    %ebx            # Division von %edx|%eax durch %ebx
              movl    %eax,(%edi)     # Quotient %eax ablegen, Rest in %edx behalten
              leal    4(%edi),%edi    # ptr++
              decl    %ecx
              jnz     L(dlu1)
L(dlu2:)    movl    %edx,%eax       # Ergebnis := letzter Rest
            popl    %ebx            # %ebx zurück
            popl    %edi            # %edi zurück
            ret

# extern uintD divucopy_loop_up (uintD digit, uintD* sourceptr, uintD* destptr, uintC len);
            ALIGN
C(divucopy_loop_up:)
            pushl   %edi            # %edi retten
            pushl   %esi            # %esi retten
            pushl   %ebx            # %ebx retten
            movl    16(%esp),%ebx   # %ebx = digit
            movl    20(%esp),%esi   # %esi = sourceptr
            movl    24(%esp),%edi   # %edi = destptr
            movl    28(%esp),%ecx   # %ecx = len
            xorl    %edx,%edx       # %edx = Rest := 0
            jecxz   L(dclu2)        # %ecx = 0 ?
            subl    %edi,%esi
L(dclu1:)     movl    (%esi,%edi),%eax # nächstes Digit *ptr
              divl    %ebx            # Division von %edx|%eax durch %ebx
              movl    %eax,(%edi)     # Quotient %eax ablegen, Rest in %edx behalten
              leal    4(%edi),%edi    # sourceptr++, destptr++
              decl    %ecx
              jnz     L(dclu1)
L(dclu2:)   movl    %edx,%eax       # Ergebnis := letzter Rest
            popl    %ebx            # %ebx zurück
            popl    %esi            # %esi zurück
            popl    %edi            # %edi zurück
            ret

#endif

