Oblig 2 - Design og simulering av CLA-adder i VHDL

Nedlastbar pdf - Merk introduksjonsteksten er noe forskjellig- oppgaven er ellers lik.

VHDL skiller seg fra andre programmeringsspr?k ved at det beskriver hardware, ikke software. Det vil si at VHDL koden ikke blir utf?rt p? en CPU, men i steden beskriver hvordan en krets med logiske porter kobles fysisk (blir implementert). I denne obligen er m?let ? f? ?velse i ? lage tre typer kode i vhdl: Dataflyt-, strukturell- og testbenkkode. Dataflytkode beskriver sammenkobling av logiske porter (AND, OR, XOR, osv). Blokker med logikk kaller vi ofte for moduler. Koden som kobler disse modulene sammen til st?rre systemer kalles strukturell kode. Alle systemer man lager m? testes (verifiseres) at fungerer som det skal. Sm? systemer kan testes direkte i et simuleringsverkt?y, men for st?rre system er det alltid gunstig ? automatisere testingen med en testbenk. Koden vi skriver testbenken i er VHDL, men den beskriver en sekvens av hendelser (omtrent som annen software*) i tillegg til ? beskrive eventuelle kretser vi trenger sammen med den vi skal teste. I enkleste forstand leser man av hvordan signalene inn og ut av kretsen endrer seg i waveform-vinduet til simuleringsverkt?yet, etter ? ha kj?rt testbenken. Vi kan ogs? skrive tesbenkkode som sjekker at utgangene til kretsen gir de resultatene vi forventer underveis og rapporterer til skjerm eller fil (selvsjekkende testbenker).

[* Det finnes verkt?y som lar oss skrive testbenker i vanlige programmeringsspr?k som for eksempel Python, men det er ikke pensum i dette kurset]

I denne obligen skal vi stegvis implementere en carry-lookahead adder(CLA-adder). Dette vil gi oss erfaring med alle typene kode nevnt ovenfor, i tillegg til ?velse i ? bruke et simuleringsverkt?y og lese av waveform-vindu. Til sist er det et m?l ? ?ke forst?elsen for oppbygningen av digital elektronikk generelt, slik at det blir lettere ? analysere hvordan de virker.

Oppgave 1 - Halvadder

M?let med denne oppgaven er ? bli kjent med hvordan vi benytter simuleringsverkt?y til ? analysere kretser ved utvikling av hardware. Verkt?yet vi bruker heter Questa (tidligere Modelsim) og er et kompilerings- og simuleringsverkt?y for hardwarespr?k (b?de VHDL og verilog). Vi skal bli kjent med Questa ved ? simulere en halvadder.

Bilde
Figur 1 - Halvadder

library IEEE; -- bibliotek
  use IEEE.STD_LOGIC_1164.all; -- pakke

entity halfadder is
  port(
    a, b : in std_logic; -- inputs
    s : out std_logic; -- sum
    c : out std_logic -- carry
  );
end entity halfadder;

architecture dataflow of halfadder is
begin
  s <= a xor b
  c <= a and b;
end architecture dataflow;

N?r du har lagret filen, skal du ?pne den i Questa. Questa er installert p? linux-systemet til ifi. For ? benytte Questa, m? linuxmilj?et ditt settes opp slik at lisensiering fungerer og at systemet kjenner stiene som er n?dvendige for ? kj?re programmet. Hvordan du setter opp dette er beskrevet p? siden FPGA_tools p? wikien til robin.

N?r milj?et er satt opp kan du kj?re vsim i terminalen for ? starte Questa.

I questa:

Det er lagt inn en feil i halvadderkoden, som gj?r at kompileringen feiler. Dette vises med et r?dt kryss ved siden av filnavnet i prosjektvinduet. Du kan se feilmeldingene ved ? h?yreklikke i prosjektvinduet og velge Compile -> Compile Summary. Fiks alle feil inntil filen kompilerer. Dette vises med en gr?nn hake ved siden av filnavnet. N?r filen er kompilert kan vi begynne simuleringen. Vi skal f?rst se p? simulering uten testbenk.

I Wave vinduet, vil du n? se fire r?de streker, en for hvert signal, samt at det st?r U i kolonnen Msgs ved siden av signalnavnene. Det betyr at den gule linja (cursoren) st?r et sted der signalene er uninitialized (derav U). For ? f? noe vettugt ut av et digitalt design, m? vi sette inputene til en verdi.

P? dette tidspunktet b?r alle signalene kunne leses av som 0.

Innleveringen i oppgave 1 skal best? av bildefilen halfadder.png.

Oppgave 2 - Fulladder og testbenk

Skriv en VHDL modul for en fulladder som vist p? Figur 2 nedenfor. Symbolet for en fulladder er vist i Figur 3. Modulen skal hete fulladder.vhd, og entiteten skal hete fulladder. Bruk navnene a, b og cin for inputene, og s og cout for outputene. Alle inputs og outputs skal v?re av typen std_logic.

Bilde
Figur 2 - Fulladder
Bilde
Figur 3 - Fulladder symbol

Sammenhengen mellom input og output for fulladderen skal v?re som angitt i sannhetsverditabellen:

a b cin cout s
0 0 0 0 0
0 0 1 0 1
0 1 0 0 1
0 1 1 1 0
1 0 0 0 1
1 0 1 1 0
1 1 0 1 0
1 1 1 1 1

For at testingen av disse verdiene skal g? smidig har vi laget en testbenk for fulladderen:


library IEEE;
  use IEEE.STD_LOGIC_1164.all;

entity tb_fulladder is -- testbenkentiteter er normalt tomme.
end entity tb_fulladder;

architecture behavioral of tb_fulladder is
  -- en komponent er en entitet definert i en annen fil, og som vi vil bruke.
  -- komponentdeklarasjonen m? matche entiteten.
  component fulladder is
    port(
      a, b : in std_logic;
      cin  : in std_logic;
      s    : out std_logic;
      cout : out std_logic
    );
  end component;
 
  -- Tilordning av startverdi ved deklarasjon gj?res med :=
  signal tb_a, tb_b, tb_cin : std_logic := '0';

  -- outputs b?r ikke f? en startverdi i testbenken, da det kan maskere feil.
  signal tb_s, tb_cout : std_logic;

begin
  -- instansiering:
  DUT: fulladder     -- Merkelappen DUT betyr ?device under test? som er en av mange
  port map(          -- vanlige betegnelser p? simuleringsobjektet.
    a    => tb_a,    -- Mappinger gj?res med =>, til forskjell fra tilordninger som
    b    => tb_b,    -- bruker <= eller :=
    cin  => tb_cin,  -- Mappinger kan ses p? en ren sammenkobling av ledninger
    s    => tb_s,    -- Vi mapper alltid testenhetens porter til testbenkens signaler
    cout => tb_cout  -- Siste informasjon f?r parantes-slutt har ikke ',' eller ';'
  );

  -- I testbenker kan vi ha prosesser uten sensitivitetsliste..
  -- i slike prosesser kan vi angi tid med ?wait? statements, og
  -- vi kan sette signaler flere ganger etter hverandre uten ? gi konflikter.
  -- NB: Prosessen vil trigges om og om igjen om vi ikke hindrer det.
  process
  begin
    wait for 10 ns;
    tb_a <= '1';
    tb_b <= '0';
    tb_cin <= '0';
    wait for 10 ns;

    report("Ferdig!") severity note;
    std.env.stop; -- stopper simuleringen
  end process;
end architecture behavioral;

N?r simuleringen stopper vil modelsim automatisk hoppe inn i koden der den stoppet. Vanligvis kommer dette vinduet opp foran wave-vinduet. For ? f? frem wave-vinduet igjen, kan man enten lukke vinduet med koden, eller trykke p? wave-tab’en som dukket opp i underkant av vinduet.

Innleveringen i oppgave 2 skal best? av filene: fulladder.vhd, tb_fulladder.vhd, fulladertest.png og fulladdertest.vcd.

Oppgave 3 - CLA-blokk med testbenk

Carry-lookahead adder (CLA)

Carry-lookahead addere er beskrevet i kapittel 5.2 i l?reboka (s241). I denne oppgaven skal vi lage en 32-bits CLA adder og teste den med simulering. Det er ikke n?dvendig ? forst? hvorfor CLA adderen vil virke for ? fullf?re denne oppgaven, men vi h?per oppgaven kan hjelpe til ? avmystifisere hvordan den er bygget opp.

Innholdet i CLA blokken er vist p? to m?ter i Figur 4 og Figur 5.

Bilde
Figur 4 - CLA adder
Bilde
Figur 5 - CLA adder

Utgangspunktet for designet er figur 5.6 p? side 242 i l?reboka. Vi deler CLA adderen i 3 forskjellige designmoduler. Den innerste modulen har du allerede laget. Det er fulladderen fra oppgave 2. Videre lager vi i denne oppgaven en modul for CLA-blokken. CLA blokken skal danne logikken beskrevet i den bl? stiplede firkanten i Figur 4/5, og vil da legge sammen to 4-bit tall. CLA blokken vil benytte fulladderen, og vil derfor ha b?de strukturell- og dataflytkode. Etterp?, i neste oppgave, setter vi sammen flere CLA blokker i en modul som skal hete CLA_top, slik at vi kan legge sammen tall som er st?rre enn 4 bit. Hver designmodul skal ha sin egen testbenk.


entity CLA_block is
  port(
    a, b : in std_logic_vector(3 downto 0);
    cin  : in std_logic;
    s    : out std_logic_vector(3 downto 0);
    cout : out std_logic
  );
end entity CLA_block;

Bruk entitetsbeskrivelsen for CLA_block ovenfor, og skriv og kompiler CLA-blokk-modulen:


min_l?kke: for i in 1 to 5 generate ny_komponent: min_komponent
  port map(
    epler => eplesignal(i),
    p?rer => p?resignal(i)
  );
end generate;

Lag en testbenk for ? teste CLA_blokken. Testbenken skal hete tb_cla_block.vhd. Benytt assert slik at testbenken stopper ved feil.

Eksempel p? assert-statement:

assert(i = j) report ("i er ulik j") severity failure;

assert rapporterer n?r det boolske uttrykket inni parantesen er usant. Alvorlighetsgraden (severity) har fire niv?er: note, warning, error, failure. Bare failure stopper simuleringen. Report kan ogs? brukes alene, uten assert, og vil da alltid skrive ut beskjeden.

Velg én av metodene under:

Innlevering i oppgave 3 skal best? av VHDL filene cla_block.vhd, tb_cla_block.vhd og en tekstfil med kopi av outputen i konsollvinduet for siste kj?ring.

Oppgave 4 - CLA-toppmodul med strukturell kode og testbenk


entity CLA_top is
  generic(
    width : positive := 32;
  );
  port(
    a, b : in  std_logic_vector(width-1 downto 0);
    cin  : in  std_logic;
    sum  : out std_logic_vector(width-1 downto 0);
    cout : out std_logic
  );
end entity CLA_top;

Bruk entitetsbeskrivelsen ovenfor og lag og kompiler toppmodulen slik at den kan utf?re 32 bits addisjon. Filnavnet p? toppmodulen skav v?re cla_top.vhd. CLA_top skal benytte ?tte CLA-blokker til ? utf?re beregningen. Du velger selv hvordan du instansierer komponentene.

Lag en testbenk som tester ut 10 forskjellige tallkombinasjoner etter tur og rapporterer eventuelle feil. Tallkombinasjonene b?r inneholde noen tall som bruker, og noen som ikke bruker, de mest signifikante bitene i a og b. Eksporter waveformen som en vcd fil CLA_top.vcd som viser kj?ringen med alle input og output.

Innleveringen i oppgave 4 skal best? av toppmodulen cla_top.vhd, testbenken tb_cla_top.vhd og en waveform CLA_top.vcd som viser kj?ringen med alle verdiene for input og output.

Hint (valgfritt ? benytte):

I VHDL kan man ikke uten videre oversette mellom tall (integer) og andre typer slik som std_logic, men det finnes biblioteker som kan gj?re det.

For tallkonverteringer benytter vi biblioteket IEEE.numeric_std

Her er et eksempel p? deklarering av biblioteket:


library IEEE;
  use IEEE.STD_LOGIC_1164.all;
  use IEEE.numeric_std.all;

Hvis vi skal konvertere et heltall til en std_logic_vector, m? vi f?rst bestemme oss om vi vil ha med fortegnsbit eller ikke. For ? benytte fortegn har biblioteket en type som heter signed, mens uten fortegn har vi unsigned. Disse typene best?r av std_logic_vectors, og man m? angi bitbredden p? samme vis. N?r vi konverterer et tall til f.eks unsigned, s? m? funksjonen vi bruker ha beskjed om hvor mange bit vi skal ha. Her f?lger eksempel p? konvertering fra integer til std_logic_vector og fra std_logic_vector til integer uten fortegn:


signal my_sig : std_logic_vector(31 downto 0);
signal my_int : integer;

...

my_sig <= std_logic_vector(to_unsigned(my_int,32));

my_int <= to_integer(unsigned(my_sig));