Ne pišete programa. Opisujete vezje.

Praktičen uvod v SystemVerilog za programirljiva vezja FPGA. Vsako poglavje vsebuje kratko razlago, delujočo kodo in napako, ki jo na tem mestu naredi večina začetnikov. Opombe o orodjih predpostavljajo Intel/Altera Quartus Prime in razvojno ploščo DE0-Nano.

  • Jantarna: kombinacijska logika, brez pomnilnika
  • Modra: sekvenčna logika, registri in taktni signal

Primere zaženite sami. Bloki kode s povezavo Simuliraj odprejo ustrezen primer v učnem simulatorju, kjer lahko kodo urejate in opazujete časovne poteke signalov. Vsak blok kode ima tudi gumb Kopiraj. Oba nabora primerov:

Spletni simulator vhode krmili iz stimulacijskega bloka, zato tam testnega okolja ni treba pisati. V Quartus Prime ga pišete sami (poglavji 11 in 12). Quartus sam nima simulatorja: simulacijo požene ModelSim oziroma Questa Intel FPGA Edition, ki ju namestite skupaj z njim.

Kazalo

    1. Koda, ki postane strojna oprema

    Programska oprema je seznam ukazov, ki jih procesor izvaja enega za drugim. Modul v SystemVerilogu je drugačen: opisuje gradnike vezja in povezave med njimi. Vsak assign in vsak blok always postane svoj gradnik vezja, vsi gradniki pa so aktivni istočasno.

    two_gates.svkombinacijska
    module two_gates (
      input  logic a, b,
      output logic y, z
    );
      assign y = a & b;   // vrata AND
      assign z = a | b;   // vrata OR, ki obstajajo istočasno
    endmodule
    a b IN ALI y z

    To je načrt vezja, ki ga zgradijo orodja. Če zamenjate obe vrstici assign, dobite popolnoma enako vezje, ker vrstni red v opisu ni vrstni red v času.

    Pogosta past za programerje. Kode ne berite kot „najprej to, potem ono“. Vprašajte se raje: kakšno strojno opremo ustvari ta vrstica in s čim je povezana?

    Pomembni pojmi

    • Simulacija na računalniku izvede opis modela vezja in prikaže časovne poteke signalov. Z njo preverjate obnašanje.
    • Sinteza pretvori opis v gradnike vezja v tehnologiji FPGA. Sintetizirati je mogoče le podmnožico jezika.

    V spodnjih izsekih so deklaracije včasih izpuščene, da ostane vidno samo bistveno.

    2. Biti in vektorji

    Povezava oz. žica prenaša en bit: 0 ali 1. Vektor je skupina povezav z enim imenom in je osnovni podatkovni tip pri načrtovanju FPGA. Ali skupina pomeni nepredznačeno število, predznačeno število ali zgolj vzorec zastavic, je stvar interpretacije; žicam je vseeno.

    Preizkusite: kliknite bite, da jih obrnete, in opazujte, kako se istih osem bitov interpretira na različne načine.

    8-bitni vektor: logic [7:0] data

    Bit 7 je najpomembnejši bit (MSB), bit 0 najmanj pomemben (LSB).

    Binarni zapis
    Šestnajstiški zapis
    Nepredznačen desetiški
    Predznačen desetiški (dvojiški komplement)
    data[7:4]
    data[3:0]
    vectors.svkombinacijska
    logic [7:0]  data;
    logic [3:0]  hi, lo;
    logic [11:0] padded;
    logic [7:0]  ones;
    
    assign hi     = data[7:4];            // rezina: štiri od osmih žic
    assign lo     = data[3:0];
    assign padded = {4'b0000, data};      // zlepljanje: združi vektorje
    assign ones   = {8{1'b1}};            // ponavljanje: osem kopij enice
    
    logic signed [7:0] temperature;       // od -128 do 127
    logic        [7:0] level;             // od 0 do 255

    Številski zapisi imajo obliko širina ' osnova vrednost: 4'b1010 je štiribitna vrednost v dvojiškem zapisu, 8'hFF je osem bitov v šestnajstiškem, 8'd200 je osem bitov v desetiškem. Širino vedno zapišite, saj tak zapis prepreči množico tihih napak.

    3. Kombinacijska logika

    Kombinacijska logika nima pomnilnika. Izhod je odvisen samo od vhodov v tem trenutku. Ko spremenite vhod, mu izhod v realnem vezju sledi s kratko zakasnitvijo. Obnaša se kot formula v preglednici: rezultatska celica je vedno usklajena s celicami, na katere se sklicuje.

    add_compare.svkombinacijska
    module add_compare (
      input  logic [7:0] a, b,
      output logic [8:0] sum,        // en bit širši, da ohrani prenos
      output logic       a_bigger
    );
      assign sum      = a + b;       // 8-bitni seštevalnik
      assign a_bigger = (a > b);     // primerjalnik
    endmodule

    Napisali ste „seštej“ in „primerjaj“, ne vrat. Sintezno orodje izbere, kako ju zgraditi iz vpoglednih tabel (LUT) v FPGA. Zato se praktično načrtovanje FPGA dela z vektorji in aritmetiko, skoraj nikoli s posameznimi vrati.

    Širina je pomembna. Seštevek dveh 8-bitnih števil ima lahko 9 bitov. Če bi bil sum širok le 8 bitov, bi se prenos izgubil brez kakršnega koli sporočila o napaki.

    4. Vrata na kratko

    Logičnih vrat vam ni treba načrtovati ročno, a jih morate prepoznati, saj so operatorji poimenovani po njih. Vrata so drobno kombinacijsko vezje nad posameznimi biti. Pri vektorjih operatorji delujejo na vseh bitnih mestih hkrati.

    OperatorVrataPomenPrimer
    &IN (AND)1 samo, če sta oba vhoda 1a & b
    |ALI (OR)1, če je vsaj en vhod 1a | b
    ^XOR1, če se vhoda razlikujetaa ^ b
    ~NE (NOT)obrne bit~a
    ? :MUXizbere enega od dveh vhodovsel ? a : b

    Če operator postavite pred en sam vektor, združi vse bite v enega. Ti redukcijski operatorji so zelo uporabni:

    reduction.svkombinacijska
    assign all_ones = &data;            // 1 samo, če so vsi biti 1
    assign any_set  = |data;            // 1, če je vsaj en bit 1
    assign parity   = ^data;            // 1, če je število enic liho
    assign masked   = data & 8'h0F;    // ohrani spodnji nibble, ostalo pobriše

    Izbiralnik ali multiplekser (mux) je najpogostejši gradnik vezja. Vsaka odločitev, ki jo napišete, postane izbiralnik. O tem govori naslednji del.

    5. Odločitve postanejo izbiralniki

    Izbiralnik ima več podatkovnih vhodov in izbirni vhod. Izbirni vhod določi, kateri vhod pride na izhod. V strojni opremi obstajata vedno obe možnosti; izbira samo izbere med njima. Tri različne notacije opisujejo isto vezje:

    mux_forms.svkombinacijska
    // 1. Pogojni operator
    assign y1 = sel ? a : b;
    
    // 2. if / else znotraj always_comb
    always_comb begin
      if (sel) y2 = a;
      else     y2 = b;
    end
    
    // 3. case, najboljši za veliko izbir (mux 4 v 1)
    always_comb begin
      case (sel4)
        2'd0:    y3 = in0;
        2'd1:    y3 = in1;
        2'd2:    y3 = in2;
        default: y3 = in3;
      endcase
    end

    always_comb je blok, ki se znova izračuna, kadar koli se spremeni karkoli, kar bere. Znotraj tega bloka zapisujete prireditve z operatorjem =.

    Nenamerni zapah (latch)

    Če blok always_comb ne dodeli vrednosti izhodu na vseh poteh, si mora vezje zapomniti staro vrednost. Orodje zgradi zapah (latch), pomnilni element, ki ga niste nameravali narediti in ga običajno ne želite.

    latch_bug.svnapaka: izpelje zapah
    always_comb begin
      if (en) y = a;        // kaj je y, ko je en 0? Obdrži staro vrednost
    end
    latch_fix.svpopravek: najprej določi privzeto vrednost
    always_comb begin
      y = '0;               // privzeta vrednost za vse poti
      if (en) y = a;
    end

    Navada, ki jo vzgojite. Vsak blok always_comb začnite s privzetimi vrednostmi za vse njegove izhode in v case vedno dodajte vejo default.

    6. Ura, flip-flopi in registri

    Vezja, ki si zapomnijo, potrebujejo pomnilni element. Osnovni je flip-flop: enobitni pomnilnik, ki pogleda svoj vhod samo v enem trenutku, ob naraščajočem robu ure, in to vrednost zadrži do naslednjega roba. Register je vektor flip-flopov, ki si delijo isto uro. Ura je metronom načrta: vse koristno se zgodi kot kombinacijska logika med registri.

    Kombinacijski izhod proti registriranemu izhodu

    Vezje: assign y = d + 4'd1; nato always_ff @(posedge clk) q <= y; Spremenite d in opazujte, kako se y odzove takoj. q se premakne šele, ko pritisnete gumb za takt.

    d (vhod)
    0000
    0
    y (žica)
    0001
    1
    q (register)
    0000
    0

    Pritisnite „Rob takta“, da naložite y v q.

    register.svsekvenčna
    module register8 (
      input  logic       clk, rst,
      input  logic [7:0] d,
      output logic [7:0] q
    );
      always_ff @(posedge clk) begin
        if (rst) q <= '0;       // sinhrona ponastavitev
        else     q <= d;
      end
    endmodule

    Če q speljete nazaj v logiko, ki ustvarja d, dobite števec, in to je natanko potrditveno polje v gradniku zgoraj:

    counter_basic.svsekvenčna
    logic [3:0] count;
    
    always_ff @(posedge clk) begin
      if (rst)     count <= 4'd0;
      else if (en) count <= count + 4'd1;   // iz 15 se sam prevrti v 0
    end

    Zakaj <= in ne =

    Znotraj always_ff uporabljajte neblokirajočo prireditev <=. Najprej se preberejo vse desne strani, nato se vsi registri posodobijo skupaj, kot pravi flip-flopi, ki vsi vzorčijo ob istem robu.

    swap.svsekvenčna
    always_ff @(posedge clk) begin
      a <= b;
      b <= a;        // pravi zamenjavi: oba bereta STARI vrednosti
    end

    Preprosto pravilo. always_ff uporablja <=. always_comb in assign uporabljata =. Obeh slogov nikoli ne mešajte v istem bloku.

    Dva znaka, en pomen. Neblokirajoča prireditev se zapiše z dvema znakoma: znakom manjše-od, ki mu sledi enačaj, <=. To ni en sam simbol ≤. V izrazu, kot je if (a <= b), ista dva znaka pomenita „manjše ali enako“, razlikuje pa ju mesto: na začetku stavka predstavlja dodelitev vrednosti: q <= d;

    Ponastavitev, ki počaka na takt, je sinhrona. Asinhrona ponastavitev deluje takoj in se zapiše always_ff @(posedge clk or posedge rst). Izberite en slog za cel projekt in ga dosledno uporabljajte; sinhroni je dobra privzeta izbira na večini FPGA.

    7. Razmišljanje na ravni RTL: registri in logika naslednjega stanja

    RTL pomeni register transfer level (raven prenosa med registri). Načrt vezja na tej ravni sestavlja množica registrov in kombinacijska logika, ki izračuna, kaj naj vsak register hrani po naslednjem robu takta. Ko načrtujete, si za vsako stanje zastavite dve vprašanji:

    • Kateri so moji registri?
    • Kakšna je enačba naslednje vrednosti za vsakega od njih?

    Če obe polovici zapišete v ločenih blokih, ostane razmišljanje pregledno. Spodaj je števec, ki lahko zadrži, šteje ali naloži vrednost:

    load_counter.svkombinacijska + sekvenčna
    logic [7:0] count, count_next;
    
    // Kombinacijsko: kaj naj postane count?
    always_comb begin
      count_next = count;                    // privzeto: zadrži
      if (load)    count_next = load_value;
      else if (en) count_next = count + 8'd1;
    end
    
    // Sekvenčno: prepiši vrednost ob robu takta
    always_ff @(posedge clk) begin
      if (rst) count <= '0;
      else     count <= count_next;
    end

    Opazite, da privzeta vrednost count_next = count hkrati deluje kot zaščita pred zapahom iz 5. dela in kot obnašanje „ne naredi nič“.

    8. Moduli, parametri in hierarhija

    Modul je škatla s poimenovanimi priključki (porti). Večja vezja gradite tako, da postavljate instance modulov in povezujete njihove priključke. Parametri naredijo modul nastavljiv: isti modul predstavlja 4-bitni ali 32-bitni števec.

    counter.svsekvenčna
    module counter #(
      parameter int WIDTH = 8
    ) (
      input  logic             clk, rst, en,
      output logic [WIDTH-1:0] count
    );
      always_ff @(posedge clk) begin
        if (rst)     count <= '0;
        else if (en) count <= count + 1'b1;
      end
    endmodule
    top.svhierarhija
    module top (
      input  logic       clk, rst,
      output logic [3:0] slow
    );
      logic [7:0] fast;
      logic       tick;
    
      counter #(.WIDTH(8)) u_fast (
        .clk(clk), .rst(rst), .en(1'b1), .count(fast)
      );
    
      assign tick = (fast == 8'hFF);     // res enkrat na 256 taktov
    
      counter #(.WIDTH(4)) u_slow (
        .clk(clk), .rst(rst), .en(tick), .count(slow)
      );
    endmodule

    Upočasnite z omogočitvenim signalom, ne z drugim taktom. Drugi števec zgoraj teče na istem taktu, a napreduje le, ko je tick visok. To je standardni način za počasnejšo hitrost v FPGA in se izogne časovnim težavam generiranih taktov.

    Priključke vedno povezujte po imenu (.clk(clk)), nikoli po položaju. Tako so napake vidne.

    9. Končni avtomati

    Končni avtomat (FSM) je digitalno vezje, katerega obnašanje je odvisno od tega, v katerem iz majhne množice stanj je. Tu se naravno združi vse dosedanje: register stanja, logika naslednjega stanja in izhodi. Uporabite enum, da imajo stanja imena.

    Primer: krmilnik časovnika. Pritisk na start požene časovnik za 100 taktnih ciklov, nato javlja done, dokler start ne spustite.

    timer_fsm.svkombinacijska + sekvenčna
    typedef enum logic [1:0] {IDLE, RUN, DONE} state_t;
    state_t     state, state_next;
    logic [7:0] timer;
    
    // 1. Register stanja
    always_ff @(posedge clk) begin
      if (rst) state <= IDLE;
      else     state <= state_next;
    end
    
    // 2. Logika naslednjega stanja
    always_comb begin
      state_next = state;
      case (state)
        IDLE:    if (start)             state_next = RUN;
        RUN:     if (timer == 8'd99)    state_next = DONE;
        DONE:    if (!start)            state_next = IDLE;
        default:                        state_next = IDLE;
      endcase
    end
    
    // 3. Podatkovna pot: časovnik šteje samo med delovanjem
    always_ff @(posedge clk) begin
      if (state == RUN) timer <= timer + 8'd1;
      else              timer <= '0;
    end
    
    // 4. Izhodi
    assign busy = (state == RUN);
    assign done = (state == DONE);

    Stanja najprej narišite kot kroge in prehode kot puščice na papir. Koda je potem neposreden prepis risbe.

    10. Časovni potek: zakaj ura ne more biti neskončno hitra

    Signali potrebujejo čas, da potujejo skozi logiko in žice. Med dvema registroma morajo podatki potovati od izhoda prvega registra skozi kombinacijsko logiko in priti na vhod drugega registra malo pred naslednjim robom takta.

    register A kombinacijska logika register B clk→q setup oba registra si delita isti takt

    Perioda takta mora biti daljša od vsote zakasnitev vzdolž najpočasnejše takšne poti, imenovane kritična pot:

    Tclk ≥ tclk-to-q + tlogic + trouting + tsetup

    Če je logika na sredini prepočasna, jo lahko razrežete na dva dela z dodatnim registrom na sredini. To je cevovod (pipelining): vsaka stopnja opravi manj dela na takt, zato lahko takt teče hitreje. Cena je en cikel dodatne latence.

    pipeline.svsekvenčna
    // Ena dolga pot: množenje, nato seštevanje, v enem taktnem ciklu
    always_ff @(posedge clk) y <= a * b + c;
    
    // S cevovodom: dve krajši poti, rezultat je en cikel kasneje
    logic [15:0] prod, c_d;
    always_ff @(posedge clk) begin
      prod <= a * b;          // stopnja 1
      c_d  <= c;              // zakasni c, da ostane poravnan s prod
      y    <= prod + c_d;     // stopnja 2
    end

    Zakasnitev ni treba računati ročno. Po razmestitvi in povezovanju (Fitter) o časovnih razmerah poroča Timing Analyzer, vi pa mu cilj podate z omejitvijo takta v datoteki SDC (12. del). Poročilo, ki pravi, da časovne omejitve niso izpolnjene, pomeni, da je vaša kritična pot predolga za ta takt.

    11. Testna okolja in koda samo za simulacijo

    Testno okolje (testbench) je modul brez priključkov, ki obdaja vaš načrt, generira takt, privede vhode in izpiše ali preveri rezultate. Nikoli se ne sintetizira, zato lahko uporablja konstrukte brez strojnega pomena: časovne zakasnitve, bloke initial, $display.

    tb_counter.svsamo simulacija
    module tb_counter;
      logic       clk = 0, rst = 1, en = 1;
      logic [7:0] count;
    
      counter #(.WIDTH(8)) dut (.clk(clk), .rst(rst), .en(en), .count(count));
    
      always #5 clk = ~clk;              // perioda 10 ns: preklop vsakih 5 ns
    
      initial begin
        #22 rst = 0;                     // spusti ponastavitev med dvema robovoma
        repeat (20) @(posedge clk);
        #1;                              // počakaj, da se neblokirajoča posodobitev umiri
        $display("count = %0d", count);  // izpiše 20
        assert (count == 8'd20) else $error("counter is wrong");
        $finish;
      end
    endmodule

    Odprite prikazovalnik časovnih potekov (waveform viewer) in poglejte clk, rst in count skupaj. Časovni poteki predstavijo sočasnost in čas, česar samo besedilo ne more pokazati.

    V Quartus Prime testno okolje shranite kot ločeno datoteko in ga ne dodajte med načrtovalske datoteke projekta, da ga sinteza ne vidi. Namesto tega ga v Assignments, Settings, EDA Tool Settings, Simulation (NativeLink settings) določite kot testno okolje (Compile test bench) in zaženite Tools, Run Simulation Tool, RTL Simulation. Simulacijo opravi ModelSim oziroma Questa Intel FPGA Edition.

    KonstruktV načrtuV testnem okolju
    zakasnitev #10ni za sintezov redu
    $display, $finishprezrto ali napakav redu
    initial s stimulacijoni za sintezov redu
    always_ff, always_comb, assigndav redu

    12. Od modela vezja do izvedbe v FPGA s Quartus Prime

    FPGA je čip, ki vsebuje matriko nastavljivih blokov s katerimi naredimo poljubna digitalna vezja. V gradivu obravnavamo razvojno ploščo Terasic DE0-Nano z FPGA vezjem Cyclone IV E (EP4CE22F17C6N), ki ima 22.320 logičnih elementov, 594 kbit vgrajenega pomnilnika in 66 vgrajenih množilnikov 18 × 18. Vaš opis se preslika nanje:

    Vir v Cyclone IVKaj izvajaKaj ste napisali
    LUT (v logičnem elementu)Katero koli majhno logično funkcijo s štirimi vhodiOperatorje, multiplekserje, primerjave
    Flip-flop (v logičnem elementu)En bit stanjaRegistre always_ff
    Pomnilniški blok M9K9 kbit pomnilnika na blokTabelo, ki se bere in piše v sekvečnem bloku
    Vgrajeni množilnikHitro množenje 18 × 18 (ali dvakrat 9 × 9)a * b

    Tabele LUT nastavimo tako, da izvajajo katero koli logično funkcijo z nekaj vhodi (v Cyclone IV imajo LUT štiri vhode). Zato lahko opišete vezje z enačbami in vektorji, logična vrata pa poišče orodje.

    Potek dela v Quartus Prime

    KorakKje v QuartusuKaj preveriti
    Ustvari projektFile, New Project Wizard. Izberite družino Cyclone IV E in napravo EP4CE22F17C6. Datoteke .sv dodajte kot načrtovalske vire in določite najvišji modul (Top-level entity). Testnih okolij projektu ne dodajajte.Datoteke s končnico .sv se berejo kot SystemVerilog. Za datoteko .v nastavite v Assignments, Settings, Compiler Settings, Verilog HDL Input različico SystemVerilog_2005.
    SimulirajTools, Run Simulation Tool, RTL Simulation (ModelSim oziroma Questa Intel FPGA Edition). Testno okolje določite v Assignments, Settings, EDA Tool Settings, Simulation.Časovni poteki ustrezajo pričakovanjem. Kot najvišji modul simulacije je izbrano testno okolje.
    ElaborirajProcessing, Start, Start Analysis & Elaboration. Nato Tools, Netlist Viewers, RTL Viewer.Vaša koda, narisana kot multiplekserji, seštevalniki in flip-flopi, pred kakršno koli optimizacijo. Najboljše mesto, da postane „koda je strojna oprema“ otipljivo.
    SintetizirajProcessing, Start, Start Analysis & Synthesis. Nato Tools, Netlist Viewers, Technology Map Viewer.Preberite opozorila v oknu Messages, zlasti o izpeljanih zapahih in večkratnih gonilnikih. V Flow Summary preverite število logičnih elementov, registrov in pomnilniških bitov.
    ImplementirajProcessing, Start Compilation (zaporedoma Analysis & Synthesis, Fitter, Assembler in Timing Analyzer). Nato Tools, Timing Analyzer. Datoteka .sdc mora biti dodana projektu.V Timing Analyzerju poglejte Report Fmax Summary, Report Setup Summary in Report Hold Summary. Rezerva (slack) je nič ali pozitivna, kar pomeni, da so časovne omejitve izpolnjene, in to v vseh časovnih modelih (Slow in Fast).
    Bitni tokAssembler ob prevajanju samodejno ustvari datoteko .sof (SRAM Object File) v mapi output_files.Datoteka .sof obstaja. Fitter ne opozarja, da imajo priključki nedodeljeno nožico.
    ProgramirajTools, Programmer. V Hardware Setup izberite USB-Blaster (na plošči je vgrajen), način JTAG, nato Add File, izberite .sof in kliknite Start.Napredek pokaže 100 % (Successful) in načrt zaživi na plošči. Programiranje prek JTAG je v SRAM-u in ob izklopu napajanja izgine; za trajen zapis v serijski pomnilnik EPCS ustvarite datoteko .jic.

    Sintetizator v Quartus Prime podpira veliko podmnožico kontstruktov jezika SystemVerilog. Ko zavrne kak konstrukt, ga poiščite v priročniku Quartus Prime Handbook, v poglavju Recommended HDL Coding Styles. Isti priročnik dokumentira sintezne atribute, kot sta (* ramstyle = "M9K" *) in (* multstyle = "dsp" *), ki določata, ali tabela postane pomnilnik M9K in ali množilnik uporabi vgrajeni množilnik.

    Prvi projekt: utripajoča LED

    Takt 50 MHz na plošči DE0-Nano je veliko prehiter, da bi ga videli. Števec ga deli navzdol: najvišji bit 26-bitnega števca se preklopi približno vsakih 0,67 sekunde.

    blinky.svsekvenčna
    `default_nettype none
    
    module blinky (
      input  wire  clk_50mhz,
      output logic led
    );
      logic [25:0] ticks = '0;          // registri v FPGA lahko začnejo z vrednostjo
    
      always_ff @(posedge clk_50mhz)
        ticks <= ticks + 1'b1;
    
      assign led = ticks[25];           // 50e6 / 2^26 je približno 0,75 utripa na sekundo
    endmodule

    Orodje mora vedeti tudi, katero nožico FPGA uporablja vsak priključek in kako hiter je takt. V Quartusu sta to dve ločeni stvari. Lokacije nožic in V/I standard se shranijo v projektno datoteko .qsf (običajno jih vnesete v Pin Plannerju, Assignments, Pin Planner), omejitev takta pa v datoteko .sdc, ki jo dodate projektu.

    blinky.qsfnožice (Quartus)
    # Naprava na plošči DE0-Nano
    set_global_assignment -name FAMILY "Cyclone IV E"
    set_global_assignment -name DEVICE EP4CE22F17C6
    
    # clk_50mhz je CLOCK_50, led je LED[0]
    set_location_assignment PIN_R8 -to clk_50mhz
    set_location_assignment PIN_A15 -to led
    set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to clk_50mhz
    set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to led
    blinky.sdcčasovna omejitev (Quartus)
    # 50 MHz pomeni periodo 20 ns
    create_clock -name clk_50mhz -period 20.000 [get_ports clk_50mhz]
    derive_clock_uncertainty

    Vse nožice plošče so navedene v uporabniškem priročniku DE0-Nano, ki ga objavi Terasic. Tam prepišite le tiste, ki jih potrebujete, in priključke preimenujte tako, da se ujemajo s priključki vašega najvišjega modula.

    Plošča DE0-Nano na kratko. Oscilator 50 MHz je na nožici R8. LED-diode (8 zelenih) se prižgejo pri visoki ravni. Tipki (2, z odpravo odskakovanja) sta aktivni pri nizki ravni, zato ju za ponastavitev uporabite kot rst_n ali ju invertirajte.

    13. Napake, ki jih lahko pričakujete

    Skoraj vsak začetnik naleti nanje. Če poznate simptom, prihranite ure.

    SimptomVzrokPopravek
    Opozorilo: izpeljan zapah (latch inferred)Izhod bloka always_comb ni dodeljen na vseh potehNajprej dodelite privzeto vrednost; dodajte else ali default
    Pomikalni register ali zamenjava daje napačne vrednostiV always_ff je uporabljen blokirajoči =V sekvenčnih blokih uporabite <=
    Napaka „multiple drivers“ (več gonilnikov)En signal je dodeljen v dveh blokih ali v assign in v blokuVsakemu signalu dajte natanko en gonilnik
    Tipkarska napaka v imenu signala nima vidnega učinkaOrodje je tiho ustvarilo novo enobitno žicoNa vrh vsake datoteke dodajte `default_nettype none
    Seštevku manjka najvišji bitVektor rezultata je preozekNaredite ga za en bit širšega od operandov
    V simulaciji deluje, na plošči neZakasnitve ali konstrukti samo za testno okolje v načrtu; manjkajoče omejitveDržite se sintetizirljive podmnožice; preverite nožice in omejitev takta
    Časovne omejitve niso izpolnjeneKombinacijska pot je daljša od periode taktaRazdelite jo s cevovodom ali znižajte frekvenco takta
    Prevajanje uspe, a plošča ne dela, kot bi moralaPort nima dodeljene nožice; Fitter je izbral poljubno nožico in izdal samo opozoriloV Pin Plannerju (ali v datoteki .qsf) vsakemu priključku dodelite lokacijo in V/I standard
    Quartus javi sintaktično napako pri logic ali always_ffDatoteka se obravnava kot navaden VerilogPreimenujte jo v .sv ali v Verilog HDL Input nastavite SystemVerilog_2005

    14. Povzetek na eni strani

    Strojna idejaKaj napišeteZapomnite si
    Žica ali vodilologic [N-1:0] x;Vedno navedite širino
    Kombinacijska logikaassign, always_combUporabljajte =; pokrijte vse poti
    Multiplekser?:, if, caseObe veji obstajata v strojni opremi
    Registeralways_ff @(posedge clk)Uporabljajte <=
    Ponastavitevif (rst) q <= '0;En slog za cel projekt
    Ponovno uporaben blokmodule s parameterPriključke povezujte po imenu
    Končni avtomatenum + register stanja + blok naslednjega stanjaNajprej narišite diagram
    Počasnejša hitrostOmogočitev takta (tick)Izogibajte se generiranim taktom
    Višja frekvenca taktaCevovodni registriStane latenco, ne prepustnosti
    Preverjanje načrtaTestno okolje + časovni potekiZakasnitve in $display so samo za simulacijo