Loops/Increment loop index within loop body: Difference between revisions
Content added Content deleted
m (updated the task's requirements to be a more clearer/accurate (courtesy N. G.).) |
(Add task to ARM assembly Raspberry pi) |
||
Line 259: | Line 259: | ||
n = 41 49752014150467 |
n = 41 49752014150467 |
||
n = 42 99504028301131 |
n = 42 99504028301131 |
||
</pre> |
|||
=={{header|ARM Assembly}}== |
|||
{{works with|as|Raspberry Pi}} |
|||
<lang ARM Assembly> |
|||
/* ARM assembly Raspberry PI */ |
|||
/* program loopinc96.s */ |
|||
/************************************/ |
|||
/* Constantes */ |
|||
/************************************/ |
|||
.equ STDOUT, 1 @ Linux output console |
|||
.equ EXIT, 1 @ Linux syscall |
|||
.equ WRITE, 4 @ Linux syscall |
|||
/*********************************/ |
|||
/* Initialized data */ |
|||
/*********************************/ |
|||
.data |
|||
szMessMultOver: .asciz "Multiplication 64 : Dépassement de capacité.\n" |
|||
sMessResult: .ascii "Index : " |
|||
sMessIndex: .fill 11, 1, ' ' @ size => 11 |
|||
.ascii "Value : " |
|||
sMessValeur: .fill 21, 1, ' ' @ size => 21 |
|||
szCarriageReturn: .asciz "\n" |
|||
/*********************************/ |
|||
/* UnInitialized data */ |
|||
/*********************************/ |
|||
.bss |
|||
/*********************************/ |
|||
/* code section */ |
|||
/*********************************/ |
|||
.text |
|||
.global main |
|||
main: @ entry of program |
|||
mov r7,#0 @ counter |
|||
mov r5,#42 @ start index low bits |
|||
mov r6,#0 @ start index high bits |
|||
1: @ begin loop |
|||
mov r0,r5 |
|||
mov r1,r6 |
|||
bl isPrime @ prime ? |
|||
bcs 100f @ error overflow ? |
|||
cmp r0,#1 @ is prime ? |
|||
beq 2f @ yes |
|||
adds r5,#1 @ no -> increment index |
|||
addcs r6,#1 |
|||
b 1b @ and loop |
|||
2: @ display index and prime |
|||
add r7,#1 @ increment counter |
|||
mov r0,r7 |
|||
ldr r1,iAdrsMessIndex @ conversion index |
|||
bl conversion10 |
|||
mov r0,r5 |
|||
mov r1,r6 @ conversion value |
|||
ldr r2,iAdrsMessValeur |
|||
bl conversionRegDoubleU @ conversion double -> ascii |
|||
ldr r0,iAdrsMessResult |
|||
bl affichageMess |
|||
adds r5,r5 |
|||
add r6,r6 |
|||
addcs r6,#1 |
|||
cmp r7,#42 @ end ? |
|||
blt 1b @ no loop |
|||
100: @ standard end of the program |
|||
mov r0, #0 @ return code |
|||
mov r7, #EXIT @ request to exit program |
|||
svc #0 @ perform the system call |
|||
iAdrsMessIndex: .int sMessIndex |
|||
iAdrsMessValeur: .int sMessValeur |
|||
iAdrszCarriageReturn: .int szCarriageReturn |
|||
iAdrsMessResult: .int sMessResult |
|||
/******************************************************************/ |
|||
/* display text with size calculation */ |
|||
/******************************************************************/ |
|||
/* r0 contains the address of the message */ |
|||
affichageMess: |
|||
push {r0,r1,r2,r7,lr} @ save registres |
|||
mov r2,#0 @ counter length |
|||
1: @ loop length calculation |
|||
ldrb r1,[r0,r2] @ read octet start position + index |
|||
cmp r1,#0 @ if 0 its over |
|||
addne r2,r2,#1 @ else add 1 in the length |
|||
bne 1b @ and loop |
|||
@ so here r2 contains the length of the message |
|||
mov r1,r0 @ address message in r1 |
|||
mov r0,#STDOUT @ code to write to the standard output Linux |
|||
mov r7, #WRITE @ code call system "write" |
|||
svc #0 @ call systeme |
|||
pop {r0,r1,r2,r7,lr} @ restaur des 2 registres */ |
|||
bx lr @ return |
|||
/******************************************************************/ |
|||
/* Converting a register to a decimal unsigned */ |
|||
/******************************************************************/ |
|||
/* r0 contains value and r1 address area */ |
|||
/* r0 return size of result (no zero final in area) */ |
|||
/* area size => 11 bytes */ |
|||
.equ LGZONECAL, 10 |
|||
conversion10: |
|||
push {r1-r4,lr} @ save registers |
|||
mov r3,r1 |
|||
mov r2,#LGZONECAL |
|||
1: @ start loop |
|||
bl divisionpar10U @ unsigned r0 <- dividende. quotient ->r0 reste -> r1 |
|||
add r1,#48 @ digit |
|||
strb r1,[r3,r2] @ store digit on area |
|||
cmp r0,#0 @ stop if quotient = 0 |
|||
subne r2,#1 @ else previous position |
|||
bne 1b @ and loop |
|||
@ and move digit from left of area |
|||
mov r4,#0 |
|||
2: |
|||
ldrb r1,[r3,r2] |
|||
strb r1,[r3,r4] |
|||
add r2,#1 |
|||
add r4,#1 |
|||
cmp r2,#LGZONECAL |
|||
ble 2b |
|||
@ and move spaces in end on area |
|||
mov r0,r4 @ result length |
|||
mov r1,#' ' @ space |
|||
3: |
|||
strb r1,[r3,r4] @ store space in area |
|||
add r4,#1 @ next position |
|||
cmp r4,#LGZONECAL |
|||
ble 3b @ loop if r4 <= area size |
|||
100: |
|||
pop {r1-r4,lr} @ restaur registres |
|||
bx lr @return |
|||
/***************************************************/ |
|||
/* division par 10 unsigned */ |
|||
/***************************************************/ |
|||
/* r0 dividende */ |
|||
/* r0 quotient */ |
|||
/* r1 remainder */ |
|||
divisionpar10U: |
|||
push {r2,r3,r4, lr} |
|||
mov r4,r0 @ save value |
|||
//mov r3,#0xCCCD @ r3 <- magic_number lower raspberry 3 |
|||
//movt r3,#0xCCCC @ r3 <- magic_number higter raspberry 3 |
|||
ldr r3,iMagicNumber @ r3 <- magic_number raspberry 1 2 |
|||
umull r1, r2, r3, r0 @ r1<- Lower32Bits(r1*r0) r2<- Upper32Bits(r1*r0) |
|||
mov r0, r2, LSR #3 @ r2 <- r2 >> shift 3 |
|||
add r2,r0,r0, lsl #2 @ r2 <- r0 * 5 |
|||
sub r1,r4,r2, lsl #1 @ r1 <- r4 - (r2 * 2) = r4 - (r0 * 10) |
|||
pop {r2,r3,r4,lr} |
|||
bx lr @ leave function |
|||
iMagicNumber: .int 0xCCCCCCCD |
|||
/***************************************************/ |
|||
/* number is prime ? */ |
|||
/***************************************************/ |
|||
/* r0 contains low bytes of double */ |
|||
/* r1 contains high bytes of double */ |
|||
/* r0 returns 1 if prime else 0 */ |
|||
@2147483647 |
|||
@4294967297 |
|||
@131071 |
|||
isPrime: |
|||
push {r1-r5,lr} @ save registers |
|||
mov r4,r0 @ save double |
|||
mov r5,r1 |
|||
subs r2,r0,#1 @ exposant n - 1 |
|||
sbcs r3,r1,#0 |
|||
mov r0,#2 @ base 2 |
|||
mov r1,#0 |
|||
bl moduloPuR96 @ compute modulo |
|||
bcs 100f @ overflow error |
|||
cmp r0,#1 @ modulo <> 1 -> no prime |
|||
bne 90f |
|||
mov r0,#3 @ base 3 |
|||
mov r1,#0 |
|||
bl moduloPuR96 |
|||
bcs 100f @ overflow error |
|||
cmp r0,#1 |
|||
bne 90f |
|||
mov r0,#5 @ base 5 |
|||
mov r1,#0 |
|||
bl moduloPuR96 |
|||
bcs 100f @ overflow error |
|||
cmp r0,#1 |
|||
bne 90f |
|||
mov r0,#7 @ base 7 |
|||
mov r1,#0 |
|||
bl moduloPuR96 |
|||
bcs 100f @ overflow error |
|||
cmp r0,#1 |
|||
bne 90f |
|||
mov r0,#11 @ base 11 |
|||
mov r1,#0 |
|||
bl moduloPuR96 |
|||
bcs 100f @ overflow error |
|||
cmp r0,#1 |
|||
bne 90f |
|||
mov r0,#13 @ base 13 |
|||
mov r1,#0 |
|||
bl moduloPuR96 |
|||
bcs 100f @ overflow error |
|||
cmp r0,#1 |
|||
bne 90f |
|||
mov r0,#17 @ base 17 |
|||
mov r1,#0 |
|||
bl moduloPuR96 |
|||
bcs 100f @ overflow error |
|||
cmp r0,#1 |
|||
bne 90f |
|||
mov r0,#1 @ is prime |
|||
msr cpsr_f, #0 @ no error overflow zero -> flags |
|||
b 100f |
|||
90: |
|||
mov r0,#0 @ no prime |
|||
msr cpsr_f, #0 @ no error overflow zero -> flags |
|||
100: @ fin standard de la fonction |
|||
pop {r1-r5,lr} @ restaur registers |
|||
bx lr @ return |
|||
/********************************************************/ |
|||
/* compute b pow e modulo m */ |
|||
/* */ |
|||
/********************************************************/ |
|||
/* r0 base double low bits */ |
|||
/* r1 base double high bits */ |
|||
/* r2 exposant low bitss */ |
|||
/* r3 exposant high bits */ |
|||
/* r4 modulo low bits */ |
|||
/* r5 modulo high bits */ |
|||
/* r0 returns result low bits */ |
|||
/* r1 returns result high bits */ |
|||
/* if overflow , flag carry is set else is clear */ |
|||
moduloPuR96: |
|||
push {r2-r12,lr} @ save registers |
|||
cmp r0,#0 @ control low byte <> zero |
|||
bne 1f |
|||
cmp r1,#0 @ control high bytes <> zero |
|||
beq 100f |
|||
1: |
|||
mov r9,r4 @ modulo PB |
|||
mov r10,r5 @ modulo PH |
|||
mov r5,r2 @ exposant ** |
|||
mov r6,r3 @ exposant |
|||
mov r7,r0 @ base PB |
|||
mov r8,r1 @ base PH |
|||
mov r2,#0 |
|||
mov r3,r9 |
|||
mov r4,r10 |
|||
mov r11,#1 @ result PB |
|||
mov r12,#0 @ result PH |
|||
/* r0 contient partie basse dividende */ |
|||
/* r1 contient partie moyenne dividende */ |
|||
/* r2 contient partie haute du diviseur */ |
|||
/* r3 contient partie basse diviseur */ |
|||
/* r4 contient partie haute diviseur */ |
|||
/* r0 retourne partie basse du quotient */ |
|||
/* r1 retourne partie moyenne du quotient */ |
|||
/* r2 retourne partie haute du quotient */ |
|||
/* r3 retourne partie basse du reste */ |
|||
/* r4 retourne partie haute du reste */ |
|||
bl divisionReg96DU |
|||
mov r7,r3 @ base <- remainder |
|||
mov r8,r4 |
|||
2: |
|||
tst r5,#1 @ test du bit 0 |
|||
beq 3f |
|||
mov r0,r7 |
|||
mov r1,r8 |
|||
mov r2,r11 |
|||
mov r3,r12 |
|||
bl multiplicationR96U |
|||
bcs 100f @ error overflow |
|||
mov r3,r9 |
|||
mov r4,r10 |
|||
bl divisionReg96DU |
|||
mov r11,r3 @ result <- remainder |
|||
mov r12,r4 |
|||
3: |
|||
mov r0,r7 |
|||
mov r1,r8 |
|||
mov r2,r7 |
|||
mov r3,r8 |
|||
bl multiplicationR96U |
|||
bcs 100f @ error overflow |
|||
mov r3,r9 |
|||
mov r4,r10 |
|||
bl divisionReg96DU |
|||
mov r7,r3 @ base <- remainder |
|||
mov r8,r4 |
|||
lsr r5,#1 |
|||
lsrs r6,#1 |
|||
orrcs r5,#0x80000000 |
|||
cmp r5,#0 |
|||
bne 2b |
|||
cmp r6,#0 |
|||
bne 2b |
|||
mov r0,r11 |
|||
mov r1,r12 |
|||
msr cpsr_f, #0 @ no error overflow zero -> flags |
|||
100: @ end function |
|||
pop {r2-r12,lr} @ restaur registers |
|||
bx lr @ return |
|||
/***************************************************/ |
|||
/* multiplication 2 registers (64 bits) unsigned */ |
|||
/* result in 3 registers 96 bits */ |
|||
/***************************************************/ |
|||
/* r0 low bits number 1 */ |
|||
/* r1 high bits number 1 */ |
|||
/* r2 low bits number 2 */ |
|||
/* r3 high bits number 2 */ |
|||
/* r0 returns low bits résult */ |
|||
/* r1 returns median bits résult */ |
|||
/* r2 returns high bits résult */ |
|||
/* if overflow , flag carry is set else is clear */ |
|||
multiplicationR96U: |
|||
push {r3-r8,lr} @ save registers |
|||
umull r5,r6,r0,r2 @ mult low bits |
|||
umull r4,r8,r0,r3 @ mult low bits 1 high bits 2 |
|||
mov r0,r5 @ result low bits ok |
|||
adds r4,r6 @ add results |
|||
addcs r8,#1 @ carry |
|||
umull r6,r7,r1,r2 @ mult high bits 1 low bits 2 |
|||
adds r4,r6 @ add results |
|||
addcs r8,#1 @ carry |
|||
adds r8,r7 @ add results |
|||
bcs 99f @ overflow ? |
|||
umull r6,r7,r1,r3 @ mult high bits 1 high bits 2 |
|||
cmp r7,#0 @ error overflow ? |
|||
bne 99f |
|||
adds r8,r6 @ add results |
|||
bcs 99f @ error overflow |
|||
mov r1,r4 @ return median bytes |
|||
mov r2,r8 @ return high bytes |
|||
msr cpsr_f, #0 @ no error overflow zero -> flags |
|||
b 100f |
|||
99: @ display message overflow |
|||
ldr r0,iAdrszMessMultOver @ |
|||
bl affichageMess |
|||
mov r0,#0 |
|||
mov r1,#0 |
|||
msr cpsr_f, #1<<29 @ maj flag carry à 1 et tous les autres à 0 |
|||
100: @ end function |
|||
pop {r3-r8,lr} @ restaur registers |
|||
bx lr @ return |
|||
iAdrszMessMultOver: .int szMessMultOver |
|||
/***************************************************/ |
|||
/* division number (3 registers) 92 bits by number (2 registers) 64 bits */ |
|||
/* unsigned */ |
|||
/***************************************************/ |
|||
/* r0 low bits dividende */ |
|||
/* r1 median bits dividende */ |
|||
/* r2 high bits dividende */ |
|||
/* r3 low bits divisor */ |
|||
/* r4 high bits divis0r */ |
|||
/* r0 returns low bits quotient */ |
|||
/* r1 returns median bits quotient */ |
|||
/* r2 returns high bits quotien */ |
|||
/* r3 returns low bits remainder */ |
|||
/* r4 returns high bits remainder */ |
|||
/* remainder do not is 3 registers */ |
|||
divisionReg96DU: |
|||
push {r5-r10,lr} @ save registers |
|||
mov r7,r3 @ low bits divisor |
|||
mov r8,r4 @ high bits divisor |
|||
mov r4,r0 @ low bits dividende -> low bits quotient |
|||
mov r5,r1 @ median bits dividende -> median bits quotient |
|||
mov r6,r2 @ high bits dividende -> high bits quotient |
|||
@ |
|||
mov r0,#0 @ low bits remainder |
|||
mov r1,#0 @ median bits remainder |
|||
mov r2,#0 @ high bits remainder (not useful) |
|||
mov r9,#96 @ counter loop (32 bits * 3) |
|||
mov r10,#0 @ last bit |
|||
1: |
|||
lsl r2,#1 @ shift left high bits remainder |
|||
lsls r1,#1 @ shift left median bits remainder |
|||
orrcs r2,#1 @ left bit median -> right bit high |
|||
lsls r0,#1 @ shift left low bits remainder |
|||
orrcs r1,#1 @ left bit low -> right bit median |
|||
lsls r6,#1 @ shift left high bits quotient |
|||
orrcs r0,#1 @ left bit high -> right bit low remainder |
|||
lsls r5,#1 @ shift left median bits quotient |
|||
orrcs r6,#1 @ left bit median -> right bit high |
|||
lsls r4,#1 @ shift left low bits quotient |
|||
orrcs r5,#1 @ left bit low -> right bit median |
|||
orr r4,r10 @ last bit -> bit 0 quotient |
|||
mov r10,#0 @ raz du bit |
|||
@ compare remainder and divisor |
|||
cmp r2,#0 @ high bit remainder |
|||
bne 2f |
|||
cmp r1,r8 @ compare median bits |
|||
blo 3f @ lower |
|||
bhi 2f @ highter |
|||
cmp r0,r7 @ equal -> compare low bits |
|||
blo 3f @ lower |
|||
2: @ remainder > divisor |
|||
subs r0,r7 @ sub divisor of remainder |
|||
sbcs r1,r8 |
|||
mov r10,#0 @ reuse ponctuelle r10 |
|||
sbc r2,r2,r10 @ carry |
|||
mov r10,#1 @ last bit à 1 |
|||
3: |
|||
subs r9,#1 @ increment counter loop |
|||
bgt 1b @ and loop |
|||
lsl r6,#1 @ shift left high bits quotient |
|||
lsls r5,#1 @ shift left median bits quotient |
|||
orrcs r6,#1 @ left bit median -> right bit high |
|||
lsls r4,#1 @ shift left low bits quotient |
|||
orrcs r5,#1 @ left bit low -> right bit median |
|||
orr r4,r10 @ last bit -> bit 0 quotient |
|||
mov r3,r0 @ low bits remainder |
|||
mov r0,r4 @ low bits quotient |
|||
mov r4,r1 @ high bits remainder |
|||
mov r1,r5 @ median bits quotient |
|||
//mov r5,r2 |
|||
mov r2,r6 @ high bits quotient |
|||
100: @ end function |
|||
pop {r5-r10,lr} @ restaur registers |
|||
bx lr @ return |
|||
/***************************************************/ |
|||
/* Conversion double integer 64bits in ascii */ |
|||
/***************************************************/ |
|||
/* r0 contains low bits */ |
|||
/* r1 contains high bits */ |
|||
/* r2 contains address area */ |
|||
conversionRegDoubleU: |
|||
push {r0-r5,lr} @ save registers |
|||
mov r5,r2 |
|||
mov r4,#19 @ start location |
|||
mov r2,#10 @ conversion decimale |
|||
1: @ begin loop |
|||
bl divisionReg64U @ division by 10 |
|||
add r3,#48 @ -> digit ascii |
|||
strb r3,[r5,r4] @ store digit in area index r4 |
|||
sub r4,r4,#1 @ decrement index |
|||
cmp r0,#0 @ low bits quotient = zero ? |
|||
bne 1b @ no -> loop |
|||
cmp r1,#0 @ high bits quotient = zero ? |
|||
bne 1b @ no -> loop |
|||
@ spaces -> begin area |
|||
mov r3,#' ' @ space |
|||
2: |
|||
strb r3,[r5,r4] @ store space in area |
|||
subs r4,r4,#1 @ decrement index |
|||
bge 2b @ and loop if > zéro |
|||
100: @ end fonction |
|||
pop {r0-r5,lr} @ restaur registers |
|||
bx lr @ return |
|||
/***************************************************/ |
|||
/* division number 64 bits / number 32 bits */ |
|||
/***************************************************/ |
|||
/* r0 contains low bits dividende */ |
|||
/* r1 contains high bits dividente */ |
|||
/* r2 contains divisor */ |
|||
/* r0 returns low bits quotient */ |
|||
/* r1 returns high bits quotient */ |
|||
/* r3 returns remainder */ |
|||
divisionReg64U: |
|||
push {r4,r5,lr} @ save registers |
|||
mov r5,#0 @ raz remainder R |
|||
mov r3,#64 @ loop counter |
|||
mov r4,#0 @ last bit |
|||
1: |
|||
lsl r5,#1 @ shift left remainder one bit |
|||
lsls r1,#1 @ shift left high bits quotient one bit |
|||
orrcs r5,#1 @ and bit -> remainder |
|||
lsls r0,#1 @ shift left low bits quotient one bit |
|||
orrcs r1,#1 @ and left bit -> high bits |
|||
orr r0,r4 @ last bit quotient |
|||
mov r4,#0 @ raz last bit |
|||
cmp r5,r2 @ compare remainder divisor |
|||
subhs r5,r2 @ if highter sub divisor of remainder |
|||
movhs r4,#1 @ and 1 -> last bit |
|||
3: |
|||
subs r3,#1 @ decrement counter loop |
|||
bgt 1b @ and loop if not zero |
|||
lsl r1,#1 @ else shift left higt bits quotient |
|||
lsls r0,#1 @ and shift left low bits |
|||
orrcs r1,#1 |
|||
orr r0,r4 @ last bit quotient |
|||
mov r3,r5 |
|||
100: @ end function |
|||
pop {r4,r5,lr} @ restaur registers |
|||
bx lr @ return |
|||
</lang> |
|||
{{out}} |
|||
<Pre> |
|||
pi@raspberrypi:~/asm/rosetta/ASS3 $ loopsinc96 |
|||
Index : 1 Value : 43 |
|||
Index : 2 Value : 89 |
|||
Index : 3 Value : 179 |
|||
Index : 4 Value : 359 |
|||
Index : 5 Value : 719 |
|||
Index : 6 Value : 1439 |
|||
Index : 7 Value : 2879 |
|||
Index : 8 Value : 5779 |
|||
Index : 9 Value : 11579 |
|||
Index : 10 Value : 23159 |
|||
Index : 11 Value : 46327 |
|||
Index : 12 Value : 92657 |
|||
Index : 13 Value : 185323 |
|||
Index : 14 Value : 370661 |
|||
Index : 15 Value : 741337 |
|||
Index : 16 Value : 1482707 |
|||
Index : 17 Value : 2965421 |
|||
Index : 18 Value : 5930887 |
|||
Index : 19 Value : 11861791 |
|||
Index : 20 Value : 23723597 |
|||
Index : 21 Value : 47447201 |
|||
Index : 22 Value : 94894427 |
|||
Index : 23 Value : 189788857 |
|||
Index : 24 Value : 379577741 |
|||
Index : 25 Value : 759155483 |
|||
Index : 26 Value : 1518310967 |
|||
Index : 27 Value : 3036621941 |
|||
Index : 28 Value : 6073243889 |
|||
Index : 29 Value : 12146487779 |
|||
Index : 30 Value : 24292975649 |
|||
Index : 31 Value : 48585951311 |
|||
Index : 32 Value : 97171902629 |
|||
Index : 33 Value : 194343805267 |
|||
Index : 34 Value : 388687610539 |
|||
Index : 35 Value : 777375221081 |
|||
Index : 36 Value : 1554750442183 |
|||
Index : 37 Value : 3109500884389 |
|||
Index : 38 Value : 6219001768781 |
|||
Index : 39 Value : 12438003537571 |
|||
Index : 40 Value : 24876007075181 |
|||
Index : 41 Value : 49752014150467 |
|||
Index : 42 Value : 99504028301131 |
|||
</pre> |
</pre> |
||