/* ARM assembly AARCH64 Raspberry PI 3B */
/*  program avltree64.s   */

/*******************************************/
/* Constantes file                         */
/*******************************************/
/* for this file see task include a file in language AArch64 assembly*/
.include "../includeConstantesARM64.inc"

.equ NBVAL,    12

/*******************************************/
/* Structures                               */
/********************************************/
/* structure tree     */
    .struct  0
tree_root:                             // root pointer (or node right)
    .struct  tree_root + 8
tree_size:                             // number of element of tree
    .struct  tree_size + 8
tree_suite:
    .struct  tree_suite + 24           // for alignement to node
tree_fin:
/* structure node tree */
    .struct  0
node_right:                            // right pointer
    .struct  node_right + 8
node_left:                             // left pointer
    .struct  node_left + 8
node_value:                            // element value
    .struct  node_value + 8
node_height:                          // element value
    .struct  node_height + 8
node_parent:                          // element value
    .struct  node_parent + 8
node_fin:

/*******************************************/
/* Initialized data                        */
/*******************************************/
.data
szMessPreOrder:       .asciz "PreOrder :\n"
szCarriageReturn:     .asciz "\n"
/* datas error display */
szMessErreur:         .asciz "Error detected.\n"
szMessKeyDbl:         .asciz "Key exists in tree.\n"
szMessInsInv:         .asciz "Insertion in inverse order.\n"
/* datas message display */
szMessResult:         .asciz "Ele: @ G: @ D: @ val @ h @ \npere @\n"

/*******************************************/
/* UnInitialized data                      */
/*******************************************/
.bss
sZoneConv:            .skip 24
stTree:               .skip tree_fin    // place to structure tree
stTree1:              .skip tree_fin    // place to structure tree
/*******************************************/
/*  code section                           */
/*******************************************/
.text
.global main
main:
    mov x20,#1                           // node tree value
1:                                      // loop insertion in order
    ldr x0,qAdrstTree                   // structure tree address
    mov x1,x20
    bl insertElement                    // add element value x1
    cmp x0,-1
    beq 99f
    add x20,x20,1                           // increment value
    cmp x20,NBVAL                       // end ?
    ble 1b                              // no -> loop

    ldr x0,qAdrstTree                   // structure tree address
    mov x1,11                           // verif key dobble
    bl insertElement                    // add element value x1
    cmp x0,-1
    bne 2f
    ldr x0,qAdrszMessErreur
    bl affichageMess
2:
    ldr x0,qAdrszMessPreOrder           // load verification
    bl affichageMess
    ldr x3,qAdrstTree                   // tree root address (begin structure)
    ldr x0,[x3,tree_root]
    ldr x1,qAdrdisplayElement           // function to execute
    bl preOrder

    ldr x0,qAdrszMessInsInv
    bl affichageMess
    mov x20,NBVAL                       // node tree value
3:                                      // loop insertion inverse order
    ldr x0,qAdrstTree1                  // structure tree address
    mov x1,x20
    bl insertElement                    // add element value x1
    cmp x0,-1
    beq 99f
    sub x20,x20,1                           // increment value
    cmp x20,0                           // end ?
    bgt 3b                              // no -> loop

    ldr x0,qAdrszMessPreOrder           // load verification
    bl affichageMess
    ldr x3,qAdrstTree1                  // tree root address (begin structure)
    ldr x0,[x3,tree_root]
    ldr x1,qAdrdisplayElement           // function to execute
    bl preOrder

                                        // search value
    ldr x0,qAdrstTree1                  // tree root address (begin structure)
    mov x1,11                          // value to search
    bl searchTree
    cmp x0,-1
    beq 100f
    mov x2,x0
    ldr x0,qAdrszMessKeyDbl             // key exists
    bl affichageMess
                                        // suppresssion previous value
    mov x0,x2
    ldr x1,qAdrstTree1
    bl supprimer

    ldr x0,qAdrszMessPreOrder           // verification
    bl affichageMess
    ldr x3,qAdrstTree1                  // tree root address (begin structure)
    ldr x0,[x3,tree_root]
    ldr x1,qAdrdisplayElement           // function to execute
    bl preOrder

    b 100f
99:                                     // display error
    ldr x0,qAdrszMessErreur
    bl affichageMess
100:                                    // standard end of the program
    mov x8, #EXIT                       // request to exit program
    svc 0                               // perform system call
qAdrszMessPreOrder:        .quad szMessPreOrder
qAdrszMessErreur:          .quad szMessErreur
qAdrszCarriageReturn:      .quad szCarriageReturn
qAdrstTree:                .quad stTree
qAdrstTree1:               .quad stTree1
qAdrdisplayElement:        .quad displayElement
qAdrszMessInsInv:          .quad szMessInsInv
/******************************************************************/
/*     insert element in the tree                                 */
/******************************************************************/
/* x0 contains the address of the tree structure */
/* x1 contains the value of element              */
/* x0 returns address of element or - 1 if error */
insertElement:                        // INFO: insertElement
    stp x1,lr,[sp,-16]!               // save  registers
    mov x6,x0                         // save head
    mov x0,#node_fin                  // reservation place one element
    bl allocHeap
    cmp x0,#-1                        // allocation error
    beq 100f
    mov x5,x0
    str x1,[x5,#node_value]           // store value in address heap
    mov x3,#0
    str x3,[x5,#node_left]            // init left pointer with zero
    str x3,[x5,#node_right]           // init right pointer with zero
    str x3,[x5,#node_height]          // init balance with zero
    ldr x2,[x6,#tree_size]            // load tree size
    cmp x2,#0                         // 0 element ?
    bne 1f
    str x5,[x6,#tree_root]            // yes -> store in root
    b 4f
1:                                    // else search free address in tree
    ldr x3,[x6,#tree_root]            // start with address root
2:                                    // begin loop to insertion
    ldr x4,[x3,#node_value]           // load key
    cmp x1,x4
    beq 6f                            // key equal
    blt 3f                            // key <
                                      // key >  insertion right
    ldr x8,[x3,#node_right]           // node empty ?
    cmp x8,#0
    csel x3,x8,x3,ne                  // current = right node if not
    //movne x3,x8                       // no -> next node
    bne 2b                            // and loop
    str x5,[x3,#node_right]           // store node address in right pointer
    b 4f
3:                                    // left
    ldr x8,[x3,#node_left]            // left pointer empty ?
    cmp x8,#0
    csel x3,x8,x3,ne                  // current = left node if not
    //movne x3,x8                       //
    bne 2b                            // no -> loop
    str x5,[x3,#node_left]            // store node address in left pointer
4:
    str x3,[x5,#node_parent]          // store parent
    mov x4,#1
    str x4,[x5,#node_height]          // store height = 1
    mov x0,x5                         // begin node to requilbrate
    mov x1,x6                         // head address
    bl equilibrer

5:
    add x2,x2,#1                        // increment tree size
    str x2,[x6,#tree_size]
    mov x0,#0
    b 100f
6:                                   // key equal ?
    ldr x0,qAdrszMessKeyDbl
    bl affichageMess
    mov x0,#-1
    b 100f
100:
    ldp x1,lr,[sp],16              // restaur  2 registers
    ret                            // return to address lr x30
qAdrszMessKeyDbl:           .quad szMessKeyDbl
/******************************************************************/
/*     equilibrer after insertion                                    */
/******************************************************************/
/* x0 contains the address of the node       */
/* x1 contains the address of head */
equilibrer:                       // INFO: equilibrer
    stp x1,lr,[sp,-16]!           // save  registers
    stp x2,x3,[sp,-16]!           // save  registers
    stp x4,x5,[sp,-16]!           // save  registers
    stp x6,x7,[sp,-16]!           // save  registers
    mov x3,#0                     // balance factor
1:                                // begin loop
    ldr x5,[x0,#node_parent]      // load father
    cmp x5,#0                     // end ?
    beq 8f
    cmp x3,#2                     // right tree too long
    beq 8f
    cmp x3,#-2                    // left tree too long
    beq 8f
    mov x6,x0                     // s = current
    ldr x0,[x6,#node_parent]      // current = father
    ldr x7,[x0,#node_left]
    mov x4,#0
    cmp x7,#0
    beq 2f
    ldr x4,[x7,#node_height]     // height left tree
2:
    ldr x7,[x0,#node_right]
    mov x2,#0
    cmp x7,#0
    beq 3f
    ldr x2,[x7,#node_height]     // height right tree
3:
    cmp x4,x2
    ble 4f
    add x4,x4,#1
    str x4,[x0,#node_height]
    b 5f
4:
    add x2,x2,#1
    str x2,[x0,#node_height]
5:
    ldr x7,[x0,#node_right]
    mov x4,0
    cmp x7,#0
    beq 6f
    ldr x4,[x7,#node_height]
6:
    ldr x7,[x0,#node_left]
    mov x2,0
    cmp x7,#0
    beq 7f
    ldr x2,[x7,#node_height]
7:
    sub x3,x4,x2                    // compute balance factor
    b 1b
8:
    cmp x3,#2
    beq 9f
    cmp x3,#-2
    beq 9f
    b 100f
9:
    mov x3,x1
    mov x4,x0
    mov x1,x6
    bl equiUnSommet
                                      // change head address ?
    ldr x2,[x3,#tree_root]
    cmp x2,x4
    bne 100f
    str x6,[x3,#tree_root]
100:
    ldp x6,x7,[sp],16              // restaur  2 registers
    ldp x4,x5,[sp],16              // restaur  2 registers
    ldp x2,x3,[sp],16              // restaur  2 registers
    ldp x1,lr,[sp],16              // restaur  2 registers
    ret                            // return to address lr x30
/******************************************************************/
/*     equilibre 1 sommet                                     */
/******************************************************************/
/* x0 contains the address of the node       */
/* x1 contains the address of the node    */
equiUnSommet:                             // INFO: equiUnSommet
    stp x1,lr,[sp,-16]!           // save  registers
    stp x2,x3,[sp,-16]!           // save  registers
    stp x4,x5,[sp,-16]!           // save  registers
    stp x6,x7,[sp,-16]!           // save  registers
    mov x5,x0                             // save p
    mov x6,x1    // s
    ldr x2,[x5,#node_left]
    cmp x2,x6
    bne 6f
    ldr x7,[x5,#node_right]
    mov x4,#0
    cmp x7,#0
    beq 1f
    ldr x4,[x7,#node_height]
1:
    ldr x7,[x5,#node_left]
    mov x2,0
    cmp x7,#0
    beq 2f
    ldr x2,[x7,#node_height]
2:
    sub x3,x4,x2
    cmp x3,#-2
    bne 100f
    ldr x7,[x6,#node_right]
    mov x4,0
    cmp x7,#0
    beq 3f
    ldr x4,[x7,#node_height]
3:
    ldr x7,[x6,#node_left]
    mov x2,0
    cmp x7,#0
    beq 4f
    ldr x2,[x7,#node_height]
4:
    sub x3,x4,x2
    cmp x3,#1
    bge 5f
    mov x0,x5
    bl rotRight
    b 100f
5:
    mov x0,x6
    bl rotLeft
    mov x0,x5
    bl rotRight
    b 100f

6:
    ldr x7,[x5,#node_right]
    mov x4,0
    cmp x7,#0
    beq 7f
    ldr x4,[x7,#node_height]
7:
    ldr x7,[x5,#node_left]
    mov x2,0
    cmp x7,#0
    beq 8f
    ldr x2,[x7,#node_height]
8:
    sub x3,x4,x2
    cmp x3,2
    bne 100f
    ldr x7,[x6,#node_right]
    mov x4,0
    cmp x7,#0
    beq 9f
    ldr x4,[x7,#node_height]
9:
    ldr x7,[x6,#node_left]
    mov x2,0
    cmp x7,#0
    beq 10f
    ldr x2,[x7,#node_height]
10:
    sub x3,x4,x2
    cmp x3,#-1
    ble 11f
    mov x0,x5
    bl rotLeft
    b 100f
11:
    mov x0,x6
    bl rotRight
    mov x0,x5
    bl rotLeft

100:
    ldp x6,x7,[sp],16              // restaur  2 registers
    ldp x4,x5,[sp],16              // restaur  2 registers
    ldp x2,x3,[sp],16              // restaur  2 registers
    ldp x1,lr,[sp],16              // restaur  2 registers
    ret                            // return to address lr x30
/******************************************************************/
/*     right rotation                                     */
/******************************************************************/
/* x0 contains the address of the node       */
rotRight:                           // INFO: rotRight
    stp x1,lr,[sp,-16]!           // save  registers
    stp x2,x3,[sp,-16]!           // save  registers
    stp x4,x5,[sp,-16]!           // save  registers
    //   x2                  x2
    //      x0                   x1
    //   x1                         x0
    //      x3                    x3
    ldr x1,[x0,#node_left]          // load left children
    ldr x2,[x0,#node_parent]        // load father
    cmp x2,#0                       // no father ???
    beq 2f
    ldr x3,[x2,#node_left]          // load left node father
    cmp x3,x0                       // equal current node ?
    bne 1f
    str x1,[x2,#node_left]        // yes store left children
    b 2f
1:
    str x1,[x2,#node_right]       // no store right
2:
    str x2,[x1,#node_parent]        // change parent
    str x1,[x0,#node_parent]
    ldr x3,[x1,#node_right]
    str x3,[x0,#node_left]
    cmp x3,#0
    beq 3f
    str x0,[x3,#node_parent]      // change parent node left
3:
    str x0,[x1,#node_right]

    ldr x3,[x0,#node_left]          // compute newbalance factor
    mov x4,0
    cmp x3,#0
    beq 4f
    ldr x4,[x3,#node_height]
4:
    ldr x3,[x0,#node_right]
    mov x5,0
    cmp x3,#0
    beq 5f
    ldr x5,[x3,#node_height]
5:
    cmp x4,x5
    ble 6f
    add x4,x4,#1
    str x4,[x0,#node_height]
    b 7f
6:
    add x5,x5,#1
    str x5,[x0,#node_height]
7:
//
    ldr x3,[x1,#node_left]         // compute new balance factor
    mov x4,0
    cmp x3,#0
    beq 8f
    ldr x4,[x3,#node_height]
8:
    ldr x3,[x1,#node_right]
    mov x5,0
    cmp x3,#0
    beq 9f
    ldr x5,[x3,#node_height]
9:
    cmp x4,x5
    ble 10f
    add x4,x4,#1
    str x4,[x1,#node_height]
    b 100f
10:
    add x5,x5,#1
    str x5,[x1,#node_height]
100:
    ldp x4,x5,[sp],16              // restaur  2 registers
    ldp x2,x3,[sp],16              // restaur  2 registers
    ldp x1,lr,[sp],16              // restaur  2 registers
    ret                            // return to address lr x30
/******************************************************************/
/*     left rotation                                     */
/******************************************************************/
/* x0 contains the address of the node  sommet     */
rotLeft:                             // INFO: rotLeft
    stp x1,lr,[sp,-16]!              // save  registers
    stp x2,x3,[sp,-16]!              // save  registers
    stp x4,x5,[sp,-16]!              // save  registers
    //   x2                  x2
    //      x0                   x1
    //          x1            x0
    //        x3                 x3
    ldr x1,[x0,#node_right]          // load right children
    ldr x2,[x0,#node_parent]         // load father (racine)
    cmp x2,#0                        // no father ???
    beq 2f
    ldr x3,[x2,#node_left]           // load left node father
    cmp x3,x0                        // equal current node ?
    bne 1f
    str x1,[x2,#node_left]         // yes store left children
    b 2f
1:
    str x1,[x2,#node_right]        // no store to right
2:
    str x2,[x1,#node_parent]         // change parent of right children
    str x1,[x0,#node_parent]         // change parent of sommet
    ldr x3,[x1,#node_left]           // left children
    str x3,[x0,#node_right]          // left children pivot exists ?
    cmp x3,#0
    beq 3f
    str x0,[x3,#node_parent]       // yes store in
3:
    str x0,[x1,#node_left]
//
    ldr x3,[x0,#node_left]           // compute new height for old summit
    mov x4,0
    cmp x3,#0
    beq 4f
    ldr x4,[x3,#node_height]       // left height
4:
    ldr x3,[x0,#node_right]
    mov x5,0
    cmp x3,#0
    beq 5f
    ldr x5,[x3,#node_height]       // right height
5:
    cmp x4,x5
    ble 6f
    add x4,x4,#1
    str x4,[x0,#node_height]       // if right > left
    b 7f
6:
    add x5,x5,#1
    str x5,[x0,#node_height]       // if left > right
7:
//
    ldr x3,[x1,#node_left]           // compute new height for new
    mov x4,0
    cmp x3,#0
    beq 8f
    ldr x4,[x3,#node_height]
8:
    ldr x3,[x1,#node_right]
    mov x5,0
    cmp x3,#0
    beq 9f
    ldr x5,[x3,#node_height]
9:
    cmp x4,x5
    ble 10f
    add x4,x4,#1
    str x4,[x1,#node_height]
    b 100f
10:
    add x5,x5,#1
    str x5,[x1,#node_height]
100:
    ldp x4,x5,[sp],16              // restaur  2 registers
    ldp x2,x3,[sp],16              // restaur  2 registers
    ldp x1,lr,[sp],16              // restaur  2 registers
    ret                            // return to address lr x30
/******************************************************************/
/*     search value in tree                                       */
/******************************************************************/
/* x0 contains the address of structure of tree */
/* x1 contains the value to search  */
searchTree:                           // INFO: searchTree
    stp x2,lr,[sp,-16]!              // save  registers
    stp x3,x4,[sp,-16]!              // save  registers
    ldr x2,[x0,#tree_root]

1:                                    // begin loop
    ldr x4,[x2,#node_value]           // load key
    cmp x1,x4
    beq 3f                            // key equal
    blt 2f                            // key <
                                      // key >  insertion right
    ldr x3,[x2,#node_right]           // node empty ?
    cmp x3,#0
    csel x2,x3,x2,ne
    //movne x2,x3                       // no -> next node
    bne 1b                            // and loop
    mov x0,#-1                        // not find
    b 100f
2:                                    // left
    ldr x3,[x2,#node_left]            // left pointer empty ?
    cmp x3,#0
    csel x2,x3,x2,ne
    bne 1b                            // no -> loop
    mov x0,#-1                        // not find
    b 100f
3:
    mov x0,x2                         // return node address
100:
    ldp x3,x4,[sp],16              // restaur  2 registers
    ldp x2,lr,[sp],16              // restaur  2 registers
    ret                            // return to address lr x30
/******************************************************************/
/*     suppression node                                           */
/******************************************************************/
/* x0 contains the address of the node */
/* x1 contains structure tree address  */
supprimer:                       // INFO: supprimer
    stp x1,lr,[sp,-16]!           // save  registers
    stp x2,x3,[sp,-16]!           // save  registers
    stp x4,x5,[sp,-16]!           // save  registers
    stp x6,x7,[sp,-16]!           // save  registers
    ldr x1,[x0,#node_left]
    cmp x1,#0
    bne 5f
    ldr x1,[x0,#node_right]
    cmp x1,#0
    bne 5f
                                 // is a leaf
    mov x4,#0
    ldr x3,[x0,#node_parent]     // father
    cmp x3,#0
    bne 11f
    str x4,[x1,#tree_root]
    b 100f
11:
    ldr x1,[x3,#node_left]
    cmp x1,x0
    bne 2f
    str x4,[x3,#node_left]       // suppression left children
    ldr x5,[x3,#node_right]
    mov x6,#0
    cmp x5,#0
    beq 12f
    ldr x6,[x5,#node_height]
12:
    add x6,x6,#1
    str x6,[x3,#node_height]
    b 3f
2:                                // suppression right children
    str x4,[x3,#node_right]
    ldr x5,[x3,#node_left]
    mov x6,#0
    cmp x5,#0
    beq 21f
    ldr x6,[x5,#node_height]
21:
    add x6,x6,#1
    str x6,[x3,#node_height]
3:                                // new balance
    mov x0,x3
    bl equilibrerSupp
    b 100f
5:                                // is not à leaf
    ldr x7,[x0,#node_right]
    cmp x7,#0
    beq 7f
    mov x2,x0
    mov x0,x7
6:
    ldr x6,[x0,#node_left]  // search the litle element
    cmp x6,#0
    beq 9f
    mov x0,x6
    b 6b
7:
    ldr x7,[x0,#node_left]
    cmp x7,#0
    beq 9f
    mov x2,x0
    mov x0,x7
8:
    ldr x6,[x0,#node_right]        // search the great element
    cmp x6,#0
    beq 9f
    mov x0,x6
    b 8b
9:
    ldr x5,[x0,#node_value]         // copy value
    str x5,[x2,#node_value]
    bl supprimer                    // suppression node x0
100:
    ldp x6,x7,[sp],16              // restaur  2 registers
    ldp x4,x5,[sp],16              // restaur  2 registers
    ldp x2,x3,[sp],16              // restaur  2 registers
    ldp x1,lr,[sp],16              // restaur  2 registers
    ret                            // return to address lr x30

/******************************************************************/
/*     equilibrer after suppression                                   */
/******************************************************************/
/* x0 contains the address of the node       */
/* x1 contains the address of head */
equilibrerSupp:                   // INFO: equilibrerSupp
    stp x1,lr,[sp,-16]!           // save  registers
    stp x2,x3,[sp,-16]!           // save  registers
    stp x4,x5,[sp,-16]!           // save  registers
    stp x6,x7,[sp,-16]!           // save  registers
    mov x3,#1                     // balance factor
    ldr x2,[x1,#tree_root]
1:
    ldr x5,[x0,#node_parent]      // load father
    cmp x5,#0                     // no father
    beq 100f
    cmp x3,#0                     // balance equilibred
    beq 100f
    mov x6,x0                     // save entry node
    ldr x0,[x6,#node_parent]      // current = father
    ldr x7,[x0,#node_left]
    mov x4,#0
    cmp x7,#0
    b 11f
    ldr x4,[x7,#node_height]    // height left tree
11:
    ldr x7,[x0,#node_right]
    mov x5,#0
    cmp x7,#0
    beq 12f
    ldr x5,[x7,#node_height]    // height right tree
12:
    cmp x4,x5
    ble 13f
    add x4,x4,1
    str x4,[x0,#node_height]
    b 14f
13:
    add x5,x5,1
    str x5,[x0,#node_height]
14:
    ldr x7,[x0,#node_right]
    mov x4,#0
    cmp x7,#0
    beq 15f
    ldr x4,[x7,#node_height]
15:
    ldr x7,[x0,#node_left]
    mov x5,0
    cmp x7,#0
    beq 16f
    ldr x5,[x7,#node_height]
16:
    sub x3,x4,x5                   // compute balance factor
    mov x2,x1
    mov x7,x0                      // save current
    mov x1,x6
    bl equiUnSommet
                                   // change head address ?
    cmp x2,x7
    bne 17f
    str x6,[x3,#tree_root]
17:
    mov x0,x7                      // restaur current
    b 1b

100:
    ldp x6,x7,[sp],16              // restaur  2 registers
    ldp x4,x5,[sp],16              // restaur  2 registers
    ldp x2,x3,[sp],16              // restaur  2 registers
    ldp x1,lr,[sp],16              // restaur  2 registers
    ret                            // return to address lr x30
/******************************************************************/
/*     preOrder                                  */
/******************************************************************/
/* x0 contains the address of the node */
/* x1 function address                 */
preOrder:                                 // INFO: preOrder
    stp x2,lr,[sp,-16]!           // save  registers
    cmp x0,#0
    beq 100f
    mov x2,x0
    blr x1                                // call function
    ldr x0,[x2,#node_left]
    bl preOrder
    ldr x0,[x2,#node_right]
    bl preOrder
100:
    ldp x2,lr,[sp],16              // restaur  2 registers
    ret                            // return to address lr x30

/******************************************************************/
/*     display node                                               */
/******************************************************************/
/* x0 contains node  address          */
displayElement:                   // INFO: displayElement
    stp x1,lr,[sp,-16]!           // save  registers
    stp x2,x3,[sp,-16]!           // save  registers
    stp x4,x5,[sp,-16]!           // save  registers
    mov x2,x0
    ldr x1,qAdrsZoneConv
    bl conversion16
    //strb wzr,[x1,x0]
    ldr x0,qAdrszMessResult
    ldr x1,qAdrsZoneConv
    bl strInsertAtCharInc
    mov x3,x0
    ldr x0,[x2,#node_left]
    ldr x1,qAdrsZoneConv
    bl conversion16
    //strb wzr,[x1,x0]
    mov x0,x3
    ldr x1,qAdrsZoneConv
    bl strInsertAtCharInc
    mov x3,x0
    ldr x0,[x2,#node_right]
    ldr x1,qAdrsZoneConv
    bl conversion16
    //strb wzr,[x1,x0]
    mov x0,x3
    ldr x1,qAdrsZoneConv
    bl strInsertAtCharInc
    mov x3,x0
    ldr x0,[x2,#node_value]
    ldr x1,qAdrsZoneConv
    bl conversion10
    //strb wzr,[x1,x0]
    mov x0,x3
    ldr x1,qAdrsZoneConv
    bl strInsertAtCharInc
    mov x3,x0
    ldr x0,[x2,#node_height]
    ldr x1,qAdrsZoneConv
    bl conversion10
    //strb wzr,[x1,x0]
    mov x0,x3
    ldr x1,qAdrsZoneConv
    bl strInsertAtCharInc
    mov x3,x0
    ldr x0,[x2,#node_parent]
    ldr x1,qAdrsZoneConv
    bl conversion16
    //strb wzr,[x1,x0]
    mov x0,x3
    ldr x1,qAdrsZoneConv
    bl strInsertAtCharInc
    bl affichageMess
100:
    ldp x4,x5,[sp],16              // restaur  2 registers
    ldp x2,x3,[sp],16              // restaur  2 registers
    ldp x1,lr,[sp],16              // restaur  2 registers
    ret                            // return to address lr x30
qAdrszMessResult:          .quad szMessResult
qAdrsZoneConv:             .quad sZoneConv

/******************************************************************/
/*     memory allocation on the heap                                  */
/******************************************************************/
/* x0 contains the size to allocate */
/* x0 returns address of memory heap or - 1 if error */
/* CAUTION : The size of the allowance must be a multiple of 4  */
allocHeap:
    stp x1,lr,[sp,-16]!            // save  registers
    stp x2,x8,[sp,-16]!            // save  registers
    // allocation
    mov x1,x0                      // save size
    mov x0,0                       // read address start heap
    mov x8,BRK                     // call system 'brk'
    svc 0
    mov x2,x0                      // save address heap for return
    add x0,x0,x1                   // reservation place for size
    mov x8,BRK                     // call system 'brk'
    svc 0
    cmp x0,-1                      // allocation error
    beq 100f
    mov x0,x2                      // return address memory heap
100:
    ldp x2,x8,[sp],16              // restaur  2 registers
    ldp x1,lr,[sp],16              // restaur  2 registers
    ret                            // return to address lr x30
/********************************************************/
/*        File Include fonctions                        */
/********************************************************/
/* for this file see task include a file in language AArch64 assembly */
.include "../includeARM64.inc"


with Ada.Text_IO, Ada.Finalization, Ada.Unchecked_Deallocation;

procedure Main is

   generic
      type Key_Type is private;
      with function "<"(a, b : Key_Type) return Boolean is <>;
      with function "="(a, b : Key_Type) return Boolean is <>;
      with function "<="(a, b : Key_Type) return Boolean is <>;
   package AVL_Tree is
      type Tree is tagged limited private;
      function insert(self : in out Tree; key : Key_Type) return Boolean;
      procedure delete(self : in out Tree; key : Key_Type);
      procedure print_balance(self : in out Tree);

   private
      type Height_Amt is range -1 .. Integer'Last;

      -- Since only one key is inserted before each rebalance, the balance of
      -- all trees/subtrees will stay in range -2 .. 2
      type Balance_Amt is range -2 .. 2;

      type Node;
      type Node_Ptr is access Node;
      type Node is new Ada.Finalization.Limited_Controlled with record
         left, right, parent : Node_Ptr := null;
         key : Key_Type;
         balance : Balance_Amt := 0;
      end record;
      overriding procedure Finalize(self : in out Node);
      subtype Node_Parent is Ada.Finalization.Limited_Controlled;

      type Tree is new Ada.Finalization.Limited_Controlled with record
         root : Node_Ptr := null;
      end record;
      overriding procedure Finalize(self : in out Tree);

   end AVL_Tree;

   package body AVL_Tree is

      procedure Free_Node is new Ada.Unchecked_Deallocation(Node, Node_Ptr);

      overriding procedure Finalize(self : in out Node) is
      begin
         Free_Node(self.left);
         Free_Node(self.right);
      end Finalize;

      overriding procedure Finalize(self : in out Tree) is
      begin
         Free_Node(self.root);
      end Finalize;

      function height(n : Node_Ptr) return Height_Amt is
      begin
         if n = null then
            return -1;
         else
            return 1 + Height_Amt'Max(height(n.left), height(n.right));
         end if;
      end height;

      procedure set_balance(n : not null Node_Ptr) is
      begin
         n.balance := Balance_Amt(height(n.right) - height(n.left));
      end set_balance;

      procedure update_parent(parent : Node_Ptr; new_child : Node_Ptr; old_child : Node_Ptr) is
      begin
         if parent /= null then
            if parent.right = old_child then
               parent.right := new_child;
            else
               parent.left := new_child;
            end if;
         end if;
      end update_parent;

      function rotate_left(a : not null Node_Ptr) return Node_Ptr is
         b : Node_Ptr := a.right;
      begin
         b.parent := a.parent;
         a.right := b.left;
         if a.right /= null then
            a.right.parent := a;
         end if;
         b.left := a;
         a.parent := b;
         update_parent(parent => b.parent, new_child => b, old_child => a);

         set_balance(a);
         set_balance(b);
         return b;
      end rotate_left;

      function rotate_right(a : not null Node_Ptr) return Node_Ptr is
         b : Node_Ptr := a.left;
      begin
         b.parent := a.parent;
         a.left := b.right;
         if a.left /= null then
            a.left.parent := a;
         end if;
         b.right := a;
         a.parent := b;
         update_parent(parent => b.parent, new_child => b, old_child => a);

         set_balance(a);
         set_balance(b);
         return b;
      end rotate_right;

      function rotate_left_right(n : not null Node_Ptr) return Node_Ptr is
      begin
         n.left := rotate_left(n.left);
         return rotate_right(n);
      end rotate_left_right;

      function rotate_right_left(n : not null Node_Ptr) return Node_Ptr is
      begin
         n.right := rotate_right(n.right);
         return rotate_left(n);
      end rotate_right_left;

      procedure rebalance(self : in out Tree; n : not null Node_Ptr) is
         new_n : Node_Ptr := n;
      begin
         set_balance(new_n);
         if new_n.balance = -2 then
            if height(new_n.left.left) >= height(new_n.left.right) then
               new_n := rotate_right(new_n);
            else
               new_n := rotate_left_right(new_n);
            end if;
         elsif new_n.balance = 2 then
            if height(new_n.right.right) >= height(new_n.right.left) then
               new_n := rotate_left(new_n);
            else
               new_n := rotate_right_left(new_n);
            end if;
         end if;

         if new_n.parent /= null then
            rebalance(self, new_n.parent);
         else
            self.root := new_n;
         end if;
      end rebalance;

      function new_node(key : Key_Type) return Node_Ptr is
        (new Node'(Node_Parent with key => key, others => <>));

      function insert(self : in out Tree; key : Key_Type) return Boolean is
         curr, parent : Node_Ptr;
         go_left : Boolean;
      begin
         if self.root = null then
            self.root := new_node(key);
            return True;
         end if;

         curr := self.root;
         while curr.key /= key loop
            parent := curr;
            go_left := key < curr.key;
            curr := (if go_left then curr.left else curr.right);
            if curr = null then
               if go_left then
                  parent.left := new_node(key);
                  parent.left.parent := parent;
               else
                  parent.right := new_node(key);
                  parent.right.parent := parent;
               end if;
               rebalance(self, parent);
               return True;
            end if;
         end loop;
         return False;
      end insert;

      procedure delete(self : in out Tree; key : Key_Type) is
         successor, parent, child : Node_Ptr := self.root;
         to_delete : Node_Ptr := null;
      begin
         if self.root = null then
            return;
         end if;

         while child /= null loop
            parent := successor;
            successor := child;
            child := (if successor.key <= key then successor.right else successor.left);
            if successor.key = key then
               to_delete := successor;
            end if;
         end loop;

         if to_delete = null then
            return;
         end if;
         to_delete.key := successor.key;
         child := (if successor.left = null then successor.right else successor.left);
         if self.root.key = key then
            self.root := child;
         else
            update_parent(parent => parent, new_child => child, old_child => successor);
            rebalance(self, parent);
         end if;
         Free_Node(successor);
      end delete;

      procedure print_balance(n : Node_Ptr) is
      begin
         if n /= null then
            print_balance(n.left);
            Ada.Text_IO.Put(n.balance'Image);
            print_balance(n.right);
         end if;
      end print_balance;

      procedure print_balance(self : in out Tree) is
      begin
         print_balance(self.root);
      end print_balance;
   end AVL_Tree;

   package Int_AVL_Tree is new AVL_Tree(Integer);

   tree : Int_AVL_Tree.Tree;
   success : Boolean;
begin
   for i in 1 .. 10 loop
      success := tree.insert(i);
   end loop;
   Ada.Text_IO.Put("Printing balance: ");
   tree.print_balance;
   Ada.Text_IO.New_Line;
end Main;


module Avl where

-- The Peano naturals
data Nat : Set where
 z : Nat
 s : Nat -> Nat

-- An AVL tree's type is indexed by a natural.
-- Avl N is the type of AVL trees of depth N. There arj 3 different
-- node constructors:
--   Left: The left subtree is one level deeper than the right
--   Balanced: The subtrees have the same depth
--   Right: The right Subtree is one level deeper than the left
-- Since the AVL invariant is that the depths of a node's subtrees
-- always differ by at most 1, this perfectly encodes the AVL depth invariant.
data Avl : Nat -> Set where
  Empty : Avl z
  Left : {X : Nat} -> Nat -> Avl (s X) -> Avl X -> Avl (s (s X))
  Balanced : {X : Nat} -> Nat -> Avl X -> Avl X -> Avl (s X)
  Right : {X : Nat} -> Nat -> Avl X -> Avl (s X) -> Avl (s (s X))

-- A wrapper type that hides the AVL tree invariant. This is the interface
-- exposed to the user.
data Tree : Set where
  avl : {N : Nat} -> Avl N -> Tree

-- Comparison result
data Ord : Set where
  Less : Ord
  Equal : Ord
  Greater : Ord

-- Comparison function
cmp : Nat -> Nat -> Ord
cmp z (s X) = Less
cmp z z = Equal
cmp (s X) z = Greater
cmp (s X) (s Y) = cmp X Y

-- Insertions can either leave the depth the same or
-- increase it by one. Encode this in the type.
data InsertResult : Nat -> Set where
  Same : {X : Nat} -> Avl X -> InsertResult X
  Bigger : {X : Nat} -> Avl (s X) -> InsertResult X

-- If the left subtree is 2 levels deeper than the right, rotate to the right.
-- balance-left X L R means X is the root, L is the left subtree and R is the right.
balance-left : {N : Nat} -> Nat -> Avl (s (s N)) -> Avl N -> InsertResult (s (s N))
balance-left X (Right Y A (Balanced Z B C)) D = Same (Balanced Z (Balanced X A B) (Balanced Y C D))
balance-left X (Right Y A (Left Z B C)) D = Same (Balanced Z (Balanced X A B) (Right Y C D))
balance-left X (Right Y A (Right Z B C)) D = Same (Balanced Z (Left X A B) (Balanced Y C D))
balance-left X (Left Y (Balanced Z A B) C) D = Same (Balanced Z (Balanced X A B) (Balanced Y C D))
balance-left X (Left Y (Left Z A B) C) D = Same (Balanced Z (Left X A B) (Balanced Y C D))
balance-left X (Left Y (Right Z A B) C) D = Same (Balanced Z (Right X A B) (Balanced Y C D))
balance-left X (Balanced Y (Balanced Z A B) C) D = Bigger (Right Z (Balanced X A B) (Left Y C D))
balance-left X (Balanced Y (Left Z A B) C) D =  Bigger (Right Z (Left X A B) (Left Y C D))
balance-left X (Balanced Y (Right Z A B) C) D = Bigger (Right Z (Right X A B) (Left Y C D))

-- Symmetric with balance-left
balance-right : {N : Nat} -> Nat -> Avl N -> Avl (s (s N)) -> InsertResult (s (s N))
balance-right X A (Left Y (Left Z B C) D) = Same (Balanced Z (Balanced X A B) (Right Y C D))
balance-right X A (Left Y (Balanced Z B C) D) = Same(Balanced Z (Balanced  X A B) (Balanced Y C D))
balance-right X A (Left Y (Right Z B C) D) = Same(Balanced Z (Left X A B) (Balanced Y C D))
balance-right X A (Balanced Z B (Left Y C D)) = Bigger(Left Z (Right X A B) (Left Y C D))
balance-right X A (Balanced Z B (Balanced Y C D)) = Bigger (Left Z (Right X A B) (Balanced Y C D))
balance-right X A (Balanced Z B (Right Y C D)) = Bigger (Left Z (Right X A B) (Right Y C D))
balance-right X A (Right Z B (Left Y C D)) = Same (Balanced Z (Balanced X A B) (Left Y C D))
balance-right X A (Right Z B (Balanced Y C D)) = Same (Balanced Z (Balanced X A B) (Balanced Y C D))
balance-right X A (Right Z B (Right Y C D)) =  Same (Balanced Z (Balanced X A B) (Right Y C D))

-- insert' T N does all the work of inserting the element N into the tree T.
insert' : {N : Nat} -> Avl N -> Nat -> InsertResult N
insert' Empty N = Bigger (Balanced N Empty Empty)
insert' (Left Y L R) X with cmp X Y
insert' (Left Y L R) X | Less with insert' L X
insert' (Left Y L R) X | Less | Same L' = Same (Left Y L' R)
insert' (Left Y L R) X | Less | Bigger L' = balance-left Y L' R
insert' (Left Y L R) X | Equal = Same (Left Y L R)
insert' (Left Y L R) X | Greater with insert' R X
insert' (Left Y L R) X | Greater | Same R' = Same (Left Y L R')
insert' (Left Y L R) X | Greater | Bigger R' = Same (Balanced Y L R')
insert' (Balanced Y L R) X with cmp X Y
insert' (Balanced Y L R) X | Less with insert' L X
insert' (Balanced Y L R) X | Less | Same L'  = Same (Balanced Y L' R)
insert' (Balanced Y L R) X | Less | Bigger L' = Bigger (Left Y L' R)
insert' (Balanced Y L R) X | Equal = Same (Balanced Y L R)
insert' (Balanced Y L R) X | Greater with insert' R X
insert' (Balanced Y L R) X | Greater | Same R' = Same (Balanced Y L R')
insert' (Balanced Y L R) X | Greater | Bigger R' = Bigger (Right Y L R')
insert' (Right Y L R) X with cmp X Y
insert' (Right Y L R) X | Less with insert' L X
insert' (Right Y L R) X | Less | Same L' = Same (Right Y L' R)
insert' (Right Y L R) X | Less | Bigger L' = Same (Balanced Y L' R)
insert' (Right Y L R) X | Equal = Same (Right Y L R)
insert' (Right Y L R) X | Greater with insert' R X
insert' (Right Y L R) X | Greater | Same R' = Same (Right Y L R')
insert' (Right Y L R) X | Greater | Bigger R' = balance-right Y L R'

-- Wrapper around insert' to use the depth-agnostic type Tree.
insert : Tree -> Nat  -> Tree
insert (avl T) X with insert' T X
... | Same T' = avl T'
... | Bigger T' = avl T'


/* ARM assembly Raspberry PI  */
/*  program avltree2.s   */

/* REMARK 1 : this program use routines in a include file
   see task Include a file language arm assembly
   for the routine affichageMess conversion10
   see at end of this program the instruction include */

/*******************************************/
/* Constantes                              */
/*******************************************/
.equ STDOUT, 1           @ Linux output console
.equ EXIT,   1           @ Linux syscall
.equ WRITE,  4           @ Linux syscall
.equ BRK,    0x2d        @ Linux syscall
.equ CHARPOS,     '@'

.equ NBVAL,    12

/*******************************************/
/* Structures                               */
/********************************************/
/* structure tree     */
    .struct  0
tree_root:                             @ root pointer (or node right)
    .struct  tree_root + 4
tree_size:                             @ number of element of tree
    .struct  tree_size + 4
tree_suite:
    .struct  tree_suite + 12           @ for alignement to node
tree_fin:
/* structure node tree */
    .struct  0
node_right:                            @ right pointer
    .struct  node_right + 4
node_left:                             @ left pointer
    .struct  node_left + 4
node_value:                            @ element value
    .struct  node_value + 4
node_height:                          @ element value
    .struct  node_height + 4
node_parent:                          @ element value
    .struct  node_parent + 4
node_fin:
/* structure queue*/
    .struct  0
queue_begin:                           @ next pointer
    .struct  queue_begin + 4
queue_end:                             @ element value
    .struct  queue_end + 4
queue_fin:
/* structure node queue    */
    .struct  0
queue_node_next:                       @ next pointer
    .struct  queue_node_next + 4
queue_node_value:                      @ element value
    .struct  queue_node_value + 4
queue_node_fin:
/*******************************************/
/* Initialized data                        */
/*******************************************/
.data
szMessPreOrder:       .asciz "PreOrder :\n"
szCarriageReturn:     .asciz "\n"
/* datas error display */
szMessErreur:         .asciz "Error detected.\n"
szMessKeyDbl:         .asciz "Key exists in tree.\n"
szMessInsInv:         .asciz "Insertion in inverse order.\n"
/* datas message display */
szMessResult:         .asciz "Ele: @ G: @ D: @ val @ h @ pere @\n"
sValue:               .space 12,' '
                      .asciz "\n"
/*******************************************/
/* UnInitialized data                      */
/*******************************************/
.bss
sZoneConv:            .skip 24
stTree:               .skip tree_fin    @ place to structure tree
stTree1:              .skip tree_fin    @ place to structure tree
stQueue:              .skip queue_fin   @ place to structure queue
/*******************************************/
/*  code section                           */
/*******************************************/
.text
.global main
main:
    mov r8,#1                           @ node tree value
1:                                      @ loop insertion in order
    ldr r0,iAdrstTree                   @ structure tree address
    mov r1,r8
    bl insertElement                    @ add element value r1
    cmp r0,#-1
    beq 99f
    //ldr r3,iAdrstTree                 @ tree root address (begin structure)
    //ldr r0,[r3,#tree_root]
    //ldr r1,iAdrdisplayElement           @ function to execute
    //bl preOrder
    add r8,#1                           @ increment value
    cmp r8,#NBVAL                       @ end ?
    ble 1b                              @ no -> loop

    ldr r0,iAdrstTree                   @ structure tree address
    mov r1,#11                          @ verif key dobble
    bl insertElement                    @ add element value r1
    cmp r0,#-1
    bne 2f
    ldr r0,iAdrszMessErreur
    bl affichageMess
2:
    ldr r0,iAdrszMessPreOrder           @ load verification
    bl affichageMess
    ldr r3,iAdrstTree                   @ tree root address (begin structure)
    ldr r0,[r3,#tree_root]
    ldr r1,iAdrdisplayElement           @ function to execute
    bl preOrder

    ldr r0,iAdrszMessInsInv
    bl affichageMess
    mov r8,#NBVAL                       @ node tree value
3:                                      @ loop insertion inverse order
    ldr r0,iAdrstTree1                  @ structure tree address
    mov r1,r8
    bl insertElement                    @ add element value r1
    cmp r0,#-1
    beq 99f
    sub r8,#1                           @ increment value
    cmp r8,#0                           @ end ?
    bgt 3b                              @ no -> loop

    ldr r0,iAdrszMessPreOrder           @ load verification
    bl affichageMess
    ldr r3,iAdrstTree1                  @ tree root address (begin structure)
    ldr r0,[r3,#tree_root]
    ldr r1,iAdrdisplayElement           @ function to execute
    bl preOrder

                                        @ search value
    ldr r0,iAdrstTree1                  @ tree root address (begin structure)
    mov r1,#11                          @ value to search
    bl searchTree
    cmp r0,#-1
    beq 100f
    mov r2,r0
    ldr r0,iAdrszMessKeyDbl             @ key exists
    bl affichageMess
                                        @ suppresssion previous value
    mov r0,r2
    ldr r1,iAdrstTree1
    bl supprimer

    ldr r0,iAdrszMessPreOrder           @ verification
    bl affichageMess
    ldr r3,iAdrstTree1                  @ tree root address (begin structure)
    ldr r0,[r3,#tree_root]
    ldr r1,iAdrdisplayElement           @ function to execute
    bl preOrder

    b 100f
99:                                     @ display error
    ldr r0,iAdrszMessErreur
    bl affichageMess
100:                                    @ standard end of the program
    mov r7, #EXIT                       @ request to exit program
    svc 0                               @ perform system call
iAdrszMessPreOrder:        .int szMessPreOrder
iAdrszMessErreur:          .int szMessErreur
iAdrszCarriageReturn:      .int szCarriageReturn
iAdrstTree:                .int stTree
iAdrstTree1:               .int stTree1
iAdrstQueue:               .int stQueue
iAdrdisplayElement:        .int displayElement
iAdrszMessInsInv:          .int szMessInsInv
/******************************************************************/
/*     insert element in the tree                                 */
/******************************************************************/
/* r0 contains the address of the tree structure */
/* r1 contains the value of element              */
/* r0 returns address of element or - 1 if error */
insertElement:                        @ INFO: insertElement
    push {r1-r8,lr}                   @ save  registers
    mov r7,r0                         @ save head
    mov r0,#node_fin                  @ reservation place one element
    bl allocHeap
    cmp r0,#-1                        @ allocation error
    beq 100f
    mov r5,r0
    str r1,[r5,#node_value]           @ store value in address heap
    mov r3,#0
    str r3,[r5,#node_left]            @ init left pointer with zero
    str r3,[r5,#node_right]           @ init right pointer with zero
    str r3,[r5,#node_height]          @ init balance with zero
    ldr r2,[r7,#tree_size]            @ load tree size
    cmp r2,#0                         @ 0 element ?
    bne 1f
    str r5,[r7,#tree_root]            @ yes -> store in root
    b 4f
1:                                    @ else search free address in tree
    ldr r3,[r7,#tree_root]            @ start with address root
2:                                    @ begin loop to insertion
    ldr r4,[r3,#node_value]           @ load key
    cmp r1,r4
    beq 6f                            @ key equal
    blt 3f                            @ key <
                                      @ key >  insertion right
    ldr r8,[r3,#node_right]           @ node empty ?
    cmp r8,#0
    movne r3,r8                       @ no -> next node
    bne 2b                            @ and loop
    str r5,[r3,#node_right]           @ store node address in right pointer
    b 4f
3:                                    @ left
    ldr r8,[r3,#node_left]            @ left pointer empty ?
    cmp r8,#0
    movne r3,r8                       @
    bne 2b                            @ no -> loop
    str r5,[r3,#node_left]            @ store node address in left pointer
4:
    str r3,[r5,#node_parent]          @ store parent
    mov r4,#1
    str r4,[r5,#node_height]          @ store height = 1
    mov r0,r5                         @ begin node to requilbrate
    mov r1,r7                         @ head address
    bl equilibrer

5:
    add r2,#1                        @ increment tree size
    str r2,[r7,#tree_size]
    mov r0,#0
    b 100f
6:                                   @ key equal ?
    ldr r0,iAdrszMessKeyDbl
    bl affichageMess
    mov r0,#-1
    b 100f
100:
    pop {r1-r8,lr}                    @ restaur registers
    bx lr                             @ return
iAdrszMessKeyDbl:           .int szMessKeyDbl
/******************************************************************/
/*     equilibrer after insertion                                    */
/******************************************************************/
/* r0 contains the address of the node       */
/* r1 contains the address of head */
equilibrer:                       @ INFO: equilibrer
    push {r1-r8,lr}               @ save  registers
    mov r3,#0                     @ balance factor
1:                                @ begin loop
    ldr r5,[r0,#node_parent]      @ load father
    cmp r5,#0                     @ end ?
    beq 5f
    cmp r3,#2                     @ right tree too long
    beq 5f
    cmp r3,#-2                    @ left tree too long
    beq 5f
    mov r6,r0                     @ s = current
    ldr r0,[r6,#node_parent]      @ current = father
    ldr r7,[r0,#node_left]
    cmp r7,#0
    ldrne r8,[r7,#node_height]     @ height left tree
    moveq r8,#0
    ldr r7,[r0,#node_right]
    cmp r7,#0
    ldrne r9,[r7,#node_height]     @ height right tree
    moveq r9,#0
    cmp r8,r9
    addgt r8,#1
    strgt r8,[r0,#node_height]
    addle r9,#1
    strle r9,[r0,#node_height]
    //
    ldr r7,[r0,#node_right]
    cmp r7,#0
    ldrne r8,[r7,#node_height]
    moveq r8,#0
    ldr r7,[r0,#node_left]
    cmp r7,#0
    ldrne r9,[r7,#node_height]
    moveq r9,#0
    sub r3,r8,r9                    @ compute balance factor
    b 1b
5:
    cmp r3,#2
    beq 6f
    cmp r3,#-2
    beq 6f
    b 100f
6:
    mov r3,r1
    mov r4,r0
    mov r1,r6
    bl equiUnSommet
                                      @ change head address ?
    ldr r2,[r3,#tree_root]
    cmp r2,r4
    streq r6,[r3,#tree_root]
100:
    pop {r1-r8,lr}                    @ restaur registers
    bx lr                             @ return
/******************************************************************/
/*     equilibre 1 sommet                                     */
/******************************************************************/
/* r0 contains the address of the node       */
/* r1 contains the address of the node    */
equiUnSommet:                             @ INFO: equiUnSommet
    push {r1-r9,lr}                       @ save  registers
    mov r5,r0                             @ save p
    mov r6,r1    // s
    ldr r2,[r5,#node_left]
    cmp r2,r6
    bne 5f
    ldr r7,[r5,#node_right]
    cmp r7,#0
    moveq r8,#0
    ldrne r8,[r7,#node_height]
    ldr r7,[r5,#node_left]
    cmp r7,#0
    moveq r9,#0
    ldrne r9,[r7,#node_height]
    sub r3,r8,r9
    cmp r3,#-2
    bne 100f
    ldr r7,[r6,#node_right]
    cmp r7,#0
    moveq r8,#0
    ldrne r8,[r7,#node_height]
    ldr r7,[r6,#node_left]
    cmp r7,#0
    moveq r9,#0
    ldrne r9,[r7,#node_height]
    sub r3,r8,r9
    cmp r3,#1
    bge 2f
    mov r0,r5
    bl rotRight
    b 100f
2:
    mov r0,r6
    bl rotLeft
    mov r0,r5
    bl rotRight
    b 100f

5:
    ldr r7,[r5,#node_right]
    cmp r7,#0
    moveq r8,#0
    ldrne r8,[r7,#node_height]
    ldr r7,[r5,#node_left]
    cmp r7,#0
    moveq r9,#0
    ldrne r9,[r7,#node_height]
    sub r3,r8,r9
    cmp r3,#2
    bne 100f
    ldr r7,[r6,#node_right]
    cmp r7,#0
    moveq r8,#0
    ldrne r8,[r7,#node_height]
    ldr r7,[r6,#node_left]
    cmp r7,#0
    moveq r9,#0
    ldrne r9,[r7,#node_height]
    sub r3,r8,r9
    cmp r3,#-1
    ble 2f
    mov r0,r5
    bl rotLeft
    b 100f
2:
    mov r0,r6
    bl rotRight
    mov r0,r5
    bl rotLeft
    b 100f

100:
    pop {r1-r9,lr}                    @ restaur registers
    bx lr                             @ return
/******************************************************************/
/*     right rotation                                     */
/******************************************************************/
/* r0 contains the address of the node       */
rotRight:                           @ INFO: rotRight
    push {r1-r5,lr}                 @ save  registers
    //   r2                  r2
    //      r0                   r1
    //   r1                         r0
    //      r3                    r3
    ldr r1,[r0,#node_left]          @ load left children
    ldr r2,[r0,#node_parent]        @ load father
    cmp r2,#0                       @ no father ???
    beq 2f
    ldr r3,[r2,#node_left]          @ load left node father
    cmp r3,r0                       @ equal current node ?
    streq r1,[r2,#node_left]        @ yes store left children
    strne r1,[r2,#node_right]       @ no store right
2:
    str r2,[r1,#node_parent]        @ change parent
    str r1,[r0,#node_parent]
    ldr r3,[r1,#node_right]
    str r3,[r0,#node_left]
    cmp r3,#0
    strne r0,[r3,#node_parent]      @ change parent node left
    str r0,[r1,#node_right]

    ldr r3,[r0,#node_left]          @ compute newbalance factor
    cmp r3,#0
    moveq r4,#0
    ldrne r4,[r3,#node_height]
    ldr r3,[r0,#node_right]
    cmp r3,#0
    moveq r5,#0
    ldrne r5,[r3,#node_height]
    cmp r4,r5
    addgt r4,#1
    strgt r4,[r0,#node_height]
    addle r5,#1
    strle r5,[r0,#node_height]
//
    ldr r3,[r1,#node_left]         @ compute new balance factor
    cmp r3,#0
    moveq r4,#0
    ldrne r4,[r3,#node_height]
    ldr r3,[r1,#node_right]
    cmp r3,#0
    moveq r5,#0
    ldrne r5,[r3,#node_height]
    cmp r4,r5
    addgt r4,#1
    strgt r4,[r1,#node_height]
    addle r5,#1
    strle r5,[r1,#node_height]
100:
    pop {r1-r5,lr}                   @ restaur registers
    bx lr
/******************************************************************/
/*     left rotation                                     */
/******************************************************************/
/* r0 contains the address of the node  sommet     */
rotLeft:                             @ INFO: rotLeft
    push {r1-r5,lr}                  @ save  registers
    //   r2                  r2
    //      r0                   r1
    //          r1            r0
    //        r3                 r3
    ldr r1,[r0,#node_right]          @ load right children
    ldr r2,[r0,#node_parent]         @ load father (racine)
    cmp r2,#0                        @ no father ???
    beq 2f
    ldr r3,[r2,#node_left]           @ load left node father
    cmp r3,r0                        @ equal current node ?
    streq r1,[r2,#node_left]         @ yes store left children
    strne r1,[r2,#node_right]        @ no store to right
2:
    str r2,[r1,#node_parent]         @ change parent of right children
    str r1,[r0,#node_parent]         @ change parent of sommet
    ldr r3,[r1,#node_left]           @ left children
    str r3,[r0,#node_right]          @ left children pivot exists ?
    cmp r3,#0
    strne r0,[r3,#node_parent]       @ yes store in
    str r0,[r1,#node_left]
//
    ldr r3,[r0,#node_left]           @ compute new height for old summit
    cmp r3,#0
    moveq r4,#0
    ldrne r4,[r3,#node_height]       @ left height
    ldr r3,[r0,#node_right]
    cmp r3,#0
    moveq r5,#0
    ldrne r5,[r3,#node_height]       @ right height
    cmp r4,r5
    addgt r4,#1
    strgt r4,[r0,#node_height]       @ if right > left
    addle r5,#1
    strle r5,[r0,#node_height]       @ if left > right
//
    ldr r3,[r1,#node_left]           @ compute new height for new
    cmp r3,#0
    moveq r4,#0
    ldrne r4,[r3,#node_height]
    ldr r3,[r1,#node_right]
    cmp r3,#0
    moveq r5,#0
    ldrne r5,[r3,#node_height]
    cmp r4,r5
    addgt r4,#1
    strgt r4,[r1,#node_height]
    addle r5,#1
    strle r5,[r1,#node_height]
100:
    pop {r1-r5,lr}                        @ restaur registers
    bx lr
/******************************************************************/
/*     search value in tree                                       */
/******************************************************************/
/* r0 contains the address of structure of tree */
/* r1 contains the value to search  */
searchTree:                           @ INFO: searchTree
    push {r1-r4,lr}                   @ save  registers
    ldr r2,[r0,#tree_root]

1:                                    @ begin loop
    ldr r4,[r2,#node_value]           @ load key
    cmp r1,r4
    beq 3f                            @ key equal
    blt 2f                            @ key <
                                      @ key >  insertion right
    ldr r3,[r2,#node_right]           @ node empty ?
    cmp r3,#0
    movne r2,r3                       @ no -> next node
    bne 1b                            @ and loop
    mov r0,#-1                        @ not find
    b 100f
2:                                    @ left
    ldr r3,[r2,#node_left]            @ left pointer empty ?
    cmp r3,#0
    movne r2,r3                       @
    bne 1b                            @ no -> loop
    mov r0,#-1                        @ not find
    b 100f
3:
    mov r0,r2                         @ return node address
100:
    pop {r1-r4,lr}                    @ restaur registers
    bx lr
/******************************************************************/
/*     suppression node                                           */
/******************************************************************/
/* r0 contains the address of the node */
/* r1 contains structure tree address  */
supprimer:                       @ INFO: supprimer
    push {r1-r8,lr}              @ save  registers
    ldr r1,[r0,#node_left]
    cmp r1,#0
    bne 5f
    ldr r1,[r0,#node_right]
    cmp r1,#0
    bne 5f
                                 @ is a leaf
    mov r4,#0
    ldr r3,[r0,#node_parent]     @ father
    cmp r3,#0
    streq r4,[r1,#tree_root]
    beq 100f
    ldr r1,[r3,#node_left]
    cmp r1,r0
    bne 2f
    str r4,[r3,#node_left]       @ suppression left children
    ldr r5,[r3,#node_right]
    cmp r5,#0
    moveq r6,#0
    ldrne r6,[r5,#node_height]
    add r6,#1
    str r6,[r3,#node_height]
    b 3f
2:                                @ suppression right children
    str r4,[r3,#node_right]
    ldr r5,[r3,#node_left]
    cmp r5,#0
    moveq r6,#0
    ldrne r6,[r5,#node_height]
    add r6,#1
    str r6,[r3,#node_height]
3:                                @ new balance
    mov r0,r3
    bl equilibrerSupp
    b 100f
5:                                @ is not à leaf
    ldr r7,[r0,#node_right]
    cmp r7,#0
    beq 7f
    mov r8,r0
    mov r0,r7
6:
    ldr r6,[r0,#node_left]
    cmp r6,#0
    movne r0,r6
    bne 6b
    b 9f
7:
    ldr r7,[r0,#node_left]         @ search the litle element
    cmp r7,#0
    beq 9f
    mov r8,r0
    mov r0,r7
8:
    ldr r6,[r0,#node_right]        @ search the great element
    cmp r6,#0
    movne r0,r6
    bne 8b
9:
    ldr r5,[r0,#node_value]         @ copy value
    str r5,[r8,#node_value]
    bl supprimer                    @ suppression node r0
100:
    pop {r1-r8,lr}                  @ restaur registers
    bx lr

/******************************************************************/
/*     equilibrer after suppression                                   */
/******************************************************************/
/* r0 contains the address of the node       */
/* r1 contains the address of head */
equilibrerSupp:                   @ INFO: equilibrerSupp
    push {r1-r8,lr}               @ save  registers
    mov r3,#1                     @ balance factor
    ldr r2,[r1,#tree_root]
1:
    ldr r5,[r0,#node_parent]      @ load father
    cmp r5,#0                     @ no father
    beq 100f
    cmp r3,#0                     @ balance equilibred
    beq 100f
    mov r6,r0                     @ save entry node
    ldr r0,[r6,#node_parent]      @ current = father
    ldr r7,[r0,#node_left]
    cmp r7,#0
    ldrne r8,[r7,#node_height]    @ height left tree
    moveq r8,#0
    ldr r7,[r0,#node_right]
    cmp r7,#0
    ldrne r9,[r7,#node_height]    @ height right tree
    moveq r9,#0
    cmp r8,r9
    addgt r8,#1
    strgt r8,[r0,#node_height]
    addle r9,#1
    strle r9,[r0,#node_height]
    //
    ldr r7,[r0,#node_right]
    cmp r7,#0
    ldrne r8,[r7,#node_height]
    moveq r8,#0
    ldr r7,[r0,#node_left]
    cmp r7,#0
    ldrne r9,[r7,#node_height]
    moveq r9,#0
    sub r3,r8,r9                   @ compute balance factor
    mov r2,r1
    mov r4,r0                      @ save current
    mov r1,r6
    bl equiUnSommet
                                   @ change head address ?
    cmp r2,r4
    streq r6,[r3,#tree_root]
    mov r0,r4                      @ restaur current
    b 1b

100:
    pop {r1-r8,lr}                  @ restaur registers
    bx lr                           @ return
/******************************************************************/
/*     preOrder                                  */
/******************************************************************/
/* r0 contains the address of the node */
/* r1 function address                 */
preOrder:                                 @ INFO: preOrder
    push {r1-r2,lr}                       @ save  registers
    cmp r0,#0
    beq 100f
    mov r2,r0
    blx r1                                @ call function

    ldr r0,[r2,#node_left]
    bl preOrder
    ldr r0,[r2,#node_right]
    bl preOrder
100:
    pop {r1-r2,lr}                        @ restaur registers
    bx lr

/******************************************************************/
/*     display node                                               */
/******************************************************************/
/* r0 contains node  address          */
displayElement:                        @ INFO: displayElement
    push {r1,r2,r3,lr}                 @ save  registers
    mov r2,r0
    ldr r1,iAdrsZoneConv
    bl conversion16
    mov r4,#0
    strb r4,[r1,r0]
    ldr r0,iAdrszMessResult
    ldr r1,iAdrsZoneConv
    bl strInsertAtCharInc
    mov r3,r0
    ldr r0,[r2,#node_left]
    ldr r1,iAdrsZoneConv
    bl conversion16
    mov r4,#0
    strb r4,[r1,r0]
    mov r0,r3
    ldr r1,iAdrsZoneConv
    bl strInsertAtCharInc
    mov r3,r0
    ldr r0,[r2,#node_right]
    ldr r1,iAdrsZoneConv
    bl conversion16
    mov r4,#0
    strb r4,[r1,r0]
    mov r0,r3
    ldr r1,iAdrsZoneConv
    bl strInsertAtCharInc
    mov r3,r0
    ldr r0,[r2,#node_value]
    ldr r1,iAdrsZoneConv
    bl conversion10
    mov r4,#0
    strb r4,[r1,r0]
    mov r0,r3
    ldr r1,iAdrsZoneConv
    bl strInsertAtCharInc
    mov r3,r0
    ldr r0,[r2,#node_height]
    ldr r1,iAdrsZoneConv
    bl conversion10
    mov r4,#0
    strb r4,[r1,r0]
    mov r0,r3
    ldr r1,iAdrsZoneConv
    bl strInsertAtCharInc
    mov r3,r0
    ldr r0,[r2,#node_parent]
    ldr r1,iAdrsZoneConv
    bl conversion16
    mov r4,#0
    strb r4,[r1,r0]
    mov r0,r3
    ldr r1,iAdrsZoneConv
    bl strInsertAtCharInc
    bl affichageMess
100:
    pop {r1,r2,r3,lr}                        @ restaur registers
    bx lr                              @ return
iAdrszMessResult:          .int szMessResult
iAdrsZoneConv:             .int sZoneConv
iAdrsValue:                .int sValue

/******************************************************************/
/*     memory allocation on the heap                                  */
/******************************************************************/
/* r0 contains the size to allocate */
/* r0 returns address of memory heap or - 1 if error */
/* CAUTION : The size of the allowance must be a multiple of 4  */
allocHeap:
    push {r5-r7,lr}                   @ save  registers
    @ allocation
    mov r6,r0                         @ save size
    mov r0,#0                         @ read address start heap
    mov r7,#0x2D                      @ call system 'brk'
    svc #0
    mov r5,r0                         @ save address heap for return
    add r0,r6                         @ reservation place for size
    mov r7,#0x2D                      @ call system 'brk'
    svc #0
    cmp r0,#-1                        @ allocation error
    movne r0,r5                       @ return address memory heap
    pop {r5-r7,lr}                    @ restaur registers
    bx lr                             @ return
/***************************************************/
/*      ROUTINES INCLUDE                 */
/***************************************************/
.include "../affichage.inc"