340 lines
12 KiB
Text
340 lines
12 KiB
Text
/* ARM assembly Raspberry PI */
|
|
/* program longmulti.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 */
|
|
|
|
/* REMARK 2 : this program use factors unsigned to 2 power 95
|
|
and the result is less than 2 power 159 */
|
|
|
|
|
|
/* for constantes see task include a file in arm assembly */
|
|
/************************************/
|
|
/* Constantes */
|
|
/************************************/
|
|
.include "../constantes.inc"
|
|
.equ BUFFERSIZE, 64
|
|
|
|
/***********************************************/
|
|
/* structures */
|
|
/**********************************************/
|
|
/* Définition multi128 */
|
|
.struct 0
|
|
multi128_N1: // 31-0
|
|
.struct multi128_N1 + 4
|
|
multi128_N2: // 63-32
|
|
.struct multi128_N2 + 4
|
|
multi128_N3: // 95-64
|
|
.struct multi128_N3 + 4
|
|
multi128_N4: // 127-96
|
|
.struct multi128_N4 + 4
|
|
multi128_N5: // 159-128
|
|
.struct multi128_N5 + 4
|
|
multi128_end:
|
|
/*********************************/
|
|
/* Initialized data */
|
|
/*********************************/
|
|
.data
|
|
szMessFactor: .asciz "Factor = "
|
|
szMessResult: .asciz "Result = "
|
|
szMessStart: .asciz "Program 32 bits start.\n"
|
|
szCarriageReturn: .asciz "\n"
|
|
|
|
i128test1: .int 0,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 r0,iAdrszMessStart
|
|
bl affichageMess
|
|
ldr r0,iAdri128test1 @ origin number
|
|
ldr r1,iAdrsZoneConv
|
|
mov r2,#BUFFERSIZE
|
|
bl convertMultiForString @ convert multi number to string
|
|
mov r2,r0 @ insert conversion in message
|
|
mov r0,#3 @ string number to display
|
|
ldr r1,iAdrszMessFactor
|
|
ldr r3,iAdrszCarriageReturn
|
|
bl displayStrings @ display message
|
|
@ multiplication
|
|
ldr r0,iAdri128test1 @ factor 1
|
|
ldr r1,iAdri128test1 @ factor 2
|
|
ldr r2,iAdri128Result1 @ result
|
|
bl multiplierMulti128
|
|
ldr r0,iAdri128Result1
|
|
ldr r1,iAdrsZoneConv
|
|
mov r2,#BUFFERSIZE
|
|
bl convertMultiForString @ conversion multi to string
|
|
mov r2,r0 @ insert conversion in message
|
|
mov r0,#3 @ number string to display
|
|
ldr r1,iAdrszMessResult
|
|
ldr r3,iAdrszCarriageReturn
|
|
bl displayStrings @ display message
|
|
|
|
100: @ standard end of the program
|
|
mov r0, #0 @ return code
|
|
mov r7, #EXIT @ request to exit program
|
|
svc #0 @ perform the system call
|
|
|
|
iAdrszCarriageReturn: .int szCarriageReturn
|
|
iAdrsZoneConv: .int sZoneConv
|
|
iAdri128test1: .int i128test1
|
|
iAdri128Result1: .int i128Result1
|
|
iAdrszMessResult: .int szMessResult
|
|
iAdrszMessFactor: .int szMessFactor
|
|
iAdrszMessStart: .int szMessStart
|
|
/***************************************************/
|
|
/* multiplication multi128 by multi128 */
|
|
/***************************************************/
|
|
// r0 contains address multi128 1
|
|
// r1 contains address multi128 2
|
|
// r2 contains address result multi128
|
|
// r0 return address result (= r2)
|
|
multiplierMulti128:
|
|
push {r1-r10,lr} @ save registers
|
|
mov r9,r0 @ factor 1
|
|
mov r10,r1 @ factor 2
|
|
mov r7,r2 @ address result
|
|
mov r6,#4 @ multi128 size
|
|
mov r5,#0
|
|
1:
|
|
str r5,[r7,r6,lsl #2] @ init result
|
|
subs r6,r6,#1
|
|
bge 1b
|
|
mov r5,#0 @ indice loop 1
|
|
2: @ loop items factor 1
|
|
ldr r0,[r9,r5,lsl #2] @ load a item
|
|
mov r4,#0
|
|
mov r8,#0
|
|
3: @ loop item factor 2
|
|
add r6,r4,r5 @ compute result indice
|
|
|
|
ldr r1,[r10,r4,lsl #2] @ oad a item factor 2
|
|
umull r2,r3,r1,r0 @ multiply long 32 bits
|
|
ldr r1,[r7,r6,lsl #2] @ load previous item of result
|
|
adds r1,r1,r2 @ add low part result multiplication
|
|
movcc r2,#0 @ high retain
|
|
movcs r2,#1
|
|
adds r1,r1,r8 @ add high part precedente
|
|
adc r8,r3,r2 @ new high part with retenue
|
|
str r1,[r7,r6,lsl #2] @ store the sum in result
|
|
|
|
add r4,r4,#1
|
|
cmp r4,#3
|
|
blt 3b @ and loop 2
|
|
cmp r8,#0 @ high part ?
|
|
beq 4f
|
|
add r6,r6,#1
|
|
cmp r6,#4 @ on last item ?
|
|
strle r8,[r7,r6,lsl #2] @ no store high part in next item
|
|
ble 4f
|
|
adr r0,szMessErrOverflow @ yes -> overflow
|
|
bl affichageMess
|
|
mov r0,#0 @ return 0
|
|
b 100f
|
|
4:
|
|
add r5,r5,#1
|
|
cmp r5,#3
|
|
blt 2b @ and loop 1
|
|
mov r0,r7
|
|
|
|
100:
|
|
pop {r1-r10,pc} @ restaur registers
|
|
szMessErrOverflow: .asciz "\033[31mOverflow !!\033[0m \n"
|
|
.align 4
|
|
/***************************************************/
|
|
/* display multi strings */
|
|
/***************************************************/
|
|
/* r0 contains number strings address */
|
|
/* r1 address string1 */
|
|
/* r2 address string2 */
|
|
/* r3 address string3 */
|
|
/* other address on the stack */
|
|
/* thinck to add number other address * 4 to add to the stack */
|
|
displayStrings: @ INFO: displayStrings
|
|
push {r1-r4,fp,lr} @ save des registres
|
|
add fp,sp,#24 @ save paraméters address (6 registers saved * 4 bytes)
|
|
mov r4,r0 @ save strings number
|
|
cmp r4,#0 @ 0 string -> end
|
|
ble 100f
|
|
mov r0,r1 @ string 1
|
|
bl affichageMess
|
|
cmp r4,#1 @ number > 1
|
|
ble 100f
|
|
mov r0,r2
|
|
bl affichageMess
|
|
cmp r4,#2
|
|
ble 100f
|
|
mov r0,r3
|
|
bl affichageMess
|
|
cmp r4,#3
|
|
ble 100f
|
|
mov r3,#3
|
|
sub r2,r4,#4
|
|
1: @ loop extract address string on stack
|
|
ldr r0,[fp,r2,lsl #2]
|
|
bl affichageMess
|
|
subs r2,#1
|
|
bge 1b
|
|
100:
|
|
pop {r1-r4,fp,pc}
|
|
/***************************************************/
|
|
/* conversion multi128 unsigned to string */
|
|
/***************************************************/
|
|
// r0 contains address multi128
|
|
// r1 contains address buffer
|
|
// r2 contains buffer length
|
|
convertMultiForString:
|
|
push {r1-r5,fp,lr} @ save des registres
|
|
sub sp,sp,#multi128_end @ reserve place to stack
|
|
mov fp,sp @ init address to quotient
|
|
mov r5,r1 @ save address buffer
|
|
mov r3,#0 @ init indice
|
|
1:
|
|
ldr r4,[r0,r3,lsl #2] @ load one part of number
|
|
str r4,[fp,r3,lsl #2] @ copy part on stack
|
|
add r3,#1
|
|
cmp r3,#5
|
|
blt 1b
|
|
|
|
2:
|
|
mov r0,#0
|
|
strb r0,[r5,r2] @ store final 0 in buffer
|
|
sub r4,r2,#1 @ end number storage
|
|
3:
|
|
mov r0,fp
|
|
mov r1,#10
|
|
bl calculerModuloMultiEntier @ compute modulo 10
|
|
add r0,r0,#0x30 @ convert result to character
|
|
strb r0,[r5,r4] @ store character on buffer
|
|
subs r4,r4,#1 @
|
|
blt 99f @ buffer too low
|
|
ldr r0,[fp,#multi128_N1] @ test if quotient = zero
|
|
cmp r0,#0
|
|
bne 3b
|
|
ldr r0,[fp,#multi128_N2]
|
|
cmp r0,#0
|
|
bne 3b
|
|
ldr r0,[fp,#multi128_N3]
|
|
cmp r0,#0
|
|
bne 3b
|
|
ldr r0,[fp,#multi128_N4]
|
|
cmp r0,#0
|
|
bne 3b
|
|
ldr r0,[fp,#multi128_N5]
|
|
cmp r0,#0
|
|
bne 3b
|
|
|
|
add r0,r5,r4 @ return begin number in buffer
|
|
add r0,r0,#1
|
|
b 100f
|
|
99: @ display error if buffer est toop low
|
|
adr r0,szMessErrBuffer
|
|
bl affichageMess
|
|
mov r0,#-1
|
|
100:
|
|
add sp,sp,#multi128_end @ stack alignement
|
|
pop {r1-r5,fp,pc} @ restaur registers
|
|
szMessErrBuffer: .asciz "\033[31mBuffer de conversion trop petit !!\033[0m \n"
|
|
.align 4
|
|
/***************************************************/
|
|
/* modulo compute unsigned */
|
|
/***************************************************/
|
|
// r0 contains address multi128
|
|
// r1 contains modulo (positive)
|
|
// r0 return modulo
|
|
// ATTENTION : le multientier origine est modifié et contient le quotient
|
|
calculerModuloMultiEntier: @ INFO: calculerModuloMultiEntier
|
|
push {r1-r5,lr} @ save des registres
|
|
cmp r1,#0
|
|
ble 99f
|
|
mov r4,r1 @ save modulo
|
|
mov r3,#4
|
|
mov r5,r0 @ multi128 address
|
|
ldr r0,[r5,r3,lsl #2] @ load last part of number in low part of 64 bits
|
|
mov r1,#0 @ init higt part 64 bits
|
|
1:
|
|
cmp r3,#0 @ end part ?
|
|
ble 2f
|
|
mov r2,r4 @ modulo
|
|
bl division32R @ divide r0,r1 by r2 in r0,r1 and remainder in r2
|
|
str r0,[r5,r3,lsl #2] @ store result part low
|
|
sub r3,r3,#1 @ other part ?
|
|
ldr r0,[r5,r3,lsl #2] @ load prev part
|
|
mov r1,r2 @ store remainder un high part of 64 bits
|
|
b 1b
|
|
2:
|
|
mov r2,r4 @ modulo
|
|
bl division32R
|
|
str r0,[r5] @ stockage dans le 1er chunk
|
|
mov r0,r2 @ return remainder
|
|
b 100f
|
|
99:
|
|
adr r0,szMessNegatif
|
|
bl affichageMess
|
|
mov r0,#-1
|
|
100: @ fin standard de la fonction
|
|
pop {r1-r5,pc} @ restaur des registres
|
|
szMessNegatif: .asciz "\033[31mLe diviseur doit être positif !\033[0m\n"
|
|
.align 4
|
|
/***************************************************/
|
|
/* division 64 bits number in 2 registers by 32 bits number */
|
|
/***************************************************/
|
|
/* r0 contains dividende low part */
|
|
/* r1 contains dividende high part */
|
|
/* r2 contains divisor */
|
|
/* r0 return quotient low part */
|
|
/* r1 return quotient high part */
|
|
/* r2 return remainder */
|
|
division32R:
|
|
push {r3-r7,lr} @ save registers
|
|
mov r6,#0 @ init high high part of remainder !!
|
|
@ r1 = high part of number in high part of remainder
|
|
mov r7,r0 @ low part of number in low part of remainder
|
|
mov r3,#0 @ init high part quotient
|
|
mov r4,#0 @ init low part quotient
|
|
mov r5,#32
|
|
1: @ begin loop
|
|
lsl r6,#1 @ left shift high high part of remainder
|
|
lsls r1,#1 @ left shift high part of remainder
|
|
orrcs r6,#1 @ add left bit high part on high high part
|
|
lsls r7,#1 @ left shift low part of remainder
|
|
orrcs r1,#1 @ add left bit low part on high part
|
|
lsls r4,#1 @ left shift low part quotient
|
|
lsl r3,#1 @ left shift high part quotient
|
|
orrcs r3,#1 @ add left bit low part on high part
|
|
@ sub divisor to high part remainder
|
|
subs r1,r2
|
|
sbcs r6,#0 @ sub restraint (retenue in french)
|
|
bmi 2f @ result negative ?
|
|
|
|
@ positive or equal
|
|
orr r4,#1 @ right bit quotient to 1
|
|
b 3f
|
|
2: @ negative
|
|
orr r4,#0 @ right bit quotient to 0
|
|
adds r1,r2 @ and restaure the remainder to precedent value
|
|
adc r6,#0 @ and restraint
|
|
3:
|
|
subs r5,#1 @ decrement indice
|
|
bgt 1b @ and loop
|
|
mov r0,r4 @ low part quotient
|
|
mov r2,r1 @ remainder
|
|
mov r1,r3 @ high part quotient
|
|
100: @
|
|
pop {r3-r7,pc} @ restaur registers
|
|
/***************************************************/
|
|
/* ROUTINES INCLUDE */
|
|
/***************************************************/
|
|
.include "../affichage.inc"
|