362 lines
13 KiB
Text
362 lines
13 KiB
Text
/* ARM assembly AARCH64 Raspberry PI 3B */
|
|
/* program longmulti64.s */
|
|
/* REMARK : this program use factors unsigned to 2 power 127
|
|
and the result is less than 2 power 255 */
|
|
/************************************/
|
|
/* Constantes */
|
|
/************************************/
|
|
/* for this file see task include a file in language AArch64 assembly*/
|
|
.include "../includeConstantesARM64.inc"
|
|
.equ BUFFERSIZE, 100
|
|
|
|
/***********************************************/
|
|
/* structures */
|
|
/**********************************************/
|
|
/* Définition multi128 */
|
|
.struct 0
|
|
multi128_N1: // 63-0
|
|
.struct multi128_N1 + 8
|
|
multi128_N2: // 127-64
|
|
.struct multi128_N2 + 8
|
|
multi128_N3: // 128-191
|
|
.struct multi128_N3 + 8
|
|
multi128_N4: // 192-255
|
|
.struct multi128_N4 + 8
|
|
multi128_end:
|
|
/*********************************/
|
|
/* Initialized data */
|
|
/*********************************/
|
|
.data
|
|
szMessFactor: .asciz "Factor = "
|
|
szMessResult: .asciz "Result = "
|
|
szMessStart: .asciz "Program 64 bits start.\n"
|
|
szCarriageReturn: .asciz "\n"
|
|
|
|
i128test1: .quad 0,1,0,0 // 2 power 64
|
|
/*********************************/
|
|
/* UnInitialized data */
|
|
/*********************************/
|
|
.bss
|
|
sZoneConv: .skip BUFFERSIZE // conversion buffer
|
|
i128Result1: .skip multi128_end
|
|
|
|
/*********************************/
|
|
/* code section */
|
|
/*********************************/
|
|
.text
|
|
.global main
|
|
main: // entry of program
|
|
ldr x0,qAdrszMessStart
|
|
bl affichageMess
|
|
ldr x0,qAdri128test1 // origin number
|
|
ldr x1,qAdrsZoneConv
|
|
mov x2,#BUFFERSIZE
|
|
bl convertMultiForString // convert multi number to string
|
|
mov x2,x0 // insert conversion in message
|
|
mov x0,#3 // string number to display
|
|
ldr x1,qAdrszMessFactor
|
|
ldr x3,qAdrszCarriageReturn
|
|
bl displayStrings // display message
|
|
|
|
// multiplication
|
|
ldr x0,qAdri128test1 // factor 1
|
|
ldr x1,qAdri128test1 // factor 2
|
|
ldr x2,qAdri128Result1 // result
|
|
bl multiplierMulti128
|
|
ldr x0,qAdri128Result1
|
|
ldr x1,qAdrsZoneConv
|
|
mov x2,#BUFFERSIZE
|
|
bl convertMultiForString // conversion multi to string
|
|
mov x2,x0 // insert conversion in message
|
|
mov x0,#3 // number string to display
|
|
ldr x1,qAdrszMessResult
|
|
ldr x3,qAdrszCarriageReturn
|
|
bl displayStrings // display message
|
|
|
|
100: // standard end of the program
|
|
mov x0, #0 // return code
|
|
mov x8,EXIT
|
|
svc #0 // perform the system call
|
|
|
|
qAdrszCarriageReturn: .quad szCarriageReturn
|
|
qAdrsZoneConv: .quad sZoneConv
|
|
qAdri128test1: .quad i128test1
|
|
qAdri128Result1: .quad i128Result1
|
|
qAdrszMessResult: .quad szMessResult
|
|
qAdrszMessFactor: .quad szMessFactor
|
|
qAdrszMessStart: .quad szMessStart
|
|
/***************************************************/
|
|
/* multiplication multi128 by multi128 */
|
|
/***************************************************/
|
|
// x0 contains address multi128 1
|
|
// x1 contains address multi128 2
|
|
// x2 contains address result multi128
|
|
// x0 return address result (= x2)
|
|
multiplierMulti128:
|
|
stp x1,lr,[sp,-16]! // save registers
|
|
mov x9,x0 // factor 1
|
|
mov x10,x1 // factor 2
|
|
mov x7,x2 // address result
|
|
mov x6,#3 // multi128 size
|
|
1:
|
|
str xzr,[x7,x6,lsl #3] // init result
|
|
subs x6,x6,#1
|
|
bge 1b
|
|
mov x5,#0 // indice loop 1
|
|
2: // loop items factor 1
|
|
ldr x0,[x9,x5,lsl #3] // load a item
|
|
mov x4,#0
|
|
mov x8,#0
|
|
3: // loop item factor 2
|
|
add x6,x4,x5 // compute result indice
|
|
|
|
ldr x1,[x10,x4,lsl #3] // load a item factor 2
|
|
mul x2,x1,x0 // multiply low 64 bits
|
|
umulh x3,x1,x0 // multiply high 64 bits
|
|
ldr x1,[x7,x6,lsl #3] // load previous item of result
|
|
adds x1,x1,x2 // add low part result multiplication
|
|
mov x11,1
|
|
csel x2,x11,xzr,cs
|
|
adds x1,x1,x8 // add high part precedente
|
|
adc x8,x3,x2 // new high part with retenue
|
|
str x1,[x7,x6,lsl #3] // store the sum in result
|
|
|
|
add x4,x4,#1
|
|
cmp x4,#3
|
|
blt 3b // and loop 2
|
|
cmp x8,#0 // high part ?
|
|
beq 5f
|
|
add x6,x6,#1
|
|
cmp x6,#2 // on last item ?
|
|
ble 4f
|
|
adr x0,szMessErrOverflow // yes -> overflow
|
|
bl affichageMess
|
|
mov x0,#0 // return 0
|
|
b 100f
|
|
4:
|
|
str x8,[x7,x6,lsl #3] // no store high part in next item
|
|
5:
|
|
add x5,x5,#1
|
|
cmp x5,#3
|
|
blt 2b // and loop 1
|
|
mov x0,x7
|
|
|
|
100:
|
|
ldp x1,lr,[sp],16 // restaur registers
|
|
ret
|
|
szMessErrOverflow: .asciz "\033[31mOverflow !!\033[0m \n"
|
|
.align 4
|
|
|
|
/***************************************************/
|
|
/* conversion multi128 unsigned to string */
|
|
/***************************************************/
|
|
// x0 contains address multi128
|
|
// x1 contains address buffer
|
|
// x2 contains buffer length
|
|
convertMultiForString:
|
|
stp x1,lr,[sp,-16]! // save registers
|
|
stp x2,x3,[sp,-16]! // save registers
|
|
stp x4,x5,[sp,-16]! // save registers
|
|
sub sp,sp,#multi128_end // reserve place to stack
|
|
mov fp,sp // init address to quotient
|
|
mov x5,x1 // save address buffer
|
|
mov x3,#0 // init indice
|
|
1:
|
|
ldr x4,[x0,x3,lsl #3] // load one part of number
|
|
str x4,[fp,x3,lsl #3] // copy part on stack
|
|
add x3,x3,#1
|
|
cmp x3,#4
|
|
blt 1b
|
|
|
|
2:
|
|
strb wzr,[x5,x2] // store final 0 in buffer
|
|
sub x4,x2,#1 // end number storage
|
|
3:
|
|
mov x0,fp
|
|
mov x1,#10
|
|
bl calculerModuloMultiEntier // compute modulo 10
|
|
add x0,x0,#0x30 // convert result to character
|
|
strb w0,[x5,x4] // store character on buffer
|
|
subs x4,x4,#1 //
|
|
blt 99f // buffer too low
|
|
ldr x0,[fp,#multi128_N1] // test if quotient = zero
|
|
cmp x0,#0
|
|
bne 3b
|
|
ldr x0,[fp,#multi128_N2]
|
|
cmp x0,#0
|
|
bne 3b
|
|
ldr x0,[fp,#multi128_N3]
|
|
cmp x0,#0
|
|
bne 3b
|
|
ldr x0,[fp,#multi128_N4]
|
|
cmp x0,#0
|
|
bne 3b
|
|
|
|
|
|
add x0,x5,x4 // return begin number in buffer
|
|
add x0,x0,#1
|
|
b 100f
|
|
99: // display error if buffer est toop low
|
|
adr x0,szMessErrBuffer
|
|
bl affichageMess
|
|
mov x0,#-1
|
|
100:
|
|
add sp,sp,#multi128_end // stack alignement
|
|
ldp x4,x5,[sp],16 // restaur registers
|
|
ldp x2,x3,[sp],16 // restaur registers
|
|
ldp x1,lr,[sp],16 // restaur registers
|
|
ret
|
|
szMessErrBuffer: .asciz "\033[31mBuffer de conversion trop petit !!\033[0m \n"
|
|
.align 4
|
|
/***************************************************/
|
|
/* modulo compute unsigned */
|
|
/***************************************************/
|
|
// x0 contains address multi128
|
|
// x1 contains modulo (positive)
|
|
// x0 return modulo
|
|
// ATTENTION : le multientier origine est modifié et contient le quotient
|
|
calculerModuloMultiEntier: // INFO: calculerModuloMultiEntier
|
|
stp x1,lr,[sp,-16]! // save registers
|
|
stp x2,x3,[sp,-16]! // save registers
|
|
stp x4,x5,[sp,-16]! // save registers
|
|
cmp x1,#0
|
|
ble 99f
|
|
mov x4,x1 // save modulo
|
|
mov x3,#3
|
|
mov x5,x0 // multi128 address
|
|
ldr x0,[x5,x3,lsl 3] // load last part of number in low part of 128 bits
|
|
mov x1,#0 // init higt part 128 bits
|
|
1:
|
|
cmp x3,#0 // end part ?
|
|
ble 2f
|
|
mov x2,x4 // modulo
|
|
bl division64R // divide x0,x1 by x2 in x0,x1 and remainder in x2
|
|
str x0,[x5,x3,lsl #3] // store result part low
|
|
sub x3,x3,#1 // other part ?
|
|
ldr x0,[x5,x3,lsl #3] // load prev part
|
|
mov x1,x2 // store remainder on high part of 128 bits
|
|
b 1b
|
|
2:
|
|
mov x2,x4 // modulo
|
|
bl division64R
|
|
str x0,[x5] // stockage dans le 1er chunk
|
|
mov x0,x2 // return remainder
|
|
b 100f
|
|
99:
|
|
adr x0,szMessNegatif
|
|
bl affichageMess
|
|
mov x0,#-1
|
|
100: // fin standard de la fonction
|
|
ldp x4,x5,[sp],16 // restaur registers
|
|
ldp x2,x3,[sp],16 // restaur registers
|
|
ldp x1,lr,[sp],16 // restaur registers
|
|
ret
|
|
szMessNegatif: .asciz "\033[31mLe diviseur doit être positif !\033[0m\n"
|
|
.align 4
|
|
/***************************************************/
|
|
/* division 128 bits number in 2 registers by 64 bits number */
|
|
/***************************************************/
|
|
/* x0 contains dividende low part */
|
|
/* x1 contains dividende high part */
|
|
/* x2 contains divisor */
|
|
/* x0 return quotient low part */
|
|
/* x1 return quotient high part */
|
|
/* x2 return remainder */
|
|
division64R:
|
|
stp x3,lr,[sp,-16]! // save registers
|
|
stp x4,x5,[sp,-16]! // save registers
|
|
stp x6,x7,[sp,-16]! // save registers
|
|
stp x8,x9,[sp,-16]! // save registers
|
|
mov x6,#0 // init high high part of remainder !!
|
|
// x1 = high part of number in high part of remainder
|
|
mov x7,x0 // low part of number in low part of remainder
|
|
mov x3,#0 // init high part quotient
|
|
mov x4,#0 // init low part quotient
|
|
mov x5,#64
|
|
1: // begin loop
|
|
lsl x6,x6,#1 // left shift high high part of remainder
|
|
cmp x1,0 // if negative ie bit 63 = 1
|
|
orr x8,x6,1
|
|
csel x6,x8,x6,lt // add left bit high part on high high part
|
|
lsl x1,x1,#1 // left shift high part of remainder
|
|
cmp x7,0
|
|
orr x8,x1,1
|
|
csel x1,x8,x1,lt // add left bit low part on high part
|
|
lsl x7,x7,#1 // left shift low part of remainder
|
|
cmp x4,0
|
|
lsl x4,x4,#1 // left shift low part quotient
|
|
lsl x3,x3,#1 // left shift high part quotient
|
|
orr x8,x3,1
|
|
csel x3,x8,x3,lt // add left bit low part on high part
|
|
// sub divisor to high part remainder
|
|
subs x1,x1,x2
|
|
sbcs x6,x6,xzr // sub restr.quad (retenue in french)
|
|
bmi 2f // result negative ?
|
|
// positive or equal
|
|
orr x4,x4,#1 // right bit quotient to 1
|
|
b 3f
|
|
2: // negative
|
|
orr x4,x4,xzr // right bit quotient to 0
|
|
adds x1,x1,x2 // and restaure the remainder to precedent value
|
|
adc x6,x6,xzr // and restr.quad
|
|
3:
|
|
subs x5,x5,#1 // decrement indice
|
|
bgt 1b // and loop
|
|
mov x0,x4 // low part quotient
|
|
mov x2,x1 // remainder
|
|
mov x1,x3 // high part quotient
|
|
100:
|
|
ldp x8,x9,[sp],16 // restaur registers
|
|
ldp x6,x7,[sp],16 // restaur registers
|
|
ldp x4,x5,[sp],16 // restaur registers
|
|
ldp x3,lr,[sp],16 // restaur registers
|
|
ret
|
|
/***************************************************/
|
|
/* display multi strings */
|
|
/* new version 24/05/2023 */
|
|
/***************************************************/
|
|
/* x0 contains number strings address */
|
|
/* x1 address string1 */
|
|
/* x2 address string2 */
|
|
/* x3 address string3 */
|
|
/* x4 address string4 */
|
|
/* x5 address string5 */
|
|
/* x6 address string5 */
|
|
displayStrings: // INFO: displayStrings
|
|
stp x7,lr,[sp,-16]! // save registers
|
|
stp x2,fp,[sp,-16]! // save registers
|
|
add fp,sp,#32 // save paraméters address (4 registers saved * 8 bytes)
|
|
mov x7,x0 // save strings number
|
|
cmp x7,#0 // 0 string -> end
|
|
ble 100f
|
|
mov x0,x1 // string 1
|
|
bl affichageMess
|
|
cmp x7,#1 // number > 1
|
|
ble 100f
|
|
mov x0,x2
|
|
bl affichageMess
|
|
cmp x7,#2
|
|
ble 100f
|
|
mov x0,x3
|
|
bl affichageMess
|
|
cmp x7,#3
|
|
ble 100f
|
|
mov x0,x4
|
|
bl affichageMess
|
|
cmp x7,#4
|
|
ble 100f
|
|
mov x0,x5
|
|
bl affichageMess
|
|
cmp x7,#5
|
|
ble 100f
|
|
mov x0,x6
|
|
bl affichageMess
|
|
100:
|
|
ldp x2,fp,[sp],16 // restaur registers
|
|
ldp x7,lr,[sp],16 // restaur registers
|
|
ret
|
|
/***************************************************/
|
|
/* ROUTINES INCLUDE */
|
|
/***************************************************/
|
|
/* for this file see task include a file in language AArch64 assembly*/
|
|
.include "../includeARM64.inc"
|