Pico & using the BCM2835 hardware RNG.
Richard Pearson (8402) 1 post |
I’m new to the RiscOS community, hello! I’ve always been facinated by randomness, and was chuffed to find out that the RPI’s BCM2835 has an undocumented hardware random number generator. It appears to be of good quality – passing FIPS 140-2 & Dieharder tests for randomness… It seems simple enough to use if you can read/write five registers in the BCM2835, however finding the right SWI calls is challenging… Here is the technical documentation for the random number generator. And here is some example code for running the RNG in Linux – I want to do the exact same thing with SYS calls.
Does anyone have any idea if it’s even possible to write to these addresses from SWI calls? If so, what calls do I need to use? I really appreciate any guidance at all… I’m a bit lost… Thank you! |
Richard (8402) 1 post |
Hi All, I managed to work it out – here’s the ugly hack for anyone who’s interested! Some quick notes: 1) The generator takes a second or two to “warm up” – during this period it returns the same value, this is what the first loop is for. There are nicer ways to detect this by using the status_register (see doc above). 2) The documentation may not be completely accurate, as setting the control register to 1 is the only way to get it to return different values – according to the docs this is 2x mode at the expense of quality. I’ve tried setting this register to 1, letting it warm up, and setting it back to 0 – but this stops the flow of values every time. The docs imply that setting 0 is a higher quality mode, but the linux driver does the same thing – so go figure – it’s undocumented. 3) I haven’t bothered to disable the interrupt in the example, but if you’re using it you should probably set the interrupt mask register to 1 to disable this. 4) I’m a complete newbie to RiskOS, BBC Basic and Risc Assembly – feel free to critique your heart out. Cheers!
|
Kuemmel (439) 384 posts |
Interesting read…didn’t know about that random generator in den BCM ! As I’m into sizecoding I was always looking for the shortest code to get good randoms. That link here explains how you achieve that (good enough for me) with just a seed/signed multiply and feed back…I’ve never implemented it in Risc OS, but should be easy…just don’t know how mathematically “good” those randoms are. |
Rick Murray (539) 13840 posts |
SYS “OS_Memory”,13,&20104000,32 TO ,,,RNG_CTRL% Just off the top of my head, I notice you’re mapping in sequential addresses (specifying 32 bytes to map in each time). Perhaps something like this might work? SYS "OS_Memory",13,&20104000,32 TO ,,,RNG_CTRL% RNG_STATUS% = RNG_CTRL% + 4 RNG_DATA% = RNG_CTRL% + 8 RNG_FF_THRES% = RNG_CTRL% + 12 RNG_INT_MASK% = RNG_CTRL% + 16
Hmm, on my Pi2 (ARMv7), it always returns 0. That said, the address may not be correct. The I/O base of the original Pi was &20xxxxxx, while in the Pi 2 (and I presume later) it becomes &3Fxxxxxx. |
Rick Murray (539) 13840 posts |
Yes, that’s it. You’ll probably want to read the CPUID to work this out. Note, off the top of my head and untested. MRC P15, 0, R0, C0, C0, 0 ; read CPUID AND R0, R0, #&F000 ; mask out all but bits 12-15 CMP R0, #&B000 ; is it an original Pi? MOVEQ R0, #1 ; Yes, it's an original MOVNE R0, #0 ; No, it's a later Pi CPUID of the original BCM2935 is &xxxxB76x, we look for the ‘B’. Later versions are something else, like &xxxxC07x for the Cortex-A7 core. If the result of the above code is ‘1’, then it’s an &20xxxxxx address. Otherwise, it’s an &3Fxxxxxx address. :-) |
RichardP (8402) 3 posts |
Sorry for the late reply Rick – I really appreciate your help with this! You’re totally right about the address change – I’ve just tested it on the 3A and it works!. I also appreciate your advice on detecting CPU ID and cleaning up the code. Many thanks! For anyone else reading – the address in my original example works on the RPI Zero W (beyond that I have not tested). |