How do I use registers and offset addresses? - c++

Currently, I am trying to write a GPIO driver and attempting to wrap my head around a couple of things. After searching the internet, I haven't really found a clear answer to a few questions I have regarding base addresses, registers, and offset addresses.
For the questions below, lets say I have an arbitrary register D1:F0 and an offset address of 10h-13h (32 bits in size). Bit 0 is always 1 and reserved, bits 10:1 is the GPIO base address, and bits 31:11 are reserved and always 0. This register has a default value of 00000001h. Using this information:
1) What is Function Number-to-Root Port Mapping in regards to D1:F0?
2) Does D1:F0 contain a port that would be usable in code?
3) How does the offset address relate to question 1/question 2?
4) The default value of the register has all bits off except the first reserved bit (which should be 1), correct?
Paranoia Check Question: Bits[4:1] means bits 1-4, right?
Thanks in advance guys and gals!
Note: I need to point out that all data, registers, memory addresses, and offsets in this post are arbitrary and in no way reflect data I will be working with/have access to. This is just conceptual and to illustrate a point.

After researching, I've found a few things out:
1) Function Number-to-Root Port Mapping in regards to the example of D1:F0 is a notation that means that the register is on Device 1, Function 0 in regards to the PCH and Bus. A bus device can have multiple "functions" that, for example, could be used by different peripherals.
2) Yes and no. NRP notation gives you, for lack of a better term, a logical mapping of the Bus Device to a function and masks the actual hexadecimal base address and offsets for the register. Processor/Chipset documentation has the physical addresses of where the bus starts, and relates those addresses to NRP notation.
3) The offset address does not relate to the example NRP notation of D1:F0. D1:F0 is just a representation of the base address for the register in regards to the Bus, not an actual register address. You would apply the offset (or offset range) to the base address of the register.
4) Correct.Just used a bit field to verify and wrote it out on paper to verify.
Extra Question: The notation of [Number1:Number2] in regards to bits means bits Number1 through Number2 , reading bits from left to right (High Order to Low Order bit). So, for example, bits [15:4] means bits 4 through 15 for a total of 12 bits.

Related

I2C communication between RP2040 and adxl357 accelerometer ( C/C++ SDK )

I need to communicate via I2C to the adxl357 accelerometer and a few questions have arisen.
Looking at the RP2040 sdk documentation I see that there is a special method to send data to a certain address, such as i2c_write_blocking(). Its arguments include a 7-bit address and the data to be sent. My question is, since the accelerometer needs a Read/Write bit, is it still possible to use this function? Or should I go to the alternative i2c_write_raw_blocking()?
Also, I don't understand the notation of the Read / Write bit, it is reported with R/#W, would that mean that 1 is Read while 0 is write?
Thanks in advance for the help.
I2C addresses have 7 bits: these are sent in the high 7 bits of an 8-bit byte, and remaining bit (the least significant bit) is set to 1 for read, 0 for write.
The reason the documentation says it wants a 7-bit address is because it is telling you that the write function will left-shift the address by one and add a 1, and the read function function will left-shift the address by one and add a 0.
If it didn't tell you this you might pre-shift the address yourself, which would be wrong.

Is `reinterpret_cast<char*>(reinterpret_cast<uintptr_t>(&ch) + 1) == &ch +1` guaranteed?

I'm writing alignment-dependent code, and quite surprised that there's no standard function testing if a given pointer is aligned properly.
It seems that most code on the internet use (long)ptr or reinterpret_cast<uintptr_t>(ptr) to test the alignment and I also used them, but I wonder if using the casted pointer to integral type is standard-conformant.
Is there any system that fires the assertion here?
char ch[2];
assert(reinterpret_cast<char*>(reinterpret_cast<uintptr_t>(&ch[0]) + 1)
== &ch[1]);
To answer the question in the title: No.
Counter example: On the old Pr1me mini-computer, a normal pointer was two 16-bit words. First word was 12-bit segment number, 2 ring bits, and a flag bit (can't remember the 16th bit). Second word was a 16-bit word offset within a segment. A char* (and hence void*) needed a third word. If the flag bit was set, the third word was either 0 or 8 (being the bit offset within the addressed word). A uintptr_t for such a machine would need to be uint48_t or uint64_t. Either way, adding 1 to such an integer would not advance to the next character in memory.
A capability addressed machine is also likely to have pointers which are much larger than the address space, and there is no particular reason why the least significant part of the corresponding integer should be part of the "address" rather than part of the extra info.
In practise of course, nobody is writing C++ for a Pr1me, and capability addressed machines seem not to have appeared either. It will work on all real systems - but the standard doesn't guarantee it.

What can I know about data if I know where they are, e.g. 0xffffffff7fffd9d8 vs. 0x10019c1e0?

I am wondering if the numeric value of a pointer tells me something of use during debugging.
For example I have the following on my call stack:
std::basic_ostringstream<char, std, char_traits<char>, std::allocator, <char>void>::str(
0xffffffff7fffd9d8,
0x10019c1e0,
0x100446710,
0x0,
0xffffffff7fffd9d8,
0xffffffff7b331688),
at 0xffffffff7b1b28ec
There seem to be pointers of the form 0xfff and 0x100. Is there a meaning to this difference?
On 64-bit platforms, in theory you could address 264 or approximately 16 exabytes. Since most applications don’t need such a large address space, hardware vendors define smaller virtual address spaces to reduce the cost of address translation. Therefore, on AMD and Intel chips, only the least significant 48 bits of the address are significant, and bits 48 through 63 must be copies of bit 47. These are called canonical form addresses, and they span the following ranges:
0000000000000000 — 00007FFFFFFFFFFF
FFFF800000000000 — FFFFFFFFFFFFFFFF
The former are called canonical lower half addresses, and the latter canonical upper half. It’s the decision of the kernel, but typically upper-half addresses refer to the stack and static program data area, while lower-half addresses refer to heap memory.
Source: Wikipedia
There is a hint you should take with a grain of salt. On 64-bit x86 Linux stack addresses generally are in the upper range, while the heap addresses are in the lower range. So your 0xffff form addresses are probably from the stack, and 0x100 from the heap.

how to efficiently access 3^20 vectors in a 2^30 bits of memory

I want to store a 20-dimensional array where each coordinate can have 3 values,
in a minimal amount of memory (2^30 or 1 Gigabyte).
It is not a sparse array, I really need every value.
Furthermore I want the values to be integers of arbirary but fixed precision,
say 256 bits or 8 words
example;
set_big_array(1,0,0,0,1,2,2,0,0,2,1,1,2,0,0,0,1,1,1,2, some_256_bit_value);
and
get_big_array(1,0,0,0,1,2,2,0,0,2,1,1,2,0,0,0,1,1,1,2, &some_256_bit_value);
Because the value 3 is relative prime of 2. its difficult to implement this using
efficient bitwise shift, and and or operators.
I want this to be as fast as possible.
any thoughts?
Seems tricky to me without some compression:
3^20 = 3486784401 values to store
256bits / 8bitsPerByte = 32 bytes per value
3486784401 * 32 = 111577100832 size for values in bytes
111577100832 / (1024^3) = 104 Gb
You're trying to fit 104 Gb in 1 Gb. There'd need to be some pattern to the data that could be used to compress it.
Sorry, I know this isn't much help, but maybe you can rethink your strategy.
There are 3.48e9 variants of 20-tuple of indexes that are 0,1,2. If you wish to store a 256 bit value at each index, that means you're talking about 8.92e11 bits - about a terabit, or about 100GB.
I'm not sure what you're trying to do, but that sounds computationally expensive. It may be reasonable feasible as a memory-mapped file, and may be reasonably fast as a memory-mapped file on an SSD.
What are you trying to do?
So, a practical solution would be to use a 64-bit OS and a large memory-mapped file (preferably on an SSD) and simply compute the address for a given element in the typical way for arrays, i.e. as sum-of(forall-i(i-th-index * 3^i)) * 32 bytes in pseudeo-math. Or, use a very very expensive machine with that much memory, or another algorithm that doesn't require this array in the first place.
A few notes on platforms: Windows 7 supports just 192GB of memory, so using physical memory for a structure like this is possible but really pushing it (more expensive editions support more). If you can find a machine at all that is. According to microsoft's page on the matter the user-mode virtual address space is 7-8TB, so mmap/virtual memory should be doable. Alex Ionescu explains why there's such a low limit on virtual memory despite an apparently 64-bit architecture. Wikipedia puts linux's addressable limits at 128TB, though probably that's before the kernel/usermode split.
Assuming you want to address such a multidimensional array, you must process each index at least once: that means any algorithm will be O(N) where N is the number of indexes. As mentioned before, you don't need to convert to base-2 addressing or anything else, the only thing that matters is that you can compute the integer offset - and which base the maths happens in is irrelevant. You should use the most compact representation possible and ignore the fact that each dimension is not a multiple of 2.
So, for a 16-dimensional array, that address computation function could be:
int offset = 0;
for(int ii=0;ii<16;ii++)
offset = offset*3 + indexes[ii];
return &the_array[offset];
As previously said, this is just the common array indexing formula, nothing special about it. Note that even for "just" 16 dimensions, if each item is 32 bytes, you're dealing with a little more than a gigabyte of data.
Maybe i understand your question wrong. But can't you just use a normal array?
INT256 bigArray[3][3][3][3][3][3][3][3][3][3][3][3][3][3][3][3][3][3][3][3];
OR
INT256 ********************bigArray = malloc(3^20 * 8);
bigArray[1][0][0][1][2][0][1][1][0][0][0][0][1][1][2][1][1][1][1][1] = some_256_bit_value;
etc.
Edit:
Will not work because you would need 3^20 * 8Byte = ca. 25GByte.
The malloc variant is wrong.
I'll start by doing a direct calculation of the address, then see if I can optimize it
address = 0;
for(i=15; i>=0; i--)
{
address = 3*address + array[i];
}
address = address * number_of_bytes_needed_for_array_value
2^30 bits is 2^27 bytes so not actually a gigabyte, it's an eighth of a gigabyte.
It appears impossible to do because of the mathematics although of course you can create the data size bigger then compress it, which may get you down to the required size although it cannot guarantee. (It must fail to some of the time as the compression is lossless).
If you do not require immediate "random" access your solution may be a "variable sized" two-bit word so your most commonly stored value takes only 1 bit and the other two take 2 bits.
If 0 is your most common value then:
0 = 0
10 = 1
11 = 2
or something like that.
In that case you will be able to store your bits in sequence this way.
It could take up to 2^40 bits this way but probably will not.
You could pre-run through your data and see which is the commonly occurring value and use that to indicate your single-bit word.
You can also compress your data after you have serialized it in up to 2^40 bits.
My assumption here is that you will be using disk possibly with memory mapping as you are unlikely to have that much memory available.
My assumption is that space is everything and not time.
You might want to take a look at something like STXXL, an implementation of the STL designed for handling very large volumes of data
You can actually use a pointer-to-array20 to have your compiler implement the index calculations for you:
/* Note: there are 19 of the [3]'s below */
my_256bit_type (*foo)[3][3][3][3][3][3][3][3][3][3][3][3][3][3][3][3][3][3][3];
foo = allocate_giant_array();
foo[0][1][1][0][2][1][2][2][0][2][1][0][2][1][0][0][2][1][0][0] = some_256bit_value;

C++ : why bool is 8 bits long?

In C++, I'm wondering why the bool type is 8 bits long (on my system), where only one bit is enough to hold the boolean value ?
I used to believe it was for performance reasons, but then on a 32 bits or 64 bits machine, where registers are 32 or 64 bits wide, what's the performance advantage ?
Or is it just one of these 'historical' reasons ?
Because every C++ data type must be addressable.
How would you create a pointer to a single bit? You can't. But you can create a pointer to a byte. So a boolean in C++ is typically byte-sized. (It may be larger as well. That's up to the implementation. The main thing is that it must be addressable, so no C++ datatype can be smaller than a byte)
Memory is byte addressable. You cannot address a single bit, without shifting or masking the byte read from memory. I would imagine this is a very large reason.
A boolean type normally follows the smallest unit of addressable memory of the target machine (i.e. usually the 8bits byte).
Access to memory is always in "chunks" (multiple of words, this is for efficiency at the hardware level, bus transactions): a boolean bit cannot be addressed "alone" in most CPU systems. Of course, once the data is contained in a register, there are often specialized instructions to manipulate bits independently.
For this reason, it is quite common to use techniques of "bit packing" in order to increase efficiency in using "boolean" base data types. A technique such as enum (in C) with power of 2 coding is a good example. The same sort of trick is found in most languages.
Updated: Thanks to a excellent discussion, it was brought to my attention that sizeof(char)==1 by definition in C++. Hence, addressing of a "boolean" data type is pretty tied to the smallest unit of addressable memory (reinforces my point).
The answers about 8-bits being the smallest amount of memory that is addressable are correct. However, some languages can use 1-bit for booleans, in a way. I seem to remember Pascal implementing sets as bit strings. That is, for the following set:
{1, 2, 5, 7}
You might have this in memory:
01100101
You can, of course, do something similar in C / C++ if you want. (If you're keeping track of a bunch of booleans, it could make sense, but it really depends on the situation.)
I know this is old but I thought I'd throw in my 2 cents.
If you limit your boolean or data type to one bit then your application is at risk for memory curruption. How do you handle error stats in memory that is only one bit long?
I went to a job interview and one of the statements the program lead said to me was, "When we send the signal to launch a missle we just send a simple one bit on off bit via wireless. Sending one bit is extremelly fast and we need that signal to be as fast as possible."
Well, it was a test to see if I understood the concepts and bits, bytes, and error handling. How easy would it for a bad guy to send out a one bit msg. Or what happens if during transmittion the bit gets flipped the other way.
Some embedded compilers have an int1 type that is used to bit-pack boolean flags (e.g. CCS series of C compilers for Microchip MPU's). Setting, clearing, and testing these variables uses single-instruction bit-level instructions, but the compiler will not permit any other operations (e.g. taking the address of the variable), for the reasons noted in other answers.
Note, however, that std::vector<bool> is allowed to use bit-packing, i.e. to store the bits in smaller units than an ordinary bool. But it is not required.