This code jumped out at me as confusing:
Code: Select all
systemTimer .req r1
ldr systemTimer,=0x20003000
#load current counter time, offset by 0x4
ldr r4,[systemTimer,#0x4]
ldrd r2,r3,[r4]
First off the interesting/strange syntax for ldrd. But then more investigation. I changed the 0x7e to 0x20 btw.
Looking at what is generated:
Code: Select all
00000000 <.text>:
0: e59f1004 ldr r1, [pc, #4] ; c <.text+0xc>
4: e5914004 ldr r4, [r1, #4]
8: e1c420d0 ldrd r2, [r4]
c: 20003000 andcs r3, r0, r0
so loading r1=0x20003000 is fine, no problems there.
the next instruction ldr r4,[r1,#4] what this is is r4 = memory[0x20003004], so r4 now contains the
lower 32 bits of the free running counter.
So now you are using the counter as an address into memory. That can be dangerous, unaligned accesses, etc.
I didnt know you could use syntax like that either, you have to use an even/odd with the odd register being even+1, so you really only need to specify one register. I can see the two register thing as a mental reminder that two registers are modified.
I am thinking that this is closer to what you were wanting
Code: Select all
ldr r1,=0x20003000
ldrd r2,[r1,#4]
And what that does is
Code: Select all
r1 = 0x20003000
r3:r2 = memory[r1+0x04] = memory[0x20003004]
The theme has been repeated
Code: Select all
#store time in timer0 comparison register, offset by 0xC
ldr r4,[systemTimer,#0xC]
str r2,[r4]
Correct me if I am wrong, but I think what you want is this:
Code: Select all
#store time in timer0 comparison register, offset by 0xC
str r2,[systemTimer,#0xC]
Now I dont think the ldrd r2,[r1,#4] is going to do what I assume you are trying to do, an atomic read of two separate peripheral registers. Even on a 64 AXI bus this should result in two separate bus transfers. Even if it had been a 64 bit aligned pair of registers and if it is a 64 bit AXI bus you would see a single AXI transfer, but that doesnt mean the peripheral hardware is going to implement the read of those two registers in an atomic manner. If it were a single AXI transfer the peripheral simply has to return all the data when it completes the transfer it can take as many cycles as it wants to return that data.
Sometimes you see 64 bit timers split like this that when reading one of the registers the other latches until you read it, allowing you to take your time to read the two. You just have to read them in the right order. Please help me but I dont see the documentation indicating that.
This appears worthy of a research project. Looking at more of your code I dont see that you are using r3, so not sure why the ldrd is used when ldr will satisfy what you are trying to do.
Another way you could have implemented your code, but with the arm instruction set there is no need to is:
Code: Select all
#store time in timer0 comparison register, offset by 0xC
add r4,systemTimer,#0xC
str r2,[r4]
The ldr/str instructions allow for somewhere around 8 to 12 bits of immediate offset to be added to the base, I would have to go to the arm docs to confirm how much. Certainly for this timer where you only need to offset from 0x00 to 0x18 you only need to set the base address and use [base,#imm_offset] addressing to reach any of the registers.
David