Hopefully, archive.org never goes away. Reason, go to page 3 at the other end of this link. What you're reading is an actual manual for an actual device meant to function as a CPU (ATMega 328P-PU, and older versions that aren't as cool). Mind you, at the time of writing this, it's less than two US dollars, while a "high end CPU" made by, say, Intel is over one thousand US dollars. Focus on the 28 PDIP (28 pins, Plastic Dual-Inline Package), since that's what I can get my hands on so cheaply. It's mean to be cheap. I thought about going right into coding here, but changed my mind, knowing that this thing probably isn't as easy to get if you're reading this in 2038. You should immediately notice that there are multiple definitions for each pin. Why? Because the programmer can change which function those pins have depending on which registers hold what values. Something like this could realstically do pretty much any task you want to hook up to a random gizmo, such as locking doors via the internet.

It has 32 kilobytes (or 32768 bytes or 262144 bits, since we use 1024 instead of 1000 for upscaling with bytes, since powers of two as much, much nicer to work with) of EEPROM to program, and it has 2 kilobytes of RAM, and 1KB of EEPROM for general memory saving. It has built in support for a few serial protocols, a few analogue to digital converters (look up what analogue vs digital is to save me the time of explaining), all at about 16 megahertz. To program the thing, you would set certain lines to certain values, then send data over serial connection and then it gets written to the EEPROM designed for programs. Usually you just use the onboard "boot loader" which is a program that many people put in the EEPROM before selling it to you, which allows for easy USB connection, instead of trying to get those pins set to what you want them to be.

So, what's the point? Well, notice there's more than one CPU with the same specs. The way these are built in reality, is that there are certain components that you're guaranteed to have. They also come with hardware that obscures the fact that there's a "pipeline." The idea of the pipeline, is that there are different steps to the process (getting info from RAM, executing instruction, storing the result, etc), and if you separate the components, you can make things alot faster by hooking them all up to the clock, having special conditions for when certain components "freeze" while the wait for the next component to finish doing what it was doing (for example, if the CPU is doing a divide operation, which usually takes longer than a single clock cycle), and just have each step doing it's own thing while other steps are doing their own things. This is made easier when you use firmware (hardcoded software) that translates the instructions. Many CPUs today don't actually directly understand the code they're supposed to. Usually, they have internal "code" that is more efficient than the code you write. While it's executing certain instructions, it's pulling in more code from wherever the program code comes from, the next stage is taking that and translating it, the next stage is storing it in a "cache" and any time code refers to itself, it might still be in the cache, which makes things execute faster.

But, you don't have to learn how it works. It more or less helps to know that it's there to help you, that it makes things faster, but you don't want to assume it can make miracles happen: you still have to write efficient code. We're constantly trying to figure out how to squeeze more out of our little chips. Thanks to abstraction, though, you can reap the benefits of the advances without having to think about them. However, if you figure out the strengths and weaknesses of the pipeline of the machine you're trying to speed up, it's helpful. It's also useful to note that a given processor is meant to react to instructions of it's "family." So, when i do x86 assembly, there's usually backwards compatibility. Some of the code i write in assembly for x86 now will still work in 2038. In fact, when I have you writing code, later, you'll find I'm relying on that idea. Below is some actual sample code for this processor. It's OK if you don't understand it, for it wasn't meant for anyone other than myself.

.macro cDelay num
    ldi r30, lo8(\num)
    ldi r31, hi8(\num)
    rcall Delay
.endm
;+-----+
;| IVT |
;+-----+
    jmp main ;RESET
    jmp default ;INT0
    jmp default ;INT1
    jmp default ;PCINT0
    jmp default ;PCINT1
    jmp default ;PCINT2
    jmp default ;WDT
    jmp default ;TIMER2 COMPA
    jmp default ;TIMER2 COMPB
    jmp default ;TIMER2 OVF
    jmp default ;TIMER1 CAPT
    jmp default ;TIMER1 COMPA
    jmp default ;TIMER1 COMPB
    jmp default ;TIMER1 OVF
    jmp default ;TIMER0 COMPA
    jmp default ;TIMER0 COMPB
    jmp default ;TIMER0 OVF
    jmp default ;SPI
    jmp default ;USART RX Complete
    jmp default ;USART empty
    jmp default ;USART TX Complete
    jmp default ;ADC complete
    jmp default ;EE Ready
    jmp default ;Analogue Comp
    jmp default ;TWI
    jmp default ;SPM Ready
;+-----------------+
;| Default Handler |
;+-----------------+
default: reti ;Ignore
;+------+
;| Main |
;+------+
main:
    sbi 0x04, 0x05 ;Enable LED to be turned on
    sbi 0x05, 0x05 ;Turn LED on
    cDelay 1000
    cbi 0x05, 0x05 ;Turn LED off
    cDelay 1000
    jmp main
;+---------------------+
;| Delay (WORD r31:30) |
;+---------------------+
Delay:
    ldi r28,lo8(4000)
    ldi r29,hi8(4000)
1:  sbiw r28,1
    brne 1b
    sbiw r30, 1
    brne Delay
    ret



What's it do? Well, the first bit is the "interrupt vector table." In other words, the first so many bytes of the code is the code that gets called when interrupts occur. Since this code was written when I was just starting out with this processor, I basically ignored everything (which was safe in this scenario, but not always safe in real life). The "reset handler" is a jump to "main," which basically turns on an LED, wastes time by "calling" the Delay function, then turns the LED off again, and goes into another Delay. The Delay function works by wasting time by constantly subtracting 1 from a register until that register is 0.

Notice that there are 58 lines of code. The first 5 are a macro, which allows us to make our own pseudo-instructions (fake instructions that represent a series of real instructions: this does not add instructions to the CPU, but merely these later get supstituted before the program is written to EEPROM). 12 lines are dedicated to those facey looking boxes that don't do anything other than help us identify sections. 25 lines make up the interrupt vector table. This leaves 15 lines to actually accomplish something (flashing the LED slow enough that we can see it turn on and off). This is the problem with peoples' first computer programs: most of their code they never understand, but often have to put there without knowing why. Unfortunately for you, I can't entirely avoid this, but I can make it easier for you, and that's one of my stretch goals for this tutorial series.

Get your own web kitty here!
┬ęCopyright 2010, 2011, 2012, 2013, 2014, 2017, 2018. All rights reserved.