dwelch posted on Jul 15 2006 at 02:40 AM said:
good idea to have the cache on with the write buffer. I assume an STM with a few registers followed by an ldrb from the location the last of those registers data will land will return the value before the write and not after (a synchronization problem). Will have to test that, with a cache I would assume it writes through the cache to the write buffer and prevents these sorts of problems. I could be talking out my ass at this point, sounds like a project to research and test.
[00069C] 0xE92D03F0 STMDB R13!,{R4,R5,R6,R7,R8,R9}
[0006A0] 0xE3A00A09 MOV R0,#0x00009000 ;@(0x09 RR 20)
[0006A4] 0xE59F1024 LDR R1,[R15,#+0x024] ;@(000006D0)
[0006A8] 0xE59F2024 LDR R2,[R15,#+0x024] ;@(000006D4)
[0006AC] 0xE59F3024 LDR R3,[R15,#+0x024] ;@(000006D8)
[0006B0] 0xE59F4024 LDR R4,[R15,#+0x024] ;@(000006DC)
[0006B4] 0xE59F5024 LDR R5,[R15,#+0x024] ;@(000006E0)
[0006B8] 0xE880001E STMIA R0,{R1,R2,R3,R4}
[0006BC] 0xE5950000 LDR R0,[R5,#+0x000]
[0006C0] 0xE8BD03F0 LDMIA R13!,{R4,R5,R6,R7,R8,R9}
[0006C4] 0xE1A0F00E MOV R15,R14,LSL#0
...
[0006D0] 0x12345678 EORNES R5,R4,#0x07800000 ;@(0x78 RR 12)
[0006D4] 0x56789ABC LDRPLBT R9,[R8]-R12, LSR #21!
[0006D8] 0xABCDEF12 BLGE S0337C328
[0006DC] 0xAB1234CD BLGE S0048DA18
[0006E0] 0x0000900C ANDEQ R9,R0,R12,LSL#0
There are no synchronization problems related to the write buffer from a single side perspective
After the quick test above a review of the TRM says that a load from noncacheable memory will drain the write buffer. So I dont know why you would want to setup a register to do an mcr p15, 9, Rd, c7, c10, 4 when a simple ldr will do the same job in one instruction.
0x69C STMDB on the stack would have filled up 6/8ths of the write buffer.
0x6A9 the MOV R0 is a freebie, it executes in the shadow of the write buffer assuming it had already been prefetched and was decoding while the STMDB was executing (cache is off for this test). With the write buffer off this instruction would had to have waited. Although if there was an instruction fetch during this
execution cycle then that instruction fetch would have drained the write buffer instead of the next instruction
0x6A4 LDR R1 would have drained it the write buffer (if an instruction fetch had not already)
0x6B8 STMIA filles up 1/2 of the write buffer
0x6BC LDR would have drained it before reading so that the value that had been in R4 is written to 0x900C before R0 tries to read it.
Note the above test used only one memory region for data, code, and the test area. cache was off and write buffer on which is why instruction fetchs could also drain the write buffer. To do a real test I should have put the memory under test in its own region separate from the program. It doesnt matter now because I RTFM, and the answer is right there.
Now saying that, there is nothing (in the 940 or 920) to prevent synchronization problems between the cores. If you were to do a good sized STMIA (on the 940), then write to one of the dual-cpu registers to cause an interrupt on the 920. The race is on. With the number of things that have to happen I cant imagine that the 920 would win. It gets an interrupt, has to finish the instruction/activity. Read the vector table, execute that instruction, then no doubt the first thing in the interrupt hander is an STMDB with a bunch of registers which would take as long or longer than the write buffer on the 940. You could try but I doubt that you could beat the 940s write buffer (using an interrupt for dual-cpu communication). going the other direction you might have a better chance, if you filled up the write buffer on the 920 (which is twice the size of the 940s) then interrupted the 940, which may have nothing better to do than wait for interrupts, and may be written as event/interrupt driven application only in the sense meaning it doesnt necessarily have to preserve registers, you might get lucky and have the 940 read a location before the 920 write buffer writes it. I would recommend that the 920 does a read in that region before writing to the dual-cpu register to flush the write buffer. Extremely unlikely that you will have problems, but possible.
So basically having the write buffer on for shared memory is safe and actually a good idea for performance reasons. DO NOT have it cached though, that will definitely kill you. You would have to keep flipping the cache on and off or invalidating parts of the cache, and it wouldnt gain you any performance improvement. Instead do a fast copy (four register LDM/STMs instead of ldrb/strb as a memcpy probably does) to a cached memory region and operate on it from there. Going to cost you the same amount of time as trying to invalidate the cache and then re-fill it as you read the region.
So in a nutshell, for shared memory between the 920 and 940 (IMO)
1) write buffer enable both sides
2) do not data cache enable either side
3) use LDM/STM pairs, probably 4 register, to fast copy from a cached region into the shared memory just before signaling the other side
4) read at least one address in the shared region before signalling the other side
5) when you receive a signal to read the shared memory from the other side use LDM/STM pairs to quickly move the new data into a data cached memory region.
6) operate on the copy of the shared buffer in your application
I am not sure you can do much better than that as a balance of performance and safety, but now that I have written this it is open for all the negative comments you can think of...flame on...