Go Down

Topic: What's inside an at328 chip that allows it to read c code? (Read 3613 times) previous topic - next topic


@ Krupski... I remember the first frequency counter I built... Eight VFD tubes (1/2 inch tall 15 V devices) and a lot of  cmos CD4XXXAE devices. I used a 74S90 for 2 to 90 Mhz and an 11C90 to go to 500 Mhz.
It was a wonder and you could always buy a Moccasin Kit for $5.00, Too...

So Many Parts and so little time to learn.. (Sigh).

--> WA7EMS <--
"The solution of every problem is another problem." -Johann Wolfgang von Goethe
I do answer technical questions PM'd to me with whatever is in my clipboard


Re the lower-level explanations...

...something that shouldn't be left out of the discussion - which is rather important - is the role of the clock, and timing diagrams.

Basically, inside the processor, the main clock is used to generate multiple other clocks (which may be faster clocks or slower clocks) - which, when applied properly to the CPU/ALU/etc circuitry - keeps those pieces synchronized properly so that bits get read, pushed into a register, operated on, pushed out the memory, then the address stepped to the "next" address as indicated (usually by another register).

If you look into "bare" CPUs (take a look at the datasheet for an 8-bit CPU like the 6805 or Z80) - you'll find in there a "timing diagram" - that shows a linear representation of square-waves and their sequence to indicate when and how memory is read and written to, when address and data lines are active, etc. It can be a very, very complex dance.

I honestly don't know what such a diagram looks like for a modern processor (I'm not even sure if you can get a datasheet for modern 64-bit PC processors - at least easily - I haven't actually looked!) - but it is sure to be complex.

You can sometimes find timing diagrams on simpler parts that you might use with an Arduino - such as shift-registers and similar. I don't think there is much if any timing diagram, though, for the ATMega328 or others - simply because everything is "on-board" and there isn't any way to add peripheral devices to the address/data bus of the CPU in the controller. There may be one for the ATMega2560 - since you can add SRAM to it - but I am not certain there...
I will not respond to Arduino help PM's from random forum users; if you have such a question, start a new topic thread.


I honestly don't know what such a diagram looks like for a modern processor
You can find some timing diagrams in an AVR datasheet.  For example, those AVRs that support external data memory would have a familiar-looking timing diagram.

Some processors (like the Motorola 68xx series) also use "prebytes". ...
This avoids making the opcode map huge with special codes for EACH operation
It might have more to do with being an "upgrade" of a pre-existing architeture that didn't have a "Y register."
One of the big differences (real, rather than marketing) between a RISC cpu like the AVR and a CISC cpu like the 68xx is that a RISC cpu will tend to have a single (or very limited) set of instruction formats.  No pre-bytes, no different-length instructions depending on the arguments, etc.

In the old days, a well-designed cpu architecture had a lot of elegance to it.  You can look at the PDP-11 instruction format, and there's a set of bits for the operation, and as set for the source, and a set for the destination, some bits for modes...  With a bit of training, you can almost see how the hardware has to work, but you can see that it was also designed for humans (assembly language programmers) and by humans.  An AVR is by-contrast, "obviously" designed with the aid of CAD tools.  The same bits might be there, but they're scattered throughout the instruction (presumably in ways that make the hardware smaller and more efficient...)


The same bits might be there, but they're scattered throughout the instruction (presumably in ways that make the hardware smaller and more efficient...
Or not, with microcode I think it can be totally random.



Or not, with microcode I think it can be totally random.
Usually microcode based processors are slower (i.e. more clock cycles per instruction required) than state machines.

For example, compare something like a Motorola 6805 or 6809 to an 8088 or 8086 and look at similar instructions (for example, "LDAA immediate" versus "MOV AL, immediate" and see how many clock cycles each takes.

The microcode based processor is typically 4 times slower than an equivalent state machine based processor.
Gentlemen may prefer Blondes, but Real Men prefer Redheads!


Re the lower-level explanations...

...something that shouldn't be left out of the discussion - which is rather important - is the role of the clock, and timing diagrams.
With reference to my examples above, the "clock" simply tells you what to do next.  In the "brick" example, the first opcode out of reset is 0x10... "pick up something from somewhere". But, what then? The clock tells you to grab the next byte which is the code for "brick". Great, now you know "pick up brick", but from where? The clock kicks you to the next byte which tells you where to get the brick from (the pile), then the next clock goes on to the next instruction... forever.

The processor is always being clocked looking for the next instruction. Even if the program is finished, the processor is still looking for something to do and the programmer would write something like "end jump to end" so that the processor, even though it's just jumping in a circle, is still doing something.

This goes on forever unless reset is asserted or the processor is put to sleep or an interrupt temporarily diverts it's program flow (or it crashes  :) )

As far as timing diagrams, they are of no use to the particular things we are discussing here and would only complicate an already complicated (for a beginner) concept.
Gentlemen may prefer Blondes, but Real Men prefer Redheads!


There seems to be quite a bit of oversimplification and in some cases misinformation.
The Compiler does NOT generate .hex files and it does not directly create executable machine code.

I'll try to fill in a more complete picture of what is happening.

There are actually multiple steps under the hood that turn your C source code into something that can be uploaded to and then executed by the AVR.

The IDE is a big GUI wrapper around many command line tools that preform this process.
It also performs some Arduino "magic foo" to try to simplify things as well as  allow less technical users to supply incomplete C/C++ code and then convert that code into valid C/C++ code that can be compiled.

Here is a list of most of the steps:

The IDE scans your code and does some checks to try to determine which libraries are used.
It copies your code and the libraries it thinks are used to a temporary working area.
During the copying of these files, it modifies your source code to insert some additional header includes and then insert functions prototypes.
The IDE then calls the avr-gcc compiler to compile the modified source code.
The compiler is actually more than a single step.
The first step runs the source code through the C preprocessor to process things like #defines.
That resulting output is then fed to the compiler to generate assembler code.
The resulting assembler is assembled into a linkable .o object module.
After all the modules are compiled into object modules, the IDE will call the linker to link them all together to create a linked image in .elf format.
This is still not a binary image as it contains lots of symbolic information.
The IDE calls another tool to convert this linked .elf image file into a .hex file which is an ascii text file of S records which is still not a binary image.
The IDE calls avrdude to send the data in this .hex file to the arduino board either through a connection to a bootloader or directly using an ISP burning tool.
avrdude reads the .hex file and converts the records to binary and then pushes the binary information to the Arduino board using the appropriate protocol for interface being used.
Each S record in the .hex file is a block of data/code with an address. Avrdude uses this address information to know where to store the data inside the AVR.
When avrdude finishes its upload, the binary code/data image will be inside the AVR and the AVR executes the binary code.

The above is a bit simplified.
There are some additional handling for libraries and in particularly the Arduino "core" library.
Here is a bit of detail on that.
The core library contains all the low level arduino libary functions like digitalRead(), shiftOut(), etc....
The IDE builds all these modules and archives them into a real library .a file.
This .a file is linked in during the link step vs linking in each .o that is inside the .a file.
The linker knows how to pull out any needed core library code from any of the .o files inside the .a file.
All the other Arduino "libraries" (WIre, LiquidCrystal, etc..)  are not true libraries in terms of the compiler tools. The IDE builds all the modules for all the source files for each library that it thinks is used after scanning the sketch. But unlike with the core library modules, it does not create a true archive library .a file for them. Instead it just creates the .o objects for a "library" in a separate directory under the temporary working directory and then tells the linker to link in each individual .o file during the link step.

Hope that helps.

--- bill

Go Up