So I've been looking into branchless programming to speed up code and I'm curious as to how exactly Arduino (or rather atmega328) actually reads machine instructions. Does it have a memory cache or does it read every instruction from the flash memory?

From my understanding of branchless programming it speeds up the computation because the CPU does not have to jump inside the instructions and can read it sequentially, hence does not need to load in new instructions in case it has to jump to a location that's not loaded.

My question is, does this apply to the atmega328? If it reads every instruction straight from flash without using a cache then it shouldn't matter much if it has to jump in the instructions, right?

  • 1
    no cache ... no loading of instructions during execution ... you would save a bit of time on each eliminated jump instruction ... so, if you are running an oscilloscope sketch, then run inline code from begining to end – jsotola Sep 10 '20 at 0:34
  • Even inline is just a suggestion though right, and the compiler can do as it pleases? You should also compile with optimization level -O3 for speed instead of -Os for size. – Gabriel Staples Sep 10 '20 at 0:46
  • @Beacon of Wierd, post this on avrfreaks.net too to see what they say, and give us a link here to it. I'd like to know, and they have a lot more low-level experts and advanced AVR users over there I imagine. – Gabriel Staples Sep 10 '20 at 0:49
  • Branchless doesn't make a lot of sense to me for AVRs. I'd suggest learning to read the assembly code generated by the compiler (avr-objdump -S <filename>.elf). Then compare different versions of your algorithms to each other. I like to use wdt_reset() to add a marker before a certain section I'm interested in. Then in the assembly code look for the wdr instruction. – Gerben Sep 10 '20 at 18:04

There is no cache, so you don't need to worry about that. All instructions are fetched direct from flash and executed straight away.

There is, though, a 2-stage pipeline. That means that in one clock cycle an instruction is fetched from flash, and in the next clock cycle it's executed - and while that is being executed the next instruction is being fetched ready.

That means that when a branch occurs, since the AVR uses a very very simplistic approach to branch prediction (i.e., it assumes the branch will not be taken and just loads the next instruction regardless), it has to discard the contents of the pipeline and start from scratch.

That's only a one clock penalty while it loads the newly-branched-to instruction, but it's still a penalty.

Cache is only needed when the CPU core runs faster than the memory can be accessed. Since the AVR only runs at up to 20MHz that is considerably slower than the flash can be accessed, so adding cache would be completely pointless. Other faster MCUs do use caching, such as the 200MHz PIC32MZ, since otherwise "wait states" would have to be introduced to slow the reading from flash down.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.