Er zijn verschillende soorten assembler, elke computerarchitectuur heeft er zijn eigen dialect van en hetzelfde kan je zeggen van microcode; een expert in x85-assembler hoeft dus ook geen expert in powerpc of avr-assembler te zijn en exact hetzelfde als het gaat over microcode (maar nog extremer).
Om gewoon te schetsen hoe programmeertalen min of meer in elkaar zitten:
een hoge programmeertaal (pascal, C, ...) kan je door een compiler laten omzetten in machinecode, dit kan je in feite zien als binaire vorm van assembler. Assembler-code wordt door een assembler vrij makkelijk omgezet naar die machinecode (met het voordeel dat je in assembler variabelen als naam kan gebruiken, in machinecode worden dat gewoon getalletjes en dat gelijkaardige operaties eenzelfde naam hebben in assembler maar een verschillend nummer kunnen hebben in machinecode: voor de machine is het anders om een constante op te tellen bij een register of twee registers op te tellen). Één instructie in een hoge taal zoals:
Code:
IF a = b
THEN
bla;
ELSE
blabla;
END;
wordt omgezet naar verschillende commando's in assembler (of machinecode, maar dat noteer ik niet):
Code:
JNE a, b, labelELSE
bla
JMP labelEND
labelELSE:
blabla
labelEND:
Hoe dat vertalen exact gebeurt, hangt een beetje af van wat voor architectuur je hebt; instructies kunnen op een andere architectuur mogelijk helemaal anders vertaald worden. In een architectuur zonder aftrekking, moet je om te kunnen aftrekken gewoon het negatieve getal bij optellen.
Met microcode gebeurt er iets gelijkaardigs: elk assemblercommando (of beter: elke instructie in de machinecode) wordt omgezet in nog kleinere instructies: bv. haal waarde uit register X, schrijf deze naar de adresbus van het geheugen, ... Voor het bovenstaande voorbeeld zou dat voor enkel de eerste JNE-instructie bv. kunnen zijn:
Code:
pop een waarde van de stack naar tijdelijk register
plaats de waarde van het tijdelijk register naar ALU-ingang 1
pop een waarde van de stack naar tijdelijk register
plaats de waarde van het tijdelijk register naar ALU-ingang 2
pop een waarde van de stack naar tijdelijk register
plaats de bitsequentie voor aftrekken op controleingang van ALU
controleer de uitgangsflag "gelijk aan 0?" van de ALU
als deze flag gezet is: plaats de waarde van het tijdelijk register in de instruction pointer
haal de volgende instructie op
Deze hangen dus even hard vast aan de architectuur: op een architectuur zonder tijdelijk register zal je bovenstaand voorbeeld niet kunnen runnen. Je moet de processor dus op een veel gedetailleerder niveau kennen om microcode te schrijven: sommige locaties die je in microcode hebt, zijn anders dan in assembler. Stel dat je A en B wilt optellen, ga je over het algemeen A naar de ene ingang van de ALU voeden, B naar de andere ingang, op een controleingang de bits voor optelling en het resultaat ergens anders weer wegschrijven. Maar in assembler kan je niet direct aan de controleingangen; dat gaat in microcode wel. Dat omzetten naar microcode wordt in de processor gedaan; in de meeste gevallen moet je je daar dus niets van aantrekken tenzij je zelf een processor zou bouwen of dat je leert hoe het werkt.
Heel simpel gesteld: met een hoge taal maak je de computer (maar vooral jezelf) wijs wat er moet gebeuren, met assembler maak je de processor wijs wat er moet gebeuren en met microcode maak je elk van de onderdelen van de processor duidelijk wat ze moeten doen.