Bit Addresability in AVR microcontrollers - Page 1
Forum section: electronics / general

author: BitsnBytes
author_rank: Contributor
timestamp: February 03, 2021, 05:30:10 pm
content: Hi All,I was reading a book and I came across a line"bit addressability is the most powerful feature of AVR microcontrollers".I read two assembly language instructions.SBI PORTA b0 //set bit of portACBI PORTA b0 // clear bit of portANote:PORTA is the SFR associated with PORTA of microcontroller.My question is how does the microcontroller access particular bit of a register. I mean the CPU point to particular location in memory by using the address of that location so I think CPU cannot point to the particular bit of the register unless it has the address of that bit. But I don't think each bit within a register is assigned an address.So how does SBI and CBI work and why do the book claim "bit addressability is the most powerful feature of AVR microcontrollers"Regards.

author: Siwastaja
author_rank: Super Contributor
timestamp: February 03, 2021, 05:35:33 pm
content: The SBI (or CBI) instruction itself contains both the peripheral address, and the bit address. As AVR instruction is just 16 bits wide, must include the opcode, and the bit number already requires 3 bits, this sets a harsh limit on the address space of IO registers.Practically this means that on larger AVRs, SBI and CBI are not available for some IO ports! Beware of this trap if you need performance; make sure beforehand what ports support SBI, CBI. C compiler takes care of the correct instruction for you, but the issue with performance remains; also the operation stops being atomic if you expect it to be!

author: 0xdeadbeef
author_rank: Super Contributor
timestamp: February 03, 2021, 05:40:03 pm
content: My understanding of similar approaches on other controllers is that operations like this are typically implemented as atomic (usually bus-blocking) read/modify access.

author: BitsnBytes
author_rank: Contributor
timestamp: February 03, 2021, 05:48:19 pm
content: Thank you for your reply.Quote from: Siwastaja on February 03, 2021, 05:35:33 pmGood point!!!Quote from: Siwastaja on February 03, 2021, 05:35:33 pmSo you mean each bit of the register has an address, but I never ever saw in datasheet the address of a bit.Excuse me please, I am confused!!!

author: BitsnBytes
author_rank: Contributor
timestamp: February 03, 2021, 05:56:39 pm
content: Atomic bit manipulation is a new topic for me.I am reading it...Thank you.

author: Siwastaja
author_rank: Super Contributor
timestamp: February 04, 2021, 07:17:00 am
content: No, the register has an address, bits have just the index from 0 to 7. SBI/CBI opcode contains both the register address and the bit index.The GPIO port registers are in the beginning of the IO address space on purpose so that their addresses fit low numbers so that SBI/CBI can be used. Yet in larger devices, the range still runs out.http://ww1.microchip.com/downloads/en/devicedoc/atmel-0856-avr-instruction-set-manual.pdfpage 151,Opcode 10011010 tells the CPU this is the SBI instruction,5 bits AAAAA tells the IO address (address space SBI/CBI can be used for from 0 to 31! Very tiny range!)3 bits bbb tells which bit to set.

author: 0xdeadbeef
author_rank: Super Contributor
timestamp: February 04, 2021, 11:42:34 am
content: Note that in other implementations, each bit might have a virtual address, i.e. this is the case of "bit-banding" on the Cortex-M3. This doesn't mean though that the architecture is actually able to transfer bitwise content on its buses. As I tried to explain before, the actual hardware implementation typically is a bus blocking atomic read/modify access of the whole byte/word/dword (whatever the bus architecture supports).So in this case of actual bit addresses, the ALU just determines the byte/word/dword address and the bit position from this virtual bit address.Also note that "bus blocking" means that the bus needs to be blockable. That's why in most implementation, these bitwise operations don't work on the whole address range respectively all buses.

author: Siwastaja
author_rank: Super Contributor
timestamp: February 04, 2021, 11:48:11 am
content: The AVR SBI/CBI is really very specific to the AVR architecture. I bet it's all custom, the CPU has "direct" access to the 32 first IO registers and just simply sets/clears the bits. The advantage of very small microcontollers like AVR is they are internally simple. Larger MCUs tend to be built from subcontracted intellectual property, have multiple clock domains, arbitrated buses, bridges, synchronization, etc.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: February 04, 2021, 11:53:10 am
content: The nuts and bolts of how it does it, could be various ways. Read on if you know a bit about CPU inner workings --There are also logical operations on some chips (Xmega, mega0?) which allow for the same functionality to any IO or memory address (depending). I haven't reviewed exactly to what all they apply, but I've seen them in a few instruction listings.Most likely, it's implemented as a normal read-modify-write cycle, but optimized in such a way that the operation doesn't have to go through the entire CPU, its ALU, up and down the data bus. It could be that a RMW cycle is, in fact, performed, but they're able to do it either in one complete CPU cycle (whether by generating extra timing pulses, or using multiple buses or ports*), or pipelined in such a way that the written value is settled before another instruction could possibly read its previous value. (I don't think AVR does much if any pipelining, so this is unlikely, but hey, maybe they've hidden it really well?)*It could be dual ported memory, at least in a specific range (all the more reason only a small address space can be accessed this way). That is, memory that is equipped with extra access signals, so that two buses can access it simultaneously. Also, adding buses anyways, means a lot of added hardware; it maybe wouldn't be a great approach.- It could also be memory or peripherals, equipped with specific hardware to perform the requested operation by itself. There is precedence for this, as the Xmega GPIOs for example have the usual OUT, DIR, IN registers, but also AND, OR and XOR shadow registers for the first two -- the obvious solution here is simply decoding operation by IO address (which is how they're arranged) and triggering the respective operation by that. I don't know that this would be feasible with typical SRAM hardware (still needs to do its own RMW cycle), but it would be another option besides dual porting.It could also be implemented directly in the data bus, where every peripheral has an interface that handles local sequencing of a RMW cycle. The common bus might have additional signals to trigger the OR, AND and XOR operations on the addressed interface. That could repeat a lot of logic (one interface for every peripheral?), but maybe a lot can be shared. Maybe it can even be shared all the way back to the bus master -- the CPU? But then what about DMA, when provided -- should it get the same features, or no?But yeah, just the IO instructions, they could even be special-purposed; they act like a register file, quick (1-cycle) access to another 32 locations. IIRC, some (early? tiny?) AVRs actually have a fully memory mapped register file, so that CPU registers themselves can be indexed. From this perspective, it might simply be the IO space is a limited extension of the register file, and the IO instructions might be better described as register-register logic/bit operations on that space.And that's not a crazy notion, in terms of some instructions accessing only certain subsets of registers -- LDI for example only works R16 and up. It might be that most instructions simply don't access the IO "register file".Tim

author: westfw
author_rank: Super Contributor
timestamp: February 04, 2021, 09:24:37 pm
content: It's worth pointing out that the AVR implementation of single-bit sets on IO ports has likely CHANGED since the original AVRs. The older AVRs took two cycles for SBI/CBI, somewhat implying a read/modify/write internal behavior. Starting with the xMegas, and continuing with (I think) all the other "AVRs" released since 2016, SBI/CBI only take a single cycle, somewhat implying that some other scheme has been implemented.(also, those newer AVRs tend to have far fewer "IO registers" within the "special address range" accessible via SBI/CBI, and they're less "general purpose", which means that per-bit hardware might be more practical than it used to be.)

author: BitsnBytes
author_rank: Contributor
timestamp: February 05, 2021, 05:27:50 am
content: Thanks for the reply.I got your point and I completely understand.Does the CPU write 1 on bit by option 1 or option 2.Regards

author: BitsnBytes
author_rank: Contributor
timestamp: February 05, 2021, 05:32:43 am
content: Thank you so much.Quote from: 0xdeadbeef on February 04, 2021, 11:42:34 amI understood!!!!

author: BitsnBytes
author_rank: Contributor
timestamp: February 05, 2021, 05:50:45 am
content: I actually don't understand very first line. Logical operations which allow same functionality to any IO memory address?Quote from: T3sl4co1l on February 04, 2021, 11:53:10 amBy the way thank you for such elaborative reply....

author: T3sl4co1l
author_rank: Super Contributor
timestamp: February 05, 2021, 08:33:44 am
content: Same functionality -- let me see here...- Xmega-D does not have it. Xmega-A series does.- Under "data transfer instructions",LAS Z, Rd Load and Set RAM locationLAC Z, Rd Load and Clear RAM locationLAT Z, Rd Load and Toggle RAM location2 clocks. Operation is described using a "temp" location. It is two clocks, so it's probably a streamlined RMW cycle -- compare with LD and ST which also claim single cycle operation to IO space (but with a 1-cycle penalty to SRAM -- curiously these do not have the same penalty!).Also haven't gone looking to see if GCC uses these. Probably uncommon; IO registers are usually one-offs, so an immediate address (LDS/STS) is easier, and doesn't clobber a register.Tim

author: bson
author_rank: Unknown
timestamp: February 05, 2021, 10:39:31 pm
content: It used to be common for 32-bit CPUs to have byte select pins for byte and word accesses, including single byte writes. There's no reason why for something like 32 I/O registers there can't be an 8-bit mask or 3-bit bit select associated with each write, to select which bit(s) to modify - or more specifically, which not to modify.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: February 05, 2021, 11:54:50 pm
content: Indeed! Ye Olde 80386, 486 did it this way (and, I suppose, later in the family as well; and, I suppose, since 8086-80286 really (16 bit), but not 8088 (8 bit external bus)). Though IIRC, they did it unary, i.e., byte enables for each byte in the DWORD. Translating that into an address requires a priority encoder. Which...doesn't mean much (4 bits unary <--> 2 bits binary), but gets worse if you imagine the same procedure down to single-bit granularity. In that case, it might be better to use a sub-address bus, and perhaps a span / bit width bus as well so that contiguous bits can be accessed. (I understand some old architectures had bit addressibility along with wider (16, 18, 24+ bit?) word access, I wonder if they did it this way.)Tim

author: Siwastaja
author_rank: Super Contributor
timestamp: February 06, 2021, 09:17:29 am
content: Many modern 32-bit CPUs like the STM32 series implement bit addressability of the GPIO registers in such a way that a 16-bit wide IO register has a 32-bit control register with 16 bits of "set" and 16 bits of "clear" command bits. The CPU doesn't need special instructions, one standard 32-bit bus write can set and/or clear, in one write, any number of bits. This is way more powerful than what AVR does.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: February 06, 2021, 12:13:16 pm
content: Yup, that's another good way to do it. Which, with the way wider buses areusuallyaddressed, that's almost exactly what the AVR GPIO registers are doing. Difference being, ARM is not byte-addressable, so it's definitely not exact.Also, I think the LPC family has IO registers by address space as well? That is to say, essentially: we have 32 bits of data bus and 32 bits of address bus, and a bus cycle is just an assertion of those 64 total lines and some strobes. If we reassign some of those address bits, effectively the memory space shrinks while the IO bus width grows. And with so much memory space to spare (i.e., a 4GB range), that's not terrible -- shrinking down to say 16MB (24 bits) in exchange for an effective 40 bits of IO.(Not sure if it's exactly like that, or I've completely misunderstood what little I've read about them!)Tim

author: S. Petrukhin
author_rank: Super Contributor
timestamp: February 10, 2021, 09:19:51 am
content: Pay attention to the aliases area.You can have access to each bit in the word as boolean value.For each bit in the available memory area, there is a word with a reflection of this bit.It seems awfully wasteful, but the Cortex developers were smoking some pretty good grass when they came up with it.

author: mikerj
author_rank: Super Contributor
timestamp: February 11, 2021, 08:32:03 am
content: Quote from: S. Petrukhin on February 10, 2021, 09:19:51 amThe address ranges used for bit banding would not otherwise be used, so how is it wasteful?

author: Siwastaja
author_rank: Super Contributor
timestamp: February 11, 2021, 08:39:42 am
content: Cortex-M microcontrollers having 4 gigabytes of addressable memory range and typically a few hundred kbytes of actual memory or peripheral registers, I wouldn't bee too concerned about "wasting" a few dozen words.Yet again, I kind of like the idea of the BSRR register much better than bit banding; bit banding is only efficient when writing one bit at a time, yet in fast GPIO access you often want to atomically set/clear multiple bits (for example: turn high-side MOSFET on and turn low-side MOSFET off) and the BSRR does that. Bit banding is of course a more general solution and can be applied as an extra layer.

author: S. Petrukhin
author_rank: Super Contributor
timestamp: February 11, 2021, 12:07:32 pm
content: Quote from: mikerj on February 11, 2021, 08:32:03 amWhy? You could have added anything to this area.I think you remember the words of Bill Gates something like this: "a computer will always have enough 640kB of memory."

author: Siwastaja
author_rank: Super Contributor
timestamp: February 11, 2021, 12:30:23 pm
content: No shit sherlock, I guess MCU manufacturers will start rethinking the wasted <1K when they are actually running out of the available 4Gbytes.It's just, I think once they come up with a real need for that 4 gig, it's quite likely saving a few dozen bytes from IO control won't satisfy their needs...For example, it's a good idea to map a long piece of address space for an external flash device, to avoid arbitrary limitations regarding the flash size. That is what the manufacturers do. But if they wanted to increase the maximum flash size from 1Gbytes to 2Gbytes, I'm pretty sure saving a few bytes somewhere isn't very helpful. Ultimately, when they want to support large external memories, they'll just decide to go for a 64-bit architecture.

author: S. Petrukhin
author_rank: Super Contributor
timestamp: February 11, 2021, 12:47:40 pm
content: Quote from: Siwastaja on February 11, 2021, 12:30:23 pmAnd they will spend even more on aliases a hole in the memory

author: Siwastaja
author_rank: Super Contributor
timestamp: February 11, 2021, 02:07:49 pm
content: You realize 64 bits gives you address space of 18446744073709551616 bytes? This is 18446744073 gigabytes. Aliasing 100 IO pins into 32-bit words means additional address space overhead of 0.0000093% in 32-bit addressing, or aliasing 100 IO pins into 64-bit words means additional address space overhead of 0.0000000000000043% in 64-bit addressing. What a waste!Address bus bits are not some magical scarcity like diamonds. Like any feature in a CPU, the purpose is to serve the programmers and users. Aliasing is doneon purpose, for a reason, and that reason is to make accesses easier, and/or faster. It's a great tool, not some kind of "problem" like you seem to think.Exactly for this reason 32-bit MCUs are commonplace now. Most of their use cases would be doable with address bus width between about 10 .. 20 bits. Yet it doesn't cost much to use 32 bits because there are benefits regarding simplicity. No one wants segmented memory, for example, or separate instructions to address flash (which is one of the reasons AVR suck). We work with such limitations if we have to, but if we can get rid of them, we sure will.

author: S. Petrukhin
author_rank: Super Contributor
timestamp: February 11, 2021, 02:37:09 pm
content: Quote from: Siwastaja on February 11, 2021, 02:07:49 pmI was joking a little...My youth is an x86 assembler, so I know what memory segmentation is and how now the entire address space is famously addressed with one register. I know what a port exchange is a separate instruction etc.Don't take it so seriously, sometimes you have to smile.

author: NorthGuy
author_rank: Super Contributor
timestamp: February 11, 2021, 05:09:31 pm
content: Quote from: Siwastaja on February 11, 2021, 12:30:23 pmKids waste address space. Real engineers waste real memory.

author: Bassman59
author_rank: Super Contributor
timestamp: February 11, 2021, 06:14:43 pm
content: Quote from: S. Petrukhin on February 11, 2021, 12:07:32 pmExceptBill Gates never said that.

author: Bassman59
author_rank: Super Contributor
timestamp: February 11, 2021, 06:20:00 pm
content: Quote from: BitsnBytes on February 03, 2021, 05:30:10 pmFor the record, the venerable 8051 has bit addressability as a feature, too. It works for the I/O lines of the four standard 8-bit ports. It also works for certain bytes in the DATA space -- the bytes are also overlaid into BDATA space -- so you can declare a variable as typebit(in Keil C51) and code like:bit foo;foo = 1;foo = 0;will toggle the bit foo exactly as you expect.

author: S. Petrukhin
author_rank: Super Contributor
timestamp: February 11, 2021, 08:54:29 pm
content: Quote from: Bassman59 on February 11, 2021, 06:14:43 pmMaybe he didn't, but it doesn't matter now, the notoriety is attached to him.I remember a time when people were happy with the 48kB (!) of memory in the assembled Sinclair, and your American guys flew to the Moon with a computer that had 256kB or something like that. I remember a time when programs worked without glitches, and then there was "as is". For those who were at the origins of "as is", I would suggest walking on "as is" bridges, flying on "as is" planes, etc.

author: S. Petrukhin
author_rank: Super Contributor
timestamp: February 11, 2021, 09:05:02 pm
content: Quote from: Bassman59 on February 11, 2021, 06:20:00 pmIn Pascal, there is a beautiful and simple solution for addressing bits:Code:varTimerEnableFlag : sbit;beginTimerAnableFlag:=false;orconstcTimerEnableFlag = 5;vari: word;RCC : word; absolute $74547;beginRCC.TimerEnableFlag:=true;RCC.B0:=0;for i:=1 to 4 do RCC.B:=CalcValueRCC(i);

author: westfw
author_rank: Super Contributor
timestamp: February 11, 2021, 11:11:52 pm
content: I find the "creative uses" to which CPU manufacturers put a 4G address space on chip family never intended to have more than a couple MB if code/data to be ... entertaining. Bit banding is one of them (which seems to be "out of style"; apparently it interacts badly with caching.) (equally entertaining is the things that they didn't throw address space at. Like Atmel SAMD chips having two 4-pin pinmux settings for even/odd pins in a byte.)Some of the NXP Arm microcontrollers have a "Bit Manipulation Engine" that extends the idea of bit-banding to include multi-bit fields.https://api.riot-os.org/group__cpu__kinetis__bme.htmlYou can think of the AVR sbi/cbi instructions containing both bit address and port address, but they're not really "general purpose addresses" in the sense that you could pass the address in a register or something. You COULD think of the AVR as having 256 distinct instructions for setting/clearing bits in a particular part of the chip. You can access the same bits with other instructions that use a more "typical" address, but only as byte-wide elements.