Utvecklingsverktygen är kanske mindre intressanta vid en generell
diskussion kring arkitekturer. Även C-kompilatorn "skriver" ju assembler...
> Och jag tror att många andra värderar att slippa bankswitchning...
Men poängen är att även bankhanteringen görs på ett konsekvent sätt,
likadant för allt. Undantaget då "un-banked" memory, men det ger inget
fel och jag *tror* att macrot BANKSEL är smart nog att inte generera
någon kod i de fallen. PIC16F1xxx serien har en "linear address area" där
allt tillgängligt minne adresseras som en enda linjär adressrymd.
NU är det väl så, när det gäller PIC <=18 (gäller väl iofs alla arkitekturer) är man en duktig programmerare, så utnyttjar arkitekturens fördelar till fullo, vilket innebär att bankbyten hålls till ett minimum.
Skriver man i C/C++ så kan man för det mesta skita i allt, såvida man inte kör med GCC och PIC32, tyvärr är GCC så dum att den inte begriper att PIC32 har en mängd register som kan användas till en massa roliga saker, så vill man skriva snabb kod med GCC så är det lämpligt att deklarera lokala räknarvariabler till exempel som register.
TomasL skrev:
En AVR kör garanterat på en intern klockhastighet som är minst 4X den officiella, annars kan den inte fungera.
Jodå, skillnaden är att när man jobbar mot RAM kräver en AVR två instruktionscykler, PIC gör det på en.
Det innebär alltså att om man ska flytta ett värde från en adress i RAM till en annan så tar det lika många klockcykler på AVR som PIC, 4 klockcykler. Skillnaden är att det på AVR kräver två instruktioner, medans PIC gör det på en.
Sen blir då skillnaden att om man INTE jobbar mot RAM utan mot register så gör en AVR de flesta instruktioner på en intruktionscykel och därmed också en klockcykel.
På en PIC kan ingen instruktion gå snabbare än 4 klockcykler.
Det kan det inte i AVRen heller, Skillnaden är att man gömt den riktiga klockan för dig.
Och nej, det går inte avkoda och utföra en instruktion på en klockcykel.
In order to maximize performance and parallelism, the AVR uses a Harvard architecture
– with separate memories and buses for program and data. Instructions in the program
memory are executed with a single level pipelining. While one instruction is being executed,
the next instruction is pre-fetched from the program memory. This concept
enables instructions to be executed in every clock cycle. The program memory is In-
System Reprogrammable Flash memory.
The fast-access Register file contains 32 x 8-bit general purpose working registers with
a single clock cycle access time. This allows single-cycle Arithmetic Logic Unit (ALU)
operation. In a typical ALU operation, two operands are output from the Register file, the
operation is executed, and the result is stored back in the Register file – in one clock
cycle.
Det hela beror ju på hur man definierar "klockcykel".
Detta eftersom det är en omöjlighet att hämta, avkoda och utföra instruktionen på en klockpuls.
Klockan måste delas upp på flera faser, för att man skall kunna utföra något.
Det där handlar ju bara om instruktionerna, inte om data.
Såvitt jag vet har även PIC en pipeline-liknande pre-fetch, d.v.s. den hämtar en instruktion i förväg (vilket gör att man vid vissa villkorsoperationer måste exekvera en NOP på grund av att den pre-fetchade instruktionen inte ska utföras).
På en PIC måste minnet "alltid" involveras (när vi jobbar med variabler), det innebär (som jag skrivit tidigare) att en adress måste läggas ut på adressbussen och data måste latchas in eller ut. Det finns inget val. Detta tar ett extra steg.
På en AVR måste detta göras när man accessar RAM, men inte när man accessar register. Det har konsekvensen att så länge man jobbar med register så räcker en instruktionscykel, jobbar man mot RAM krävs två. Man har ett val, vill man spara tid jobbar man med främst register och kan halvera exekveringstiden. Det valet kan du inte göra på en PIC.
En PIC gör alltså alltid implicit LD och ST när man jobbar mot RAM (detta står för två av de fyra klockcyklerna i en instruktionscykel), på en AVR kan man hoppa över dem om man jobbar med register. Se mitt tidigare exempel med "Vad som händer".
"att en adress måste läggas ut på adressbussen ... men inte när man accessar register"
Alltså, en AVR har 32(?) register-variabler. Dessa måste väljas, alltså finns det en adress-buss åt detta. I själva verket är de bara en RAM-avdelning bland två och då arkitekturen är gammal eller att det är tagit ett val kan den adress som läggs ut bara adressera 32 adresser.
Ska man utöka detta antal finns det inte plats i instruktionerna till detta varför man måste ta till "utökad" adressering. Alltså kan man konstatera att det beror på att Atmel har sett till att instruktionerna är bakåtkompatibla.
Så skillnaden är att båda PIC och ATmega har en adressbuss för RAM men att ATmega inte kan adressera mer än en mindre del av den minnesbank direkt i instruktionerna medan PIC kan.
PIC kan klara detta då deras instruktioner inte är begränsade till 8 bit, de kör med båda 10, 12 och 14 bitars instruktioner men de hämtas som en samlat instruktion och inte två läsningar.
Z80 hade samma begränsning: i en byte kunde man klämma in ett val mellan IX eller IY, SP eller HL, BC eller DE osv. frö de olika funktioner. Det är helt enkelt en fråga om att grunden blev utvecklat då minne kostade seriösa pengar och man därför fick snåla med det.'
Så skillnaden i antal "register" mellan PIC & ATmega är obefintlig, ATmegan kan dock bara avsätta 5 bit till adressering av register i en instruktion medan Microchip har vald det antal bits per instruktionsord som täcker det önskade behov.
Du har nog inte fattat den skillnad men ett register är exakt identisk med en RAM-plats, det som skiljer är området instruktionsordet kan adressera. Och kör man med bytes som instruktionsord blir det till att ha en eller fler extra bytes med när adresser ut över ett visst antal behövs.
Skillnaden mellan register och RAM är att en och samma operation kan göras på flera register samtidigt.
Det går på en AVR att ha tre register "anslutna" till ALU samtidigt, två som källor och ett som destination.
Med RAM kan du inte adressera mer än en "cell" i taget. Ska du använda två variabler i RAM för en beräkning på PIC måste en av dem läsas in i W först.
Visst på en AVR måste alla variabler som ligger i RAM läsas in i ett register först, så ja, om alla variabler ligger i RAM så är det enklare att koda på PIC (men det tar ändå fler klockcykler). Men det är just därför AVR har många register, för att man inte ska behöva ha sån många variabler i RAM och register går snabbare.
En AVR har inte EN adressbuss för registren, den har flera (om man nu ska se det så). Den har en separat "buss" för källa och sen separat "buss" för destination. Det är detta som gör att den kan adressera flera register samtidigt.
AVR kör med 16 bitars instruktioner, inte 8. 2 st instruktioner ger 32 bitar.
Programräknaren räknar i word men det går att komma åt
enskilda bytes med hjälp av Z som pekare.
Jo, detta spelar roll om man t.ex. skall göra en sån loop som jag visade upp i exempel tidigare (ett par nästade loopar med variabler som räknas upp).
Då dessa variabler inte används utanför loopen är det utmärkt att ha dem i register, så slipper man den tidsödande accessen av RAM.
På en PIC kan du inte göra sånt. (Jag vet att ni försöker påstå att RAM på en PIC är register, men du kan INTE accessa flera variabler i RAM samtidigt på en PIC, på en AVR kan du accessa flera register i samma instruktion av typen var3=var2+var1. På en AVR måste du ladda in ena variabeln i W för en sån instruktion, och det kräver extra steg för att sen skriva resultatet till RAM eftersom du inte kan läsa var2 samtidigt som du skriver resultatet till var3.)
Jag vet inte exakt hur en AVR jobbar, men med största sannolikhet (baserat på vad jag läst om hur andra processorer jobbar) här det så här:
Instruktionen innehåller bitar som väljer registren för source1, source2 och dest till ALU. Denna avkodning görs i pipeline. När instruktionen ska genomföras är registren valda (adresserade via tre olika "adressbussar"). På uppåtgående klockflank klockas source1 och source2 in i ALU, på nedåtgående klockflank klockas dest (och flaggor) ut ur ALU.
PIC kan säkert koda av vilken adress som ska användas i sin pre-fetch, men det går inte att både adressera RAM och utföra en ALU-operation på samma klockcykel. PICen kräver 4 klockcykler för sin instruktion, där är klockcykel 2 eller 3 identisk med den som AVRen gör (data klockas in och ut ur ALU).
Även om PICen har bitar i instruktionen som pekar ut vilka adresser i RAM som är source1, source2 och dest så kan den inte adressera dem under en och samma plockpuls. Den måste klara av följande steg:
1. Lägg ut source-adress på adressbussen (minnet har en viss latens så det går inte att läsa/skriva direkt)
2. Läs-signal till minnet (nu ligger rätt data på databussen)
3. Klocka in data i ALU från databussen
4. Klocka ut resultat från ALU till databussen
5. Lägg ut dest-adress på adressbussen (kan eventuellt göras parallellt med föregående steg)
6. Skrivsignal till minnet
Det krävs alltså minst 5 klockflanker, troligen 6.
Hur som helst, det är praktiskt att ha 1024 bytes som hanteras på samma sätt.
Alla instruktioner fungerar mot allt. Inte olika instruktioner bereoende på vilken
del av tre som data råkara befinna sig i (och vilken halva av I/O memory som
registret råkar ha hamnat i). Inga I/O-register som har hamnat i "data space".
Och man läser programminnet med exakt samma kod som man läser indexerat
mot annan minne, inte separata instruktioner (LPM och liknande).
Nej, man kan inte göra "var3=var2+var1" direkt på en PIC, men å andra
sidan kan du bara göra det mot 32 bytes på en AVR. Det förutsätter att
du redan har plockat in datat i dessa "register".
En load/store arkitektur fungerar bra i stora RISC processorer, men i
8-bits processorer som AVR/PIC och liknande blir det mest en extra
lite onödigt komplexitet.