add assignment 7 and finish verslag

This commit is contained in:
2024-09-16 00:38:39 +02:00
parent 8990f0e51e
commit 9dd8148633
4 changed files with 265 additions and 28 deletions

View 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;
}

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

@@ -11,78 +11,241 @@ Ik moest de volgende assignment maken:
## 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.
![openOCD error](assignment1/first_error.png)
![[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.
![assegnment 1 output](assignment1/output.png)
![[2 - elektrotechniek/rts10/assignment_assembly/assignment1/output.png]]
## 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.
![simpele test code](assignment2/main.c)
```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:
![asambly implementatie van vermedigvuldiging](assignment2/multiply.asm)
```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:
![screenshot test resultaat](assignment2/rest_result.png)
![[2 - elektrotechniek/rts10/assignment_assembly/assignment2/rest_result.png]]
### 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.
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
## 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:
![slimmere vermedigvuldiging assambly](assignment5/multiply.asm)
```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:
![schreenshot testresultaat](assignment5/result.png)
![[2 - elektrotechniek/rts10/assignment_assembly/assignment5/result.png]]
### 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
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]]