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:
- Osnove: kombinacijska logika v poglavjih 2 do 5.
- Osnove: sekvenčna logika v poglavjih 6 do 10 in 12.
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.
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
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.
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.
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.
| Operator | Vrata | Pomen | Primer |
|---|---|---|---|
& | IN (AND) | 1 samo, če sta oba vhoda 1 | a & b |
| | ALI (OR) | 1, če je vsaj en vhod 1 | a | b |
^ | XOR | 1, če se vhoda razlikujeta | a ^ b |
~ | NE (NOT) | obrne bit | ~a |
? : | MUX | izbere enega od dveh vhodov | sel ? a : b |
Če operator postavite pred en sam vektor, združi vse bite v enega. Ti redukcijski operatorji so zelo uporabni:
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:
// 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.
always_comb begin
if (en) y = a; // kaj je y, ko je en 0? Obdrži staro vrednost
end
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.
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:
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.
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:
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.
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
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.
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.
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.
// 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.
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.
| Konstrukt | V načrtu | V testnem okolju |
|---|---|---|
zakasnitev #10 | ni za sintezo | v redu |
$display, $finish | prezrto ali napaka | v redu |
initial s stimulacijo | ni za sintezo | v redu |
always_ff, always_comb, assign | da | v 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 IV | Kaj izvaja | Kaj ste napisali |
|---|---|---|
| LUT (v logičnem elementu) | Katero koli majhno logično funkcijo s štirimi vhodi | Operatorje, multiplekserje, primerjave |
| Flip-flop (v logičnem elementu) | En bit stanja | Registre always_ff |
| Pomnilniški blok M9K | 9 kbit pomnilnika na blok | Tabelo, ki se bere in piše v sekvečnem bloku |
| Vgrajeni množilnik | Hitro 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
| Korak | Kje v Quartusu | Kaj preveriti |
|---|---|---|
| Ustvari projekt | File, 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. |
| Simuliraj | Tools, 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. |
| Elaboriraj | Processing, 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. |
| Sintetiziraj | Processing, 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. |
| Implementiraj | Processing, 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 tok | Assembler 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. |
| Programiraj | Tools, 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.
`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.
# 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
# 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.
| Simptom | Vzrok | Popravek |
|---|---|---|
| Opozorilo: izpeljan zapah (latch inferred) | Izhod bloka always_comb ni dodeljen na vseh poteh | Najprej dodelite privzeto vrednost; dodajte else ali default |
| Pomikalni register ali zamenjava daje napačne vrednosti | V 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 bloku | Vsakemu signalu dajte natanko en gonilnik |
| Tipkarska napaka v imenu signala nima vidnega učinka | Orodje je tiho ustvarilo novo enobitno žico | Na vrh vsake datoteke dodajte `default_nettype none |
| Seštevku manjka najvišji bit | Vektor rezultata je preozek | Naredite ga za en bit širšega od operandov |
| V simulaciji deluje, na plošči ne | Zakasnitve ali konstrukti samo za testno okolje v načrtu; manjkajoče omejitve | Držite se sintetizirljive podmnožice; preverite nožice in omejitev takta |
| Časovne omejitve niso izpolnjene | Kombinacijska pot je daljša od periode takta | Razdelite jo s cevovodom ali znižajte frekvenco takta |
| Prevajanje uspe, a plošča ne dela, kot bi morala | Port nima dodeljene nožice; Fitter je izbral poljubno nožico in izdal samo opozorilo | V Pin Plannerju (ali v datoteki .qsf) vsakemu priključku dodelite lokacijo in V/I standard |
Quartus javi sintaktično napako pri logic ali always_ff | Datoteka se obravnava kot navaden Verilog | Preimenujte jo v .sv ali v Verilog HDL Input nastavite SystemVerilog_2005 |
14. Povzetek na eni strani
| Strojna ideja | Kaj napišete | Zapomnite si |
|---|---|---|
| Žica ali vodilo | logic [N-1:0] x; | Vedno navedite širino |
| Kombinacijska logika | assign, always_comb | Uporabljajte =; pokrijte vse poti |
| Multiplekser | ?:, if, case | Obe veji obstajata v strojni opremi |
| Register | always_ff @(posedge clk) | Uporabljajte <= |
| Ponastavitev | if (rst) q <= '0; | En slog za cel projekt |
| Ponovno uporaben blok | module s parameter | Priključke povezujte po imenu |
| Končni avtomat | enum + register stanja + blok naslednjega stanja | Najprej narišite diagram |
| Počasnejša hitrost | Omogočitev takta (tick) | Izogibajte se generiranim taktom |
| Višja frekvenca takta | Cevovodni registri | Stane latenco, ne prepustnosti |
| Preverjanje načrta | Testno okolje + časovni poteki | Zakasnitve in $display so samo za simulacijo |