-
ARM (SAMC) memory mapping
Posted by
Simon
on 04 Jan, 2020 12:50
-
Looking at the datasheet for the SAMC range the addresses address individual bytes. Any 32 bit register is 4 addresses apart. Would this mean that an 8 bit variable would only use 8 bits of memory and not 32 bit?
-
#1 Reply
Posted by
Jeroen3
on 04 Jan, 2020 15:39
-
In
ARMv6-m the model is that bytes are addressable. But accessibility with byte width is not guaranteed.
Bits are no longer addressable as with older 8 bit architectures. Unless your chip has bit-banding, of which the usability is debatable.
However it may very well be required to read/write in full words (32 bits) or more in some regions.
Would this mean that an 8 bit variable would only use 8 bits of memory and not 32 bit?
Yes, of course 8 bits only use 8 bits of space.
Were you under the impressions that the minimum addressable unit was 32 bit? Since that would complicate things
a lot.
edit:
added link to armv6-m technical reference manual
-
#2 Reply
Posted by
Simon
on 04 Jan, 2020 16:05
-
Yes, of course 8 bits only use 8 bits of space.
Not if the smallest addressable unit is bigger. This is like the fallacy of the Boolean variables in say Arduino. The variable is 8 bits even if it only needs one bit. GCC for AVR has as a minimum 8 bit variables.
Were you under the impressions that the minimum addressable unit was 32 bit? Since that would complicate things a lot.
No it would just mean that every variable would take up 32 bits which would be very inefficient for flag variables that only need 1 bit but with byte addressing is more efficient if not perfect for sub 8 bit variables. the premise of my question is that it looks like each address is for 8 bits not 32 at least on the registers. Presumably it's the same for the RAM as this is where it would make a real difference to code density.
-
#3 Reply
Posted by
andersm
on 04 Jan, 2020 17:08
-
Not if the smallest addressable unit is bigger. This is like the fallacy of the Boolean variables in say Arduino. The variable is 8 bits even if it only needs one bit. GCC for AVR has as a minimum 8 bit variables.
The C language does not support a "bit" type. Compilers that do have it, use nonstandard extensions. You can use bitfields to pack flags, but they can produce rather inefficient code.
-
#4 Reply
Posted by
Simon
on 04 Jan, 2020 17:12
-
well yes a byte variable that only needs one bit is faster to test for 0 or 1 than having to drag a bit out of a byte full. but the stand alone variable will mean 8 times the memory used.
-
#5 Reply
Posted by
Simon
on 04 Jan, 2020 17:24
-
generally I just use 1 byte variables for flags but never had enough to worry about the memory used. Obviously on ARM it made sense to have the ability to address 1 byte at a time rather than every "word" or 1-16 bit variables would use 2 to 32 times the required memory space.
-
#6 Reply
Posted by
ataradov
on 04 Jan, 2020 19:01
-
No it would just mean that every variable would take up 32 bits
Imagine addressing an array of bytes if this were the case. That would be a total nightmare and architecture would be basically dead, since none in their right mind would use it.
-
#7 Reply
Posted by
Simon
on 04 Jan, 2020 19:43
-
which is what i thought but was just wondering
-
-
Couple things...
* Regarding "booleans", a C compiler will usually not "pack" several variables together on its own, and the smallest variable in C has byte size. So booleans or not, the only standard way of doing this would be to use bit fields, as variables themselves can't be any smaller than a "byte". The resulting size of such a struct with bit fields may still be larger than what's strictly needed, and is often not any smaller than an 'int' - the size of which depends on the platform. It may also not be as efficient to access.
* Regarding "bytes", this has been in a recent discussion about C. Yes the C standard doesn't actually guarantee that a "byte", which is pretty much defined as the same as a "char", is 8-bit. It' just the smallest usable size in C, and by definition, sizeof(char) is 1. sizeof() gives the size in bytes. Which again are not guaranteed to be 8-bit, but are implementation-defined.
* Now there is at least one detail in C99 standards and later, that IMO can't make a byte, as defined in the C standard, anything else than 8-bit. Warning, the following ONLY applies to C99+, not earlier standard versions. The reasoning is as follows: a "byte" is the smallest size a variable can hold. With C99+, the introduction of <stdint.h> makes int8_t/uint8_t available (some of the intxx_t are optional, but I think int8_t/uint8_t is mandatory.) It follows that the smallest size, as defined as a "byte", can't be larger than an int8_t/uint8_t, which is guaranteed to be exactly 8 bits. So, only on platforms that don't support the int8_t/uint8_t types, there could be a chance that a "byte" is not 8-bit. If a platform/compiler supports them, then a "byte" can't possibly be anything else than this, as it would imply, for instance, that sizeof(int8_t) is smaller than 1, which is not possible.
-
#9 Reply
Posted by
Simon
on 04 Jan, 2020 19:54
-
well as the address space seems to go every byte because all 32 bit registers have 4 bytes that can be individually addressed so clearly ARM addresses bytes although the data bus is 32 bit.
I would have thought that a micro-controller compiler would be tightly optimised to it's architecture.
-
#10 Reply
Posted by
ataradov
on 04 Jan, 2020 19:55
-
The bus is maximum 32-bits. There are size signals that indicate the desired transfer size.
Also, fetching a byte directly is more efficient than fetching a word and extracting a byte from that.
-
#11 Reply
Posted by
newbrain
on 04 Jan, 2020 22:25
-
* Now there is at least one detail in C99 standards and later, that IMO can't make a byte, as defined in the C standard, anything else than 8-bit. [...]some of the intxx_t are optional, but I think int8_t/uint8_t is mandatory.[...]
No, they are not. All types in
stdint.h are optional:
These types are optional. However, if an implementation provides integer types with widths of 8, 16, 32, or 64 bits, it shall define the corresponding typedef names.
So, no additional requirement on the architecture, as long as the minimum size requirement are fulfilled, i.e.
(u)int9_t is a perfectly acceptable "byte".
In C11, the typedefs are mandatory if 8, 16, 32, 64 -bits wide integers exist
and their representation is two's complement.No further changes in C18.
-
#12 Reply
Posted by
ataradov
on 04 Jan, 2020 22:43
-
From a practical point of view it does not matter. The only platform that have 16-bit "byte" are some DSPs and those are dying and quickly become irrelevant. Plus coding for those in C was always stupid anyway.
No one will make a processor with non-8-bit bytes.
-
-
* Now there is at least one detail in C99 standards and later, that IMO can't make a byte, as defined in the C standard, anything else than 8-bit. [...]some of the intxx_t are optional, but I think int8_t/uint8_t is mandatory.[...]
No, they are not. All types in stdint.h are optional:
These types are optional. However, if an implementation provides integer types with widths of 8, 16, 32, or 64 bits, it shall define the corresponding typedef names.
Ok, I thought they were, but wasn't entirely sure. Hence my cautious "I think". Just had to re-open the standard. Actually, the "int_least8_t" is the one that is required. Which makes sense.
What this implies then, is that a "byte" cannot be less than 8-bit IMO, following the same reasoning as above.
The rest of my post even more cautiously added: "So, only on platforms that don't support the int8_t/uint8_t types, there could be a chance that a "byte" is not 8-bit."
Which I think is correct in this form.
So, no additional requirement on the architecture, as long as the minimum size requirement are fulfilled, i.e. (u)int9_t is a perfectly acceptable "byte".
Indeed. But we still have a problem of handling multiples of "bytes" for the sizeof operator to be consistent. If a byte was implemented as a 9-bit word, logically any type that would be of sizeof 2 would have to be double that at least, so on such a platform, I don't think exact 16-bit words could in turn exist.
So take again my more cautious: "So, only on platforms that don't support the int8_t/uint8_t types, there could be a chance that a "byte" is not 8-bit."
Everytime int8_t/uint8_t types would be defined, I think you can safely assume that a byte is exactly 8-bit.
-
#14 Reply
Posted by
westfw
on 05 Jan, 2020 00:08
-
the address space seems to go every byte because all 32 bit registers have 4 bytes that can be individually addressed so clearly ARM addresses bytes although the data bus is 32 bit.
By "registers" here, presumably you mean "control registers for peripherals." The CPU registers r0..16 are NOT byte-addressable.
You have to be a little bit careful. The Microchip SAMC datasheet says explicitly:
the 8-bit quarters and 16-bit halves of a 32-bit register, and the 8-bit halves of a 16-bit register can be accessed directly.
But I don't think that that's necessarily true of all ARM architecture chips; I'm pretty sure I've seen some that only support 32bit reads of certain registers. Maybe that was the core ARM peripherals (SysTick, NVIC, etc):
The PPB address space only supports aligned word accesses. Byte and halfword access is UNPREDICTABLE.
I'm also not sure that you can always read multiple 8bit registers that happen to be adjacent...
Note that while there is still cause to conserve memory itself, there is LOTS "address space" available, and most ARM microcontrollers are more than happy to scatter peripheral config/status info across "many" bytes worth of registers. many of which have unused ("reserved") bits. Sometimes the layout is convenient, sometimes not (especially with the CM0's limit on index/offset addressing.)
-
#15 Reply
Posted by
ataradov
on 05 Jan, 2020 00:17
-
Yes, majority of peripheral registers on MCUs are 32-bit access only. Majority of registers on 32-bit MCUs are 32 bit only, not that 8- and 16-bit garbage.
The spreading happens naturally to save the resources on decoding logic. It is easier to decode big chunks of memory allocated to the peripherals. The peripheral then can use a few bits to decode the register within its chunk. The remaining bits may be left unconnected in decoders.
The result would be the all peripheral registers are aliased over the big chunk. But even if you want to trap the incorrect access, it is still easier this way.
-
-
Indeed.
And 32-bit address space is still gigantic enough for an MCU these days that you can largely afford to waste some of it (still a ridiculous amount compared to the 4GB available...)
-
#17 Reply
Posted by
Simon
on 05 Jan, 2020 10:06
-
what i was more interested in was that the addresses address 8 bits at a time so the smallest chunk of data handled is a byte so there is no point in having a variable smaller than a byte but as it does not address 4 bytes at a time it does not mean that 4 bytes of RAM have to be used no matter the size of variable.
I find the 8/16 bit access to the peripheral config registers a bit confusing as generally i would write them all in one go and i am worried about the caveats like synchronised registers. Usually i work out what an entire register needs to be and do it in one write if I am setting up a peripheral. I suppose where there are only one bit in a register byte that can be read/written as a byte as there is nothing else to upset without the need for read-modify-write.
-
#18 Reply
Posted by
newbrain
on 05 Jan, 2020 16:34
-
SiliconWizard, sorry if I was a bit dry in my note, but it was just meant to point out that the standard, as of today, still allows for "odd" architectures, not to contest your correctly phrased post.
Actually, the "int_least8_t" is the one that is required. Which makes sense.
[...]
What this implies then, is that a "byte" cannot be less than 8-bit IMO, following the same reasoning as above.
Indeed. But we still have a problem of handling multiples of "bytes" for the sizeof operator to be consistent. If a byte was implemented as a 9-bit word, logically any type that would be of sizeof 2 would have to be double that at least, so on such a platform, I don't think exact 16-bit words could in turn exist.
[...]
Everytime int8_t/uint8_t types would be defined, I think you can safely assume that a byte is exactly 8-bit.
Agreed on all counts, with the minor nitpick (as it would seem I'm at it...
) that the minimum bit size of "char" is clearly enforced in
5.2.4.2.1 Sizes of integer types <limits.h> (C99), part of "Environmental limits", so the int_least8_t is a consequence:
[...]
Their implementation-defined values shall be equal or greater in magnitude (absolute value) to those shown, with the same sign.
— number of bits for smallest object that is not a bit-field (byte)
CHAR_BIT 8
This was already true in C89, before the introduction of (always be praised) stdint.h.
Yes, majority of peripheral registers on MCUs are 32-bit access only. Majority of registers on 32-bit MCUs are 32 bit only, not that 8- and 16-bit garbage.
Eh...a vast majority, yes, unfortunately mixed with a lot of 16 bit legacy peripherals IPs even in modern and powerful MCUs (e.g. iMX RTxxxx and its PWM, TMR, ENC, mostly everything in MSP432 - lifted straight from MSP430? - etc. etc.).
-
#19 Reply
Posted by
Simon
on 05 Jan, 2020 16:56
-
I don't see the problem with 8 and 16 bit periphery registers. pins on SAMC is a good example. You have registers to setup a pin, but you have 2 pins per register so if you are trying to do anything vaguely automated that requires address arithmetic it just becomes harder although i suppose this is where the 8 and 16 bit access comes handy along with the byte addressing rather than word addressing as it makes writing code easier.
-
#20 Reply
Posted by
ataradov
on 05 Jan, 2020 17:37
-
Non 32-bit peripheral registers are plain annoying. Partially because it is not really predictable if certain register can be accessed by bytes or not. Not all of them can.
The problem of better pin manipulation is solved be actually designing better peripherals. For GPIOs, foe example, it would be bets to have two "views". One is for simultaneous manipulation of all the bits, and another for manipulating individual bits. In the first case you would have one 32-bit register representing pin direction, anther register representing state, etc. This can have optional mask applied as well. In the later case you would have an array of 32 registers representing all settings for each pin.
You can mix and match. You can initialize all pins at once, for example, and later use individual pins because that's what you want to do most of the time.
This will make writing code actually fun and easy. An all we have to do is make chip designers actually take input from programmers.
-
-
Bit access on some architectures is resolved with the use of masking registers. For instance, for some register (such as GPIO latches), there can be two associated registers, with each bit set either setting or clearing the associated bit in the target register. Some architectures even provide a third, "toggle" register to toggle bits. The benefit compared to single bit-addressing instructions is that you can modify one or several bits in just one instruction. You can usually still directly write to the latch registers as well, so that gives maximum flexibility IMO.
-
#22 Reply
Posted by
ataradov
on 05 Jan, 2020 18:27
-
Yes, absolutely, SAM C has all of that. The issue comes with more supplementary controls. Like drive strength, pull-up, alternative function, etc. All of that I would rather see located in a single register per pin. And usually all of that is spread all over the place. You can still have corresponding register for setting/clearing individual bits in this registers, of course.