Verilog assign-statements begrijpen: Continue signaaltoewijzing uitgelegd
Signalen van type wire of vergelijkbare wire-achtige datatypes vereisen continue toewijzing van een waarde. Stel je een elektrische draad voor op een breadboard: zolang de +5V batterij aan één uiteinde aangesloten is, krijgt het component aan de andere kant de benodigde spanning.
In Verilog wordt dit gerealiseerd door het assign statement, waarbij elke wire of soortgelijke wire-achtige datatypes continu met een waarde gedreven worden. De waarde kan een constante zijn of een expressie van een groep signalen.
Assign-syntaxis
De toewijzingssyntaxis begint met het sleutelwoord assign gevolgd de signaalnaam, die een enkel signaal of een concatenatie van verschillende signaalnets kan zijn. De drive strength en vertraging zijn optioneel en worden meestal gebruikt voor dataflow-modellering dan voor synthetise naar echte hardware. De expressie of signaal aan de rechterkant wordt geëvalueerd en toegewezen aan het net of de expressie van nets aan de linkerkant.
assign = [drive_strength] [delay] Vertragingswaarden zijn nuttig voor het specificeren van gate-delays en het modelleren van timing-gedrag in echte hardware, omdat de waarde dicteert wanneer het net de geëvalueerde waarde krijgt.
Regels
Er zijn regels voor het gebruik van een assign statement:
- LHS moet altijd een scalar of vector net of een concatenatie van scalar/vector nets zijn, nooit een scalar of vector register.
- RHS kan scalar of vector registers en functie-aanroepen bevatten.
- Wanneer elk operand op de RHS van waarde verandert, wordt LHS bijgewerkt met de nieuwe waarde.
assignstatements heten ook continue toewijzingen en zijn altijd actief.
Voorbeeld #1
In het volgende voorbeeld wordt een net out continu gedreven door een expressie van signalen i1 en i2 met logische AND &.
Als de draden in poorten omgezet worden en gesynthetiseerd, krijgen we een RTL-schema zoals hieronder na synthetise.
Continue toewijzingsstatements kunnen combinatorische gates in Verilog voorstellen.
Voorbeeld #2
De onderstaande module neemt twee invoeren en gebruikt een assign statement om de uitvoer z te drijven met part-select en meerdere bit-concatenaties. Behandel elk geval als de enige code in de module, anders zullen meerdere assign statements op hetzelfde signaal de uitvoer X maken.
module xyz (input [3:0] x, input y, output [4:0] z);
wire [1:0] a; wire b;
// Stel x='hC en y='h1, laten we de waarde van z zien
// Case #1: 4-bits x en 1 bit y geconcateneerd tot 5-bit net, toegewezen aan 5-bit z -> z='b11001 of 'h19
assign z = {x, y};
// Case #2: 4-bits x en 1 bit y geconcateneerd, toegewezen aan geselecteerde 3-bits van z. Overige 2 bits ongedreven -> hoog-imp. z='bZ001Z
assign z[3:1] = {x, y};
// Case #3: Zelfde statement, maar bit4 van z gedreven met constante 1. Nu z = 'b1001Z (alleen bit0 ongedreven)
assign z[3:1] = {x, y}; assign z[4] = 1;
// Case #4: Bit3 gedreven met 0, twee drivers voor bit3 met dezelfde waarde 0 -> geen conflict, z='bZ001Z
assign z[3:1] = {x, y}; assign z[3] = 0;
// Case #5: Bit3 gedreven met 1, twee drivers met verschillende waarden (eerste 0, tweede 1) -> onbekend wie wint, z='bZX01Z
assign z[3:1] = {x, y}; assign z[3] = 1;
// Case #6: Gedeeltelijke selectie operand RHS: alleen 2-bits uit x gekozen -> z = 'b00001
assign z = {x[1:0], y};
// Case #7: Expliciet alleen 3-bits van z toewijzen, rest onverbonden -> z = 'bZZ001
assign z[2:0] = {x[1:0], y};
// Case #8: Dezelfde variabele meerdere keren gebruiken: 3{y} = {y,y,y} -> z = 'b00111
assign z = {3{y}};
// Case #9: LHS geconcateneerd: a is 2-bit vector, b scalar. RHS geëvalueerd 11001, LHS 3-bit breed -> eerste 3 bits van LSB van RHS toegewezen aan LHS. a='b00, b='b1
assign {a, b} = {x, y};
// Case #10: Volgorde op LHS omgekeerd, RHS gelijk -> a='b01, b='b0
assign {a, b} = {x, y};
endmoduleReg-variabelen toewijzen
Het is illegaal reg-type variabelen te drijven of toe te wijzen met een assign statement. Een reg variabele kan data opslaan en hoeft niet continu gedreven te worden. reg signalen kunnen alleen in procedurale blokken als initial en always gedreven worden.
Impliciete continue toewijzing
Wanneer een assign statement gebruikt wordt om een net een waarde te geven, heet dat expliciete toewijzing. Verilog stelt ook toewijzing toe bij declaratie van het net, impliciete toewijzing.
wire [1:0] a; assign a = x & y; // Expliciete toewijzing
wire [1:0] a = x & y; // Impliciete toewijzingCombinatorische logica-ontwerp
Bekijk het volgende digitale circuit van combinatorische gates en de bijbehorende Verilog-code.
Combinatorische logica vereist continue aangedreven invoeren om de uitvoer te behouden, in tegenstelling tot sequentiële elementen zoals flipflops waar de waarde op de klokflank vastgelegd wordt. Een assign statement past perfect omdat de uitvoer o wordt bijgewerd wanneer een van de invoeren aan de rechterkant verandert.
// Module met vier inputs, boolean operatie, output o via assign
module combo ( input a, b, c, d, output o);
assign o = ~((a & b) | c ^ d);
endmoduleHardwareschema
Na design elaboratie en synthetise zien we een combinatorisch circuit dat zich gedraagt zoals gemodelleerd door het assign statement.
Zie dat signaal o 1 wordt wanneer de combinatorische expressie aan de RHS waar wordt. o wordt 0 wanneer RHS false is. Uitvoer o is X van 0ns tot 10ns omdat invoeren X zijn in dezelfde tijd.
Klik hier voor een slideshow met simulatiefbeeld!
Verilog
- De C# Switch Statement: Syntaxis, Voorbeelden & Best Practices
- C# Break Statement: Hoe en Wanneer Te Gebruiken
- C# Continue Statement: Effectief Lusiteraties Overslaan
- Verilog concatenatie beheersen: Een praktische gids
- Verilog-toewijzingen begrijpen: types, syntax en best practices
- Verilog Blocking vs. Non-Blocking: belangrijkste verschillen uitgelegd
- Verilog-functies beheersen voor efficiënt RTL-ontwerp
- Verilog Tasks begrijpen: Functions vs Tasks, Syntax en Gebruik
- Verilog Clock Generator: Ontwerp & Implementatie Gids
- Verilog Math Functions beheersen voor efficiënt Hardware-ontwerp
- Verilog $timeformat beheersen: Precisie en Weergave-controle