hi i created a hardware that calculates the square root of (a^2+b^2 )
i sent the inputs (a and b) with assembly and that was fine however when i tried to send them using c code the hardware take them as inputs calculates a^2 + b^2 but never do the square root
i am really clueless here i couldn't locate the problem
heeeeeeeeeeeeeeelp
Could you provide the assembly listing that works, the C code that doesn't and a disassembly (objdump -d executable on Unix/Linux systems) of the non-working C code for analysis ?
my assembly code
PRESERVE8 THUMB AREA RESET, DATA, READONLY ; First 32 WORDS is VECTOR TABLE EXPORT __Vectors __Vectors DCD 0x000003FC DCD Reset_Handler DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 ; External Interrupts DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 DCD 0 AREA |.text|, CODE, READONLY ;Reset Handler Reset_Handler PROC GLOBAL Reset_Handler ENTRY AGAIN LDR R1, =0x59000000 LDR R0, =0x00000022 STR R0, [R1] LDR R1, =0x59000000 LDR R0, =0x00002200 STR R0, [R1] B AGAIN ENDP ALIGN 4 ;; Align to a word boundary END
AREA |.text|, CODE, READONLY
;Reset Handler
Reset_Handler PROC
GLOBAL Reset_Handler
my c code
unsigned int xd[10]; unsigned int yd[10]; volatile unsigned int regdistance __attribute__((at(0x59000000))); int main() { int i; for( i=0;i<10;i++){ xd[0]=0; yd[0]=0; xd[i+1]= xd[i]+1; yd[i+1]= yd[i]+1; regdistance = xd[i]; regdistance = yd[i]; while(1); }
code.hex
0000FFFC 00000169 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 F802F000 F832F000 C830A00C 18243808 46A2182D 46AB1E67 465D4654 D10142AC F824F000 3E0F467E 46B6CC0F 42332601 1AFBD000 46AB46A2 47184333 00000138 00000148 24002300 26002500 D3013A10 D8FBC178 D3000752 D500C130 4770600B 46C0B51F BD1F46C0 BD10B510 F851F000 F7FF4611 F000FFF5 F000F809 B403F869 FFF2F7FF F000BC03 0000F86D E0202100 4A122000 4A126010 00886010 58104A0F 1C4A1C40 4B0D0092 00885098 58104A0C 1C4A1C40 4B0A0092 00885098 58104A07 60104A08 461A0088 4A065810 BF006010 290AE7FE 2000DBDC 00004770 00000204 0000022C 59000000 47004803 49044803 4B054A04 00004770 00000081 000002C0 00000AC0 000006C0 000006C0 47704770 46754770 F822F000 000546AE 46534669 00C008C0 B0184685 F7FFB520 BC60FFDF 08492700 260046B6 C5C0C5C0 C5C0C5C0 C5C0C5C0 C5C0C5C0 00493D40 4770468D 46C04604 462046C0 FF91F7FF 47704800 00000254 20184901 E7FEBEAB 00020026 00004770 00000204 00000204 000008BC 000000C4
Assuming regdistance is an address of your hardware peripheral, then it needs to be a pointer, not an integer, and you need to write to the value pointed at by the pointer, rather than just setting the address locally. Eg. something like:
volatile unsigned int * regdistance __attribute__((at(0x59000000))); int main() { int i; for( i=0;i<10;i++) { xd[0]=0; yd[0]=0; xd[i+1]= xd[i]+1; yd[i+1]= yd[i]+1; *regdistance = xd[i]; *regdistance = yd[i]; } while(1); }
P.S. It looks like you will overflow your loop (I had to guess a bit what the expected indentation for the for loop was). E.g. your access xd[i+1] will access xd[10]which is element 11 in the array, but they are only allocated as 10 elements long.
HTH, Pete
>
http://www.keil.com/support/docs/2829.htm
With the Keil CARM C Compiler, you may use either pointer definitions (as
shown above) or at keyword to define a variable at a fixed memory address. As with the RealView C Compiler, the following definition also makes a correct memory reservation, so that the area cannot be used twice.
shown above) or at keyword to define a variable at a fixed memory
address. As with the RealView C Compiler, the following definition also
makes a correct memory reservation, so that the area cannot be used twice.
i tried to send these inputs with a pointer but in vain however when i used
this form at least the hardware took them as inputs however now even
a2+b2 don't calculate it !!!
2016-06-02 11:07 GMT+01:00 peterharris <community@arm.com>:
Hardware Implementation reply from Peter Harris <https://community.arm.com/people/peterharris?et=watches.email.thread> in
Hardware Implementation
reply from Peter Harris
<https://community.arm.com/people/peterharris?et=watches.email.thread> in
Never knew that - thanks )
So, if I understand correctly :
AGAIN LDR R1, =0x59000000 LDR R0, =0x00000022 STR R0, [R1] LDR R1, =0x59000000 LDR R0, =0x00002200 STR R0, [R1] B AGAIN ENDP
0x59000000 is the address where the input should be sent. I'll call it input_address here.
Then the first input value (a in your algebraic formulae) is retrieved from address 0x22 and stored at input_address.
Same thing for second input value (b), which address seems to be 0x2200.
Then, I guess, once two values provided the hardware do the whole calculation automatically ?
In that case, do this code work in your case :
test.c
int calculate(int a, int b) { volatile int *input_address = (int*)0x59000000; while(1) { *input_address = a; *input_address = b; } }
Compiling it with gcc like this :
armv7a-hardfloat-linux-gnueabi-gcc -O3 -nostdlib -shared -o test.o test.c
Generates this machine code :
armv7a-hardfloat-linux-gnueabi-objdump -d test.o
00000218 <calculate>: 218: e3a03459 mov r3, #1493172224 ; 0x59000000 21c: e5830000 str r0, [r3] 220: e5831000 str r1, [r3] 224: eafffffc b 21c <calculate+0x4>
Which is roughly the same.
In any case, in your provided code, did you try this instead :
int main() { the_old_days: xd[0]=0; yd[0]=0; int i; for(i=0;i<9;i++){ /* with i < 10, when i = 9, xd[i+1] will be equal to xd[10] which is out of bounds */ xd[i+1]= xd[i]+1; yd[i+1]= yd[i]+1; regdistance = xd[i]; regdistance = yd[i]; } goto the_old_days; }
as i told M
Peter Harris
I don't why my keil can't allocate a memory address with a pointer however i think that the problem is within the def of the "attribute" which allocate a fixed address that can't be reused by another
i tried to differentiate the output of yd and xd and when i compiled my code i observed that regdistance take only the value of xd so i defined another address memory to put the yd and when i simulate my hardware behavior i found that now it calculates the a^2+b^2 but not the square root
if anyone has a suggestion or any idea how can i resolve this prob please help
Well, can you use objdump -d on the bugged binary file and paste the output here.
I do not think that the variable definition is the problem here. However, one way to be sure is to try defining regdistance within main like this :
volatile int *regdistance = (int*)0x59000000;
And see if it works.
Note that you might want to replace
for (i = 0; i < 10; i++)
by
for (i = 0; i < 9; i++)
else you will write into places you did not define (xd[9+1] is not defined).
However, the "at" behaviour can also be emulated doing something like :
volatile int input_address __attribute__ ((section ("regdistance"))); int calculate(int a, int b) { while(1) { input_address = a; input_address = b; } }
Using a linker script like this :
test.ld
ENTRY(calculate)SECTIONS{ . = 0x10000; .text : { *(.text*) } . = 0x59000000; .regdistance : { *(regdistance*) }}
ENTRY(calculate)
SECTIONS
{
. = 0x10000;
.text : { *(.text*) }
. = 0x59000000;
.regdistance : { *(regdistance*) }
}
And then compile like this :
armv7a-hardfloat-linux-gnueabi-gcc -O3 -nostdlib -mthumb -T test.ld -o test test.c
Code produced :
LANG=C armv7a-hardfloat-linux-gnueabi-objdump -d testtest: file format elf32-littlearmDisassembly of section .text:
LANG=C armv7a-hardfloat-linux-gnueabi-objdump -d test
test: file format elf32-littlearm
Disassembly of section .text:
00010000 <calculate>: 10000: f240 0300 movw r3, #0 10004: f6c5 1300 movt r3, #22784 ; 0x5900 10008: 6018 str r0, [r3, #0] 1000a: 6019 str r1, [r3, #0] 1000c: e7fc b.n 10008 <calculate+0x8> 1000e: bf00 nop