Beauty of load-store architecture
I assume the reader will have some idea about microcontroller architecture at least about 8051 architecture. It is easy to implement small projects using assembly language but on large complicated projects it will become difficult to track the logic, in those cases C or some other high level languages will come to our rescue. this is why because, these languages will have a long development history, less chance of finding bugs inside paradigm, chances of finding functions already implemented as libraries, more structured, easy to debug , readability etc. And another important quality is people having little idea of underlying microcontroller architecture can read the program and understand what’s going on in the program without much difficulty! So if we want to implement a microcontroller project using C or some high level language, which will be the best hardware platform among 8051 and AVR? This is our primary matter of discussion.
Actually AVR is RISC architecture (reduced instruction set computer) and 8051 is CISC (complex instruction set computer). To know the basic difference between these two, I have to explain few things…
Most of the time when compilers convert a high level program to a low level one the combination of instructions used is really small. Also when we are dealing with constant data (immediate) these constants will come under 13 bits of information, so it is easy to hide these data inside the instruction itself. If there is only a single accumulator there is a bottleneck in instruction execution as we have to put data, calculate it, move it to memory before another calculation starts. Also before 1980’s the matter of putting more registers into CPU were expensive.
All these things led to the development of RISC architecture. With lots of registers with accumulator power, no more you need to confine to a single register for your logical, arithmetical calculations.
Instruction sets became linear. We can code the instruction XYZ to any register may it be A or B or C, most of the case it will work. You don’t need to worry about whether this instruction XYZ will work with A and will act differently with another register B. To make this thing happen, developers avoided using register directly accessing memory for immediate data. So special instructions where put in practice which will either load or store to memory. Uniform, fixed length instructions with arithmetics restricted to registers were chosen to ease instruction pipelining in these simple designs, with special load-store instructions accessing memory. So commonly RISC architecture is known as LOAD-STORE architecture.I will use a simple comparison between 8051 and AVR to make this concept clear. Previously in 8051 we can use
ADD A, #32H
For adding immediate data 0x32 to accumulator content. But this Addition property rotated only around accumulator A. But in AVR, you cannot use
ADD R0, #32H
Because , it is in more linear in form like
ADD Rd, Rr
Where Rd and Rr can be anything between R0 to R31. The draw back is that we cannot use immediate data for calculation in these instruction. You should use LOAD-STORE structure to make this happen. Load the immediate data from memory to register, use it for calculation, return the results using store instructions to the memory. These things are valid for both program memory and data memory.
LDI R1, 0x32
ADD R0, R1
This will give the compiler a freedom to choose between registers. When they want to do some math, they can just use any available register. It no more needs to worry about moving data between STACK and REGISTER for smooth functionality.
And another major difference between CISC and RISC is that, in CISC a chunk of functionalities are implemented using a single instruction. But in RISC these kinds of instructions are avoided and jobs are done in small steps. For example consider the instruction in 8051:
DJNZ R0, label
Which will first decrement R0, compares to zero to see if it is zero, then if it is not zero it will execute a jump to the given label. In AVR these kinds of structures are split up into small functionalities like below.
The first instruction will decrement R0, in the same step it will affect the flags like Sign, Negative, Zero, etc. And the second instruction has nothing to do with R0 or any other register, it will just check the Zero flag and takes a decision, (BRNE: Branch if Not Equal or Not Empty) then what is the plus for this over the previous one?
In the first case No flags are affected, but the second case it will, so the compiler has the freedom of which flag to be checked. And also it will take 2 machine cycle (24 clock) to do this in 8051. But the second one will use 1+1 machine cycle (2 clock) for false condition and 1+2 machine cycle (3 clock) in true condition to do the same thing. Which means the number of instruction may increase but the ability to do things in nearly single cycle makes it a good choice for high level programming. Also if things can be done in single cycle the efficiency of pipe line increases, making less chance of breaking the parallel execution. Thus AVR will come as our primary choice for programming in high level language (if we are considering among 8051 and AVR). This discussion will not stop here, there are lot more factors which will make RISC architecture as the best choice to program in C. I will try to add those things in future.