Hi all, I’m after some advice on low level memory access.
What is the best way to access (read or write) to individual registers in an embedded application with Julia?
Say I want to read address 0x6000 0000 plus an offset from there to confirm a pin driver configuration. Is there a Julia instruction to read an address directly?
unsafe_read
might be what you are looking for.
Nice lead! I’ll check it out, thanks.
unsafe_load
seems suitable for this.
If you want to use pointer, then
offset = ...
p = Ptr{Nothing}(0x60000000 + offset) # build a void* pointer
Base.unsafe_convert(Ptr{...},p) # convert the pointer to a given type
Base.unsafe_load(p) # load the value from the pointer
If you want to read or write registers directly, I guess the best you can do is to use LLVM’s assembler expressions, check LLVM’s documentation.
And to use these from Julia, you can write your own llvmcall
expressions, or use LLVM.jl. An example from CUDA.jl:
using LLVM
using LLVM.interop
dynamic_smem_size() = @asmcall("mov.u32 \$0, %dynamic_smem_size;", "=r", true, UInt32, Tuple{})
Thanks Chen,
I tried p = Ptr{Nothing}(0x60000000 + offset) but this gives a Method error: no method matching Ptr{Nothing}(::UInt32)
But p=Ptr{Nothing}() is accepted, and returns Ptr{Nothing} @0x0000000000000000
If it works elsewhere, is there a package required?
Thanks Tim,
I’ll put LLVM in my “plan B” tray while I try out the unsafe_ Ptr permutations.
Looks like you’re working on a 64bit system where a pointer is of 64 bits ( it has the same size as a 64bit integer and can be safely casted from a 64bit integer, but not from a 32bit integer), so you need to use Ptr{Nothing}(0x6000000000000000)
instead.
But…p=Ptr{Nothing}(0x0000000060000000) is accepted and returns
Ptr{Nothing} @0x0000000060000000
Yay!
Its a Jetson Nano.
You’re right, that was accepted.
Progress so far…
julia> offset = 0x3230
0x3230
julia> p=Ptr{Nothing}(0x0000000060000000 + offset)
Ptr{Nothing} @0x0000000060003230
julia> pc=Base.unsafe_convert(Ptr{UInt64},p)
Ptr{UInt64} @0x0000000060003230
julia> regval=Base.unsafe_load(pc)
signal (11): Segmentation fault
in expression starting at REPL[4]:1
unsafe_load at ./pointer.jl:105 [inlined]
unsafe_load at ./pointer.jl:105
unknown function (ip: 0x7f62395faf)
Allocations: 2650 (Pool: 2639; Big: 11); GC: 0
Segmentation fault (core dumped)
&Dumped, as expected.&
Maybe you should first test whether the equivalent C program works, like:
#include<stdio.h>
int main(){
unsigned long a = 0x0000000060003230;
unsigned long *p = (unsigned long *)(a);
printf("%d\n",*p);
return 0;
};
I guess the problem here is that we need system calls to perform these IO actions (that is, confirm a pin driver configuration), instead of directly load values from the memory. Or the memory address is the mapped one…
It would be easier if you can just wrap these kinds of low level codes in C and provide the utility as a dynamic library, so you can directly call it from Julia instead of twisting pointers directly in Julia…