add assignment 7 and finish verslag
This commit is contained in:
30
assignment_assembly/assignment7/main.c
Normal file
30
assignment_assembly/assignment7/main.c
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
unsigned int multiply(unsigned int a, unsigned int b);
|
||||||
|
unsigned int power(unsigned int n, unsigned int m);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
extern void initialise_monitor_handles(void);
|
||||||
|
initialise_monitor_handles();
|
||||||
|
|
||||||
|
unsigned int n[] = {0, 1, 0, 1, 2000, 2 , 7, 4294967295u, 3 };
|
||||||
|
unsigned int m[] = {0, 0, 1, 1, 2, 31 , 11, 1 , 20 };
|
||||||
|
unsigned int r[] = {1, 1, 0, 1, 4000000, 0x80000000u, 1977326743, 4294967295u, 3486784401u};
|
||||||
|
|
||||||
|
for (size_t i = 0; i != sizeof(n)/sizeof(n[0]); i++)
|
||||||
|
{
|
||||||
|
printf("%u ^ %u: ", n[i], m[i]);
|
||||||
|
unsigned int result = power(n[i], m[i]);
|
||||||
|
unsigned int correct = r[i];
|
||||||
|
if (result != correct)
|
||||||
|
{
|
||||||
|
printf("Failed, function returned %u but the correct answer is %u\n", result, correct);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Passed, %u\n", result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
44
assignment_assembly/assignment7/power.asm
Normal file
44
assignment_assembly/assignment7/power.asm
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
.cpu cortex-m4
|
||||||
|
.thumb
|
||||||
|
.syntax unified
|
||||||
|
.globl power
|
||||||
|
.text
|
||||||
|
.thumb_func
|
||||||
|
// R5 = n, R6 = m, R4 = result (p)
|
||||||
|
power:
|
||||||
|
PUSH.N {R4, R5, R6}
|
||||||
|
SUB.N SP, SP, #4
|
||||||
|
STR LR, [SP, #0] // push LR to the stack
|
||||||
|
MOVS.N R4, #1 // set result to 1
|
||||||
|
CMP.N R1, #0
|
||||||
|
BEQ.N exit // goto exit if m == 0
|
||||||
|
MOVS.N R5, R0 // move n to R5
|
||||||
|
MOVS.N R6, R1 // move m to R6
|
||||||
|
loop:
|
||||||
|
CMP.N R6, #1
|
||||||
|
BEQ.N exit // goto exit if m == 1
|
||||||
|
MOVS.N R3, #1
|
||||||
|
ANDS.N R3, R6 // R3 = m & 0x1
|
||||||
|
BEQ.N even
|
||||||
|
MOVS.N R0, R4
|
||||||
|
MOVS.N R1, R5
|
||||||
|
LDR.N R3, =multiply
|
||||||
|
BLX.N R3 // p * n
|
||||||
|
MOVS.N R4, R0 // move multiply result to p
|
||||||
|
even:
|
||||||
|
MOVS.N R0, R5
|
||||||
|
MOVS.N R1, R5
|
||||||
|
LDR.N R3, =multiply
|
||||||
|
BLX.N R3 // p * n
|
||||||
|
MOVS.N R5, R0 // move multiply result to n
|
||||||
|
LSRS.N R6, R6, #1 // m = m >> 1
|
||||||
|
B.N loop
|
||||||
|
exit:
|
||||||
|
MOVS.N R0, R4
|
||||||
|
MOVS.N R1, R5
|
||||||
|
LDR.N R3, =multiply
|
||||||
|
BLX.N R3 // p * n
|
||||||
|
LDR LR, [SP, #0] // pop LR from the stack
|
||||||
|
ADD.N SP, SP, #4
|
||||||
|
POP.N {R4, R5, R6}
|
||||||
|
BX.N LR
|
||||||
BIN
assignment_assembly/assignment7/result.png
Normal file
BIN
assignment_assembly/assignment7/result.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
@@ -11,78 +11,241 @@ Ik moest de volgende assignment maken:
|
|||||||
|
|
||||||
## Testing a simple LEGv7 Pinky program
|
## Testing a simple LEGv7 Pinky program
|
||||||
|
|
||||||
Er is een project gegeven die tegevoerd en getest moet worden. De eerste keer dat ik door de stappen heen ging kreeg een een error dat de openOCD.exe fout ging. Dit is logiesh voor mij, omdat ik linux gebruikt als OS en .exe alleen voor Windows zijn.
|
Er is een project gegeven die toegevoerd en getest moet worden. De eerste keer dat ik door de stappen heen ging, kreeg een error dat de openOCD.exe fout ging. Dit is logisch voor mij, omdat ik Linux gebruikt als OS en .exe alleen voor Windows zijn.
|
||||||
|
|
||||||

|
![[2 - elektrotechniek/rts10/assignment_assembly/assignment1/first_error.png]]
|
||||||
|
|
||||||
Het opnieuw selecteeren van de OpenOCD debug probe in het 'Debug Configurations' venster werdt de linux variant corect ingesteld en werkte het.
|
Het opnieuw selecteren van de OpenOCD debug probe in het 'Debug Configurations' venster werd de Linux variant correct ingesteld en werkte het.
|
||||||
|
|
||||||
Voor de zekerheid heb ik het nog een keer geprobeerd terwel ik alle weizigingen in het project bij hou ik git^[voor de geintreseerde heb ik de git repo op mijn server gezet waar de commit van de clock wiezigingen te vinden is met de volgende link (https://gitea.finnvanreenen.nl/FReenen/RTS10_assignment_project_files/commit/4dcb59bc058b3a710a1ca471e4a5d007f64f344c)[https://gitea.finnvanreenen.nl/FReenen/RTS10_assignment_project_files/commit/4dcb59bc058b3a710a1ca471e4a5d007f64f344c]]. Hier zag ik dat er wat clock instellingen werden geweiziged. Dus ik heb het opniew geprobeerd maar dat aleen het veld 'OpenOCD Command' aangepast in de debug configuratie. Met deze methode werden de klock instellingen niet aangepast, alleen een aantal dingen dat ik herken als de verschillen tussen Windows en Linux.
|
Voor de zekerheid heb ik het nog een keer geprobeerd terwel ik alle wijzigingen in het project bij hou ik git^[voor de geïnteresseerde heb ik de git repo op mijn server gezet waar de commit van de clock wijzigingen te vinden is met de volgende link (https://gitea.finnvanreenen.nl/FReenen/RTS10_assignment_project_files/commit/4dcb59bc058b3a710a1ca471e4a5d007f64f344c)[https://gitea.finnvanreenen.nl/FReenen/RTS10_assignment_project_files/commit/4dcb59bc058b3a710a1ca471e4a5d007f64f344c]]. Hier zag ik dat er wat clock instellingen werden gewijzigd. Dus ik heb het opnieuw geprobeerd, maar dan alleen het veld 'OpenOCD Command' aangepast in de debugconfiguratie. Met deze methode werden de clock instellingen niet aangepast, alleen een aantal dingen dat ik herken als de verschillen tussen Windows en Linux.
|
||||||
|
|
||||||
Hierna werken het nogsteed zoals verwacht.
|
Hierna werken het nog steeds zoals verwacht.
|
||||||
|
|
||||||

|
![[2 - elektrotechniek/rts10/assignment_assembly/assignment1/output.png]]
|
||||||
|
|
||||||
## Writeting a simple multiplication program
|
## Writeting a simple multiplication program
|
||||||
|
|
||||||
Om te beginnen heb ik het project van de vorige assignment. Hier heb ik aan *main.c* een paar simpele regels toegevoegd om de basis werking te testen.
|
Om te beginnen heb ik het project van de vorige assignment. Hier heb ik aan *main.c* een paar simpele regels toegevoegd om de basis werking te testen.
|
||||||
|
|
||||||

|
```c
|
||||||
|
/* main.c simple program to test assembler program */
|
||||||
|
|
||||||
Pas toen ik het werkend had kwam ik achter dat ik `a` en `b` heb omgedraaid. Dit maakt gelukkig niet uit in een vermedigvuldiging. Daarnaast heb ik ook `i` weg gewerkt door i.p.v. `i` te verhogen en daarna te vergeleiken met `b` heb ik `b` verlaagd tot het 0 is.
|
#include <stdio.h>
|
||||||
|
|
||||||
|
extern int test(int a, int b);
|
||||||
|
extern unsigned int multiply(unsigned int a, unsigned int b);
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
extern void initialise_monitor_handles(void);
|
||||||
|
initialise_monitor_handles();
|
||||||
|
|
||||||
|
int a = test(3, 5);
|
||||||
|
printf("Result of test(3, 5) = %d\n", a);
|
||||||
|
|
||||||
|
unsigned int b = multiply(3, 5);
|
||||||
|
printf("Result of multipy(3, 5) = %d\n", b);
|
||||||
|
|
||||||
|
b = multiply(3, 0);
|
||||||
|
printf("Result of multipy(3, 0) = %d\n", b);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Pas toen ik het werkend had, kwam ik achter dat ik `a` en `b` heb omgedraaid. Dit maakt gelukkig niet uit in een vermenigvuldiging. Daarnaast heb ik ook `i` weg gewerkt door i.p.v. `i` te verhogen en daarna te vergelijken met `b` heb ik `b` verlaagd tot het 0 is.
|
||||||
|
|
||||||
Dit is mijn implementatie:
|
Dit is mijn implementatie:
|
||||||
|
|
||||||

|
```assambly
|
||||||
|
.cpu cortex-m4
|
||||||
|
.thumb
|
||||||
|
.syntax unified
|
||||||
|
.globl multiply
|
||||||
|
.text
|
||||||
|
.thumb_func
|
||||||
|
multiply:
|
||||||
|
MOVS.N R2, #0 // set result to 0
|
||||||
|
CMP.N R1, #0
|
||||||
|
BEQ.N exit // goto exit if b == 0
|
||||||
|
loop:
|
||||||
|
ADDS.N R2, R0, R2 // add a to result
|
||||||
|
SUBS.N R1, #1 // substract 1 from b
|
||||||
|
BEQ.N exit // goto exit if b == 0
|
||||||
|
B.N loop // loop otherwise
|
||||||
|
exit:
|
||||||
|
MOVS.N R0, R2 // move result to R0
|
||||||
|
BX.N LR
|
||||||
|
```
|
||||||
|
|
||||||
En het test resultaat:
|
En het testresultaat:
|
||||||
|
|
||||||

|
![[2 - elektrotechniek/rts10/assignment_assembly/assignment2/rest_result.png]]
|
||||||
|
|
||||||
### How many instructions does it take your procedure to run the code: `multiply(65535, 65535)`?
|
### How many instructions does it take your procedure to run the code: `multiply(65535, 65535)`?
|
||||||
|
|
||||||
65535 (decimaal) = 0xFFFF (hex) ofwel 16 eenen in binair.
|
65535 (decimaal) = 0xFFFF (hex) ofwel 16 enen in binair.
|
||||||
|
|
||||||
Voor de loop zijn 3 instructies.
|
Voor de loop zijn 3 instructies.
|
||||||
|
|
||||||
een interatie van de loop zijn 4 instructies, deze loop wordt netzovaak ald de waarde van `b` uitgevoerd dus 4 * 65535 - 1 = 262139 instructies (de - 1 is voor de laaste iteratie waar die uit de loop springt waardoor de laaste instructie in de loop wordt overgeslagen).
|
Een iteratie van de loop zijn 4 instructies, deze loop wordt net zo vaak als de waarde van `b` uitgevoerd dus 4 * 65535 - 1 = 262139 instructies (de - 1 is voor de laatste iteratie waar die uit de loop springt waardoor de laatste instructie in de loop wordt overgeslagen).
|
||||||
|
|
||||||
Na de loop zijn nog 2 instructie, dat een totaal maakt van 262144 instructies
|
Na de loop zijn nog 2 instructie, dat een totaal maakt van 262144 instructies
|
||||||
|
|
||||||
## A smarter tail recursive multiply algorithm
|
## A smarter tail recursive multiply algorithm
|
||||||
|
|
||||||
Voor deze opdracht heb ik niet exect de gegeven C code na gemaakt. Ik heb de twee functies als een geschreven. Hierbij is het argument `m` van `function multiply2` verplaast als laaste argument i.p.v. de eerste en de `if (b == 0)` heb ik verplaats naar `multiply`.
|
Voor deze opdracht heb ik niet exact de gegeven C code na gemaakt. Ik heb de twee functies als een geschreven. Hierbij is het argument `m` van `function multiply2` verplaatst als laatste argument i.p.v. de eerste en de `if (b == 0)` heb ik verplaats naar `multiply`.
|
||||||
|
|
||||||
Het verplatsen van argument `m` is alleen een probleem waneer er andere code is die gebruik maakt dat deze functie behalve `multiply`.
|
Het verplaatsen van argument `m` is alleen een probleem wanneer er andere code is die gebruik maakt dat deze functie behalve `multiply`.
|
||||||
|
|
||||||
Het verplasen van de `if (b == 0)`statement is een optimazatie. Deze statement kan nooit waar zijn na de eerste iteratie. `b` wordt steeds 1 plek naar recht geschoven tot dat de laaste bit die `1` is op de 1 positie staat. In dat geval eindigd de funcie direct.
|
Het verplassen van de `if (b == 0)`statement is een optimalisatie. Dit statement kan nooit waar zijn na de eerste iteratie. `b` wordt steeds 1 plek naar recht geschoven tot dat de laatste bit die `1` is op de 1 positie staat. In dat geval eindigt de functie direct.
|
||||||
|
|
||||||
De asambly code:
|
De assembly code:
|
||||||
|
|
||||||

|
```assambly
|
||||||
|
.cpu cortex-m4
|
||||||
|
.thumb
|
||||||
|
.syntax unified
|
||||||
|
.globl multiply
|
||||||
|
.text
|
||||||
|
.thumb_func
|
||||||
|
// R0 = a, R1 = b, R2 = result (m), R3 = odd/even mask/result
|
||||||
|
multiply:
|
||||||
|
MOVS.N R2, #0 // set result to 0
|
||||||
|
CMP.N R1, #0
|
||||||
|
BEQ.N exit // goto exit if b == 0
|
||||||
|
multiply2:
|
||||||
|
CMP.N R1, #1
|
||||||
|
BNE.N check_even // goto check_even if b == 1
|
||||||
|
ADDS.N R2, R0 // move a to result
|
||||||
|
B.N exit // goto exit
|
||||||
|
check_even:
|
||||||
|
MOVS.N R3, #1 // set R3 to 1 as bit mask
|
||||||
|
ANDS.N R3, R1 // and R3 (bit mask) with b
|
||||||
|
BNE.N odd // goto exit if b == 0
|
||||||
|
even:
|
||||||
|
LSLS.N R0, R0, #1 // a = a << 1
|
||||||
|
LSRS.N R1, R1, #1 // b = b >> 1
|
||||||
|
B.N multiply2 // recurse
|
||||||
|
odd:
|
||||||
|
ADDS.N R2, R0 // add a to result
|
||||||
|
LSLS.N R0, R0, #1 // a = a << 1
|
||||||
|
LSRS.N R1, R1, #1 // b = b >> 1
|
||||||
|
B.N multiply2 // recurse
|
||||||
|
exit:
|
||||||
|
MOVS.N R0, R2 // move result to R0
|
||||||
|
BX.N LR
|
||||||
|
```
|
||||||
|
|
||||||
Het test resultaat:
|
Het testresultaat:
|
||||||
|
|
||||||

|
![[2 - elektrotechniek/rts10/assignment_assembly/assignment5/result.png]]
|
||||||
|
|
||||||
### How many instructions does it take your procedure to run the code: `multiply(65535, 65535)`?
|
### How many instructions does it take your procedure to run the code: `multiply(65535, 65535)`?
|
||||||
|
|
||||||
65535 (decimaal) = 0xFFFF (hex) ofwel 16 eenen in binair.
|
65535 (decimaal) = 0xFFFF (hex) ofwel 16 enen in binair.
|
||||||
|
|
||||||
vanaf lable `multiply` duurt het 3 instructie tot de eerste branch instructie. Deze word niet genomen omdat `b` niet 0 is.
|
Vanaf label `multiply` duurt het 3 instructie tot de eerste branch instructie. Deze wordt niet genomen omdat `b` niet 0 is.
|
||||||
|
|
||||||
hierna komt `multiply2` waar de 2de instrucie een branche is die genomen wordt. b nog geen 0.
|
Hierna komt `multiply2` waar de 2de instructie een branche is die genomen wordt. `b` nog geen 0.
|
||||||
|
|
||||||
`check_even` heeft 3 instructies tot een brance. deze brance wordt altijd genomen omdat `b` in binar alleen maar uit 1en bestaat, dus het schuiven naar rechts (de enige bewerking die gedaan wordt op `b`) verandert bit 1 niet naar 0 voor dat `b` 1 is geweest waneer de loop eindigt.
|
`check_even` heeft 3 instructies tot een brance. Deze brance wordt altijd genomen, omdat `b` in binair alleen maar uit enen bestaat, dus het schuiven naar rechts (de enige bewerking die gedaan wordt op `b`) verandert bit 1 niet naar 0 voor dat `b` 1 is geweest wanneer de loop eindigt.
|
||||||
|
|
||||||
`odd` heeft 4 instructies, waarna `multiply2` weer word geroepen.
|
`odd` heeft 4 instructies, waarna `multiply2` weer wordt geroepen.
|
||||||
|
|
||||||
De loop van `multiply2` -> `check_even` -> `odd` word 15 keer gedaan. Voor elk bitje dat 1 is in `b` tot dat er nog maar 1 over is. Deze loop betaat uit 8 instructies dus totaal 120 instructies.
|
De loop van `multiply2` -> `check_even` -> `odd` word 15 keer gedaan. Voor elk bitje dat 1 is in `b` tot dat er nog maar 1 over is. Deze loop bestaat uit 8 instructies, dus totaal 120 instructies.
|
||||||
|
|
||||||
waneer `b` == 1 is net nog 6 instructies tot de `BX.N LR` instrcutie.
|
Wanneer `b` == 1 is net nog 6 instructies tot de `BX.N LR` instructie.
|
||||||
|
|
||||||
Totaal is dat dus 129 instructies (3 van `multiply` + 120 van de loop + 6 van het einde). Dit is signifikant minder dat bij assignment 1, dit waren er 262144 dus deze implementatie is ongeveer 2032 keer minder instructies in dit specifieke geval.
|
Totaal is dat dus 129 instructies (3 van `multiply` + 120 van de loop + 6 van het einde). Dit is significant minder dat bij assignment 1, dit waren er 262144 dus deze implementatie is ongeveer 2032 keer minder instructies in dit specifieke geval.
|
||||||
|
|
||||||
## A smarter power algorithm
|
## A smarter power algorithm
|
||||||
|
|
||||||
|
Ik kwam wat kort in tijd en heb de machten tot 0 niet werkend kunnen maken. Hier wordt p * n terg gestuurd i.p.v. 1. Verder werkt de code.
|
||||||
|
|
||||||
|
De assembly voor de power functie:
|
||||||
|
|
||||||
|
```assambly
|
||||||
|
.cpu cortex-m4
|
||||||
|
.thumb
|
||||||
|
.syntax unified
|
||||||
|
.globl power
|
||||||
|
.text
|
||||||
|
.thumb_func
|
||||||
|
// R5 = n, R6 = m, R4 = result (p)
|
||||||
|
power:
|
||||||
|
PUSH.N {R4, R5, R6}
|
||||||
|
SUB.N SP, SP, #4
|
||||||
|
STR LR, [SP, #0] // push LR to the stack
|
||||||
|
MOVS.N R4, #1 // set result to 1
|
||||||
|
CMP.N R1, #0
|
||||||
|
BEQ.N exit // goto exit if m == 0
|
||||||
|
MOVS.N R5, R0 // move n to R5
|
||||||
|
MOVS.N R6, R1 // move m to R6
|
||||||
|
loop:
|
||||||
|
CMP.N R6, #1
|
||||||
|
BEQ.N exit // goto exit if m == 1
|
||||||
|
MOVS.N R3, #1
|
||||||
|
ANDS.N R3, R6 // R3 = m & 0x1
|
||||||
|
BEQ.N even
|
||||||
|
MOVS.N R0, R4
|
||||||
|
MOVS.N R1, R5
|
||||||
|
LDR.N R3, =multiply
|
||||||
|
BLX.N R3 // p * n
|
||||||
|
MOVS.N R4, R0 // move multiply result to p
|
||||||
|
even:
|
||||||
|
MOVS.N R0, R5
|
||||||
|
MOVS.N R1, R5
|
||||||
|
LDR.N R3, =multiply
|
||||||
|
BLX.N R3 // p * n
|
||||||
|
MOVS.N R5, R0 // move multiply result to n
|
||||||
|
LSRS.N R6, R6, #1 // m = m >> 1
|
||||||
|
B.N loop
|
||||||
|
exit:
|
||||||
|
MOVS.N R0, R4
|
||||||
|
MOVS.N R1, R5
|
||||||
|
LDR.N R3, =multiply
|
||||||
|
BLX.N R3 // p * n
|
||||||
|
LDR LR, [SP, #0] // pop LR from the stack
|
||||||
|
ADD.N SP, SP, #4
|
||||||
|
POP.N {R4, R5, R6}
|
||||||
|
BX.N LR
|
||||||
|
```
|
||||||
|
|
||||||
|
de test code die ik heb gebruikt om de functie te testen:
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
unsigned int multiply(unsigned int a, unsigned int b);
|
||||||
|
unsigned int power(unsigned int n, unsigned int m);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
extern void initialise_monitor_handles(void);
|
||||||
|
initialise_monitor_handles();
|
||||||
|
|
||||||
|
unsigned int n[] = {0, 1, 0, 1, 2000, 2 , 7, 4294967295u, 3 };
|
||||||
|
unsigned int m[] = {0, 0, 1, 1, 2, 31 , 11, 1 , 20 };
|
||||||
|
unsigned int r[] = {1, 1, 0, 1, 4000000, 0x80000000u, 1977326743, 4294967295u, 3486784401u};
|
||||||
|
|
||||||
|
for (size_t i = 0; i != sizeof(n)/sizeof(n[0]); i++)
|
||||||
|
{
|
||||||
|
printf("%u ^ %u: ", n[i], m[i]);
|
||||||
|
unsigned int result = power(n[i], m[i]);
|
||||||
|
unsigned int correct = r[i];
|
||||||
|
if (result != correct)
|
||||||
|
{
|
||||||
|
printf("Failed, function returned %u but the correct answer is %u\n", result, correct);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Passed, %u\n", result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
het testresultaat:
|
||||||
|
|
||||||
|
![[2 - elektrotechniek/rts10/assignment_assembly/assignment7/result.png]]
|
||||||
|
|||||||
Reference in New Issue
Block a user