Slik lages hardware med algoritmer

Jonas Julian Jensen forklarer deg "noe de færreste IT-folk vet": Hvordan man koder fram en mikrobrikke.

Med VHDL kan man skrive koden som utgjør en mikrobrikke. 📸: Preechar Bowonkitwanchai / Shutterstock / NTB scanpix
Med VHDL kan man skrive koden som utgjør en mikrobrikke. 📸: Preechar Bowonkitwanchai / Shutterstock / NTB scanpix Vis mer

Noe de færreste IT-folk vet er at digital elektronikk også designes ved hjelp programmeringsspråk. Det vil si for eksempel prosessoren i datamaskinen din, mikrobrikkene på hovedkortet ditt, eller grafikkprosessoren på skjermkortet ditt. Omtrent alle typer integrerte kretser inneholder digital logikk.

Det virker kanskje fjernt fra det relativt høye abstraksjonsnivået man jobber på når man programmerer for web, eller fra det beskyttede miljøet som et operativsystem gir, men det er faktisk IT-folk som har til oppgave å designe maskinvaren også.

Det gjør de nesten uten unntak ved å bruke et av de to maskinvarespråkene som finnes; VHDL eller Verilog/SystemVerilog. Disse tilhører en gruppe programmeringsspråk som kalles for HDLer. Det står for «Hardware Description Language». De er programmeringsspråk, og som navnet antyder, er de spesielt godt egnet til å designe maskinvare.

La oss ta et steg tilbake og definere hvordan «vanlige» programmeringsspråk virker før vi begynner å snakke om hva som kjennetegner HDLene. I sekvensielle språk som C, Java, aller JavaScript, starter prosessoren på første linje og utfører den ene instruksjonen etter den andre. Med mindre instruksjonen er «jump» eller «branch», blir de utført i den rekkefølgen de står i. Alt skjer i én enkelt tråd.

Sekvensielle programmeringsspråk kan også ha flere tråder (multi-threading), men i grunnen er hver tråd et nytt program som opererer på den samme stacken.

📸: Jonas Julian Jensen
📸: Jonas Julian Jensen Vis mer

Event-drevet programmering

HDLene kan derimot beskrives som parallelle, event-drevne programmeringsspråk. Språkene er turingkomplette. De kunne derfor ha vært brukt som et vanlig språk dersom noen hadde giddet å lage en kompilator eller tolk til dem, men det hadde nok vært lite praktisk. Det de derimot er veldig gode til, er å beskrive oppførselen til en krets som kan implementeres ved bruk av digital logikk.

La meg forklare hva jeg mener med et eksempel. VHDL-koden under viser en prosess, en slags program-tråd i VHDL. Denne prosessen trigges av at objektet «selector» endrer verdi. Når det skjer, kjører hele resten av koden på null tid, og prosessen går tilbake til å vente på neste endring av «selector».

MUX_1 : process
begin
 
  -- Vent til 'selector' endrer seg
  wait on selector;
 
  -- La verdien på 'mux_out' være bestemt av 'selector'
  case selector is
    when 0 =>
      mux_out <= x"A";
    when 1 =>
      mux_out <= x"B";
    when 2 =>
      mux_out <= x"C";
    when 3 =>
      mux_out <= x"D";
  end case;
 
end process;

Et viktig konsept i VHDL, er at alle instruksjoner unntatt de som begynner med «wait», tar null tid. Wait-linjene beskriver eventene som driver programmet videre. Når jeg sier at det tar null tid å utføre en instruksjon, tenker du kanskje at det umulig kan henge på greip.

Halvlederteknologien er rask, men den er ikke uendelig rask. Og det har du helt rett i, men med vissheten om at programmet skal implementeres i digital elektronikk, kan man likevel programmere som om det tar null tid.

Programmet over beskriver for øvrig oppførselen til en kjent digital komponent, en multiplekser.

En multiplexer (MUX) kopierer inngangen som er angitt av «selector» til utgangen. 📸: Jonas Julian Jensen
En multiplexer (MUX) kopierer inngangen som er angitt av «selector» til utgangen. 📸: Jonas Julian Jensen Vis mer

Klokkestyrt logikk

Nå som jeg har overbevist dere om at man kan anta at VHDL-kode tar null tid å utføre, lurer du kanskje hvor tidsbegrepet kommer inn i bildet. Svaret er at det er klokkesignalet som står for tidsstyringen i en digital krets. De aller fleste prosessene vil være direkte eller indirekte «sensitive» for klokkesignalet.

La oss se på et eksempel på en klokkestyrt komponent. Koden under beskriver en prosess som trigges av en stigende flanke på klokkesignalet «clk».

RAM_1 : process
begin
 
  -- Vent til den stigende flanken på klokkesignalet
  wait until rising_edge(clk);
 
  -- Skriv innholdet i wr_data til adresse wr_addr
  ram(wr_addr) <= wr_data;
 
  -- Les innholdet i adresse rd_addr ut til rd_data
  rd_data <= ram(rd_addr);
 
end process;

Programmet vil vente på den første linjen helt til klokkens stigende flanke detekteres. Deretter vil de neste to kodelinjene utføres på samme tid. Husk, alle linjer som ikke begynner med «wait», utføres på null tid. Det vil si at objektet «ram», som er en array, vil både skrives til og leses fra på samme tid.

VHDL opererer både med tidstrinn som tar tid, og tidstrinn som tar null tid (delta cycles). Slik kan man modellere prosesser som reagerer i forhold til hverandre på en deterministisk måte. Skriving til og lesing fra «ram» objektet skjer innenfor samme tidstrinn fordi det ikke er noen wait-linje mellom dem.

Denne koden implementerer også en velkjent komponent, nemlig dual-port blokk-RAM. Blokk-RAM er statisk RAM, i motsetning til den billigere dynamiske RAMen (DRAM) som utgjør hovedtyngden av minne i datamaskinen din.

To-ports RAM tegnet som en logisk komponent. 📸: Jonas Julian Jensen
To-ports RAM tegnet som en logisk komponent. 📸: Jonas Julian Jensen Vis mer

Syntese

Hvis du fortsatt henger med, lurer du sikkert på hvordan blir denne koden oversatt til et skjema over en fysisk, digital krets. Det foregår ved at man mater programmet inn i et synteseverktøy, en slags kompilator som forsøker å oversette koden til en digital krets. Synteseverktøyet er leverandør-spesifikk programvare, den er nært knyttet til målteknologien.

📸: Jonas Julian Jensen
📸: Jonas Julian Jensen Vis mer

Produktet fra syntesen er en nettliste, et kretsskjema. Kretsskjemaet vil være forskjellig avhengig av om det er programmerbar logikk (FPGA) eller skreddersydde integrerte kretser du lager (ASIC). Synteseverktøyet vil bruke komponentdatabasen for den aktuelle målteknologien til å sette sammen en krets som gjør akkurat det VHDL-programmet beskriver.

Place and route

Dersom syntesen er vellykket, sitter man igjen med en nettliste. Det er en logisk tegning over kretsen din. For at nettlisten skal kunne bli til en fysisk krets, må de logiske komponentene tilegnes fysiske komponenter med gitt plassering. Samtidig må koblingene mellom de forskjellige komponentene trekkes opp, slik at den fysiske implementasjonen blir lik den logiske.

Dette puslespillet er en tidskrevende prosess som utføres i en fase som heter Place and Route (PAR). Enda et teknologispesifikt programvareverktøy brukes for å få dette til. Leverandørene av programmerbare logiske kretser legger ned mye arbeid i disse verktøyene fordi de legger føringene for hvor avansert designet kan være. Syntese og PAR kan ta alt fra noen minutter til flere dager, alt ettersom hvor komplisert logikken er og hvor få ressurser man har tilgjengelig på brikken.

📸: Jonas Julian Jensen
📸: Jonas Julian Jensen Vis mer

Dersom PAR er vellykket, vil du nå sitte igjen med en annen type kretsskjema, en teknologispesifikk nettliste. Hvis målteknologien er en FPGA, kan nettlisten gjøres om til en bit-fil med konfigurasjonen for kretsen. Dersom det er en ASIC, er det noen flere steg som skal til før den kan sendes til fabrikasjon.

Hvordan komme i gang med programmerbar logikk

Det kan virke vanskelig å komme i gang med hardware-design fordi man må ha litt forståelse for den bakenforliggende teknologien. Det finnes heller ikke like mange ressurser lett tilgjengelig på nettet som for andre typer programmering. De etablerte aktørene kompliserer også hardware-design mer enn det som er nødvendig. Kanskje fordi kundene deres er store, høyteknologiske firma, ikke privatpersoner. Storforbrukerne av FPGA kommer fra telecom, defense, og aerospace. Bransjer som er kjent for å holde kortene tett til brystet.

Heldigvis går det an å programmere VHDL helt uten hardware. Alle VHDL programmer kjøres uansett i en simulator før de går igjennom syntese og PAR, det er den eneste måten å sørge for at de virker. Man kan ikke enkelt se inn i en integrert krets som ikke funker, printf-debugging er derfor ikke et alternativ. Med studentversjonen av en simulator, kan man prøve seg på VHDL-programmering helt gratis.

Noen FPGAer koster over $1000 stykket, men de billigste utviklingskortene for FPGA koster ikke mer enn noen hundrelapper. Et av dem er Lattice iCEstick til $25. Du kan komme langt med disse. Selv om de har færre ressurser, kan de brukes til mange morsomme prosjekter. Utviklingsprosessen er fortsatt den samme, det er derfor jeg har valgt denne som plattform til mitt neste kurs.

Det, og andre gratis kurs kan du finne på bloggen VHDLwhiz. Den tilhører undertegnede, og har som mål å vise at hardware-design ikke behøver å være vanskelig.