Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Industrial programming >> Verilog

Combinatorische logica implementeren met Verilog's always-blok

Het Verilog always blok kan gebruikt worden voor zowel sequentiële als combinatorische logica. Eerder werden ontwerpvoorbeelden getoond met een assign statement. Dezelfde ontwerpen worden nu verkend met een always blok.

Voorbeeld #1: Eenvoudige combinatorische logica

De onderstaande code implementeert een simpele digitale combinatorische logica met een uitvoersignaal z van type reg dat wordt bijgewerkt wanneer een van de signalen in de gevoeligheidslijst zijn waarde verandert. De gevoeligheidslijst wordt gedeclareerd binnen haakjes na de @ operator.

module combo ( input a, b, c, d, e, output reg z);
always @ ( a or b or c or d or e) begin
    z = ((a & b) | (c ^ d) & ~e);
end
endmodule

De module combo wordt geëlaboreerd in het volgende hardwareschema met synthetise-tools, waar de combinatorische logica geïmplementeerd is met digitale gates.

Gebruik blokkerende toewijzingen bij het modelleren van combinatorische logica met een always-blok

Testbench

De testbench simuleert het ontwerp om te verifiëren dat het zich gedraagt zoals verwacht. Alle invoercombinaties worden aangedreven met een for lus met een vertraging van 10 tijdseenheden.

module tb;
reg a, b, c, d, e; wire z; integer i;
combo u0 ( .a(a), .b(b), .c(c), .d(d), .e(e), .z(z));
initial begin
    a <= 0; b <= 0; c <= 0; d <= 0; e <= 0;
    $monitor ("a=%0b b=%0b c=%0b d=%0b e=%0b z=%0b", a, b, c, d, e, z);
    for (i = 0; i < 32; i = i + 1) begin {a, b, c, d, e} = i; #10; end
end
endmodule
Simulation Log
 ncsim> run
a=0 b=0 c=0 d=0 e=0 z=0
a=0 b=0 c=0 d=0 e=1 z=0
a=0 b=0 c=0 d=1 e=0 z=1
a=0 b=0 c=0 d=1 e=1 z=0
a=0 b=0 c=1 d=0 e=0 z=1
a=0 b=0 c=1 d=0 e=1 z=0
a=0 b=0 c=1 d=1 e=0 z=0
a=0 b=0 c=1 d=1 e=1 z=0
a=0 b=1 c=0 d=0 e=0 z=0
a=0 b=1 c=0 d=0 e=1 z=0
a=0 b=1 c=0 d=1 e=0 z=1
a=0 b=1 c=0 d=1 e=1 z=0
a=0 b=1 c=1 d=0 e=0 z=1
a=0 b=1 c=1 d=0 e=1 z=0
a=0 b=1 c=1 d=1 e=0 z=0
a=0 b=1 c=1 d=1 e=1 z=0
a=1 b=0 c=0 d=0 e=0 z=0
a=1 b=0 c=0 d=0 e=1 z=0
a=1 b=0 c=0 d=1 e=0 z=1
a=1 b=0 c=0 d=1 e=1 z=0
a=1 b=0 c=1 d=0 e=0 z=1
a=1 b=0 c=1 d=0 e=1 z=0
a=1 b=0 c=1 d=1 e=0 z=0
a=1 b=0 c=1 d=1 e=1 z=0
a=1 b=1 c=0 d=0 e=0 z=1
a=1 b=1 c=0 d=0 e=1 z=1
a=1 b=1 c=0 d=1 e=0 z=1
a=1 b=1 c=0 d=1 e=1 z=1
a=1 b=1 c=1 d=0 e=0 z=1
a=1 b=1 c=1 d=0 e=1 z=1
a=1 b=1 c=1 d=1 e=0 z=1
a=1 b=1 c=1 d=1 e=1 z=1
ncsim: *W,RNQUIE: Simulation is complete. 

Let op: zowel assign als always methodes worden geïmplementeerd in dezelfde hardwarelogica.

Voorbeeld #2: Half Adder

De half adder module accepteert twee scalaire invoeren a en b en gebruikt combinatorische logica om de uitgangen sum en carry-bit cout toe te wijzen. De som wordt gedreven door een XOR tussen a en b, de carry-bit door een AND.

module ha ( input a, b, output sum, cout);
always @ (a or b) begin
    {cout, sum} = a + b;
end
endmodule

Testbench

module tb;
reg a, b; wire sum, cout; integer i;
ha u0 ( .a(a), .b(b), .sum(sum), .cout(cout));
initial begin
    a <= 0; b <= 0;
    $monitor("a=%0b b=%0b sum=%0b cout=%0b", a, b, sum, cout);
    for (i = 0; i < 4; i = i + 1) begin {a, b} = i; #10; end
end
endmodule
Simulation Log
 ncsim> run
a=0 b=0 sum=0 cout=0
a=0 b=1 sum=1 cout=0
a=1 b=0 sum=1 cout=0
a=1 b=1 sum=0 cout=1
ncsim: *W,RNQUIE: Simulation is complete. 

Voorbeeld #3: Full Adder

Een always-blok kan het gedrag van een full adder beschrijven om de uitgangen sum en cout te drijven.

module fa ( input a, b, cin, output reg sum, cout);
always @ (a or b or cin) begin
    {cout, sum} = a + b + cin;
end
endmodule

Testbench

module tb;
reg a, b, cin; wire sum, cout; integer i;
fa u0 ( .a(a), .b(b), .cin(cin), .sum(sum), .cout(cout));
initial begin
    a <= 0; b <= 0;
    $monitor("a=%0b b=%0b cin=%0b cout=%0b sum=%0b", a, b, cin, cout, sum);
    for (i = 0; i < 8; i = i + 1) begin {a, b, cin} = i; #10; end
end
endmodule
Simulation Log
 ncsim> run
a=0 b=0 cin=0 cout=0 sum=0
a=0 b=0 cin=1 cout=0 sum=1
a=0 b=1 cin=0 cout=0 sum=1
a=0 b=1 cin=1 cout=1 sum=0
a=1 b=0 cin=0 cout=0 sum=1
a=1 b=0 cin=1 cout=1 sum=0
a=1 b=1 cin=0 cout=1 sum=0
a=1 b=1 cin=1 cout=1 sum=1
ncsim: *W,RNQUIE: Simulation is complete. 

Voorbeeld #4: 2x1 Multiplexer

De simpele 2x1 multiplexer gebruikt een ternaire operator om te beslissen welke invoer aan de uitvoer c toegewezen wordt. Als sel 1 is, wordt uitvoer gedreven door a, anders door b.

module mux_2x1 (input a, b, sel, output reg c);
always @ ( a or b or sel) begin
    c = sel ? a : b;
end
endmodule

Testbench

module tb;
reg a, b, sel; wire c; integer i;
mux_2x1 u0 ( .a(a), .b(b), .sel(sel), .c(c));
initial begin
    a <= 0; b <= 0; sel <= 0;
    $monitor("a=%0b b=%0b sel=%0b c=%0b", a, b, sel, c);
    for (i = 0; i < 3; i = i + 1) begin {a, b, sel} = i; #10; end
end
endmodule
Simulation Log
 ncsim> run
a=0 b=0 sel=0 c=0
a=0 b=0 sel=1 c=0
a=0 b=1 sel=0 c=1
ncsim: *W,RNQUIE: Simulation is complete. 

Voorbeeld #5: 1x4 Demultiplexer

De demultiplexer gebruikt een combinatie van sel en f om de verschillende uitvoersignalen te drijven. Elk uitvoersignaal is van type reg en gebruikt een always blok dat wordt bijgewerkt op basis van veranderingen in de signalen in de gevoeligheidslijst.

module demux_1x4 ( input f, input [1:0] sel, output reg a, b, c, d);
always @ ( f or sel) begin
    a = f & ~sel[1] & ~sel[0];
    b = f & sel[1] & ~sel[0];
    c = f & ~sel[1] & sel[0];
    d = f & sel[1] & sel[0];
end
endmodule

Testbench

module tb;
reg f; reg [1:0] sel; wire a, b, c, d; integer i;
demux_1x4 u0 ( .f(f), .sel(sel), .a(a), .b(b), .c(c), .d(d));
initial begin
    f <= 0; sel <= 0;
    $monitor("f=%0b sel=%0b a=%0b b=%0b c=%0b d=%0b", f, sel, a, b, c, d);
    for (i = 0; i < 8; i = i + 1) begin {f, sel} = i; #10; end
end
endmodule
Simulation Log
 ncsim> run
f=0 sel=0 a=0 b=0 c=0 d=0
f=0 sel=1 a=0 b=0 c=0 d=0
f=0 sel=10 a=0 b=0 c=0 d=0
f=0 sel=11 a=0 b=0 c=0 d=0
f=1 sel=0 a=1 b=0 c=0 d=0
f=1 sel=1 a=0 b=0 c=1 d=0
f=1 sel=10 a=0 b=1 c=0 d=0
f=1 sel=11 a=0 b=0 c=0 d=1
ncsim: *W,RNQUIE: Simulation is complete. 

Voorbeeld #6: 4x16 Decoder

module dec_3x8 ( input en, input [3:0] in, output reg [15:0] out);
always @ (en or in) begin
    out = en ? 1 << in: 0;
end
endmodule

Testbench

module tb;
reg en; reg [3:0] in; wire [15:0] out; integer i;
dec_3x8 u0 ( .en(en), .in(in), .out(out));
initial begin
    en <= 0; in <= 0;
    $monitor("en=%0b in=0x%0h out=0x%0h", en, in, out);
    for (i = 0; i < 32; i = i + 1) begin {en, in} = i; #10; end
end
endmodule
Simulation Log
 ncsim> run
en=0 in=0x0 out=0x0
en=0 in=0x1 out=0x0
...
en=1 in=0xf out=0x8000
ncsim: *W,RNQUIE: Simulation is complete. 

Verilog

  1. Accurate temperatuurbewaking in een serverkast met Raspberry Pi
  2. Circuit met een schakelaar: Praktische gids voor basis elektrische circuits
  3. Geïntegreerde Schakelingen: Fundamenten van Digitale Logische Poorten
  4. Programmeerbare Logische Controllers (PLC's): Moderne Digitale Besturing voor Industriële Systemen
  5. Booleaanse Algebra Begrijpen: Van Logica Fundamenten tot Digitale Schakelingen
  6. Vermenigvuldigen en delen met wetenschappelijke notatie beheersen
  7. Industry 4.0 Inzichten: Q&A met Verena Majuntke van Bosch.IO over IoT, Automatisering en de Toekomstfabriek
  8. Perfecte afwerkingen behalen met Okamoto's precisieslijpmachines
  9. VHDL & Verilog Meesteren: Schone Combinatoire en Sequentiele Logica Schrijven
  10. Praktisch Verilog Gate-Level Ontwerp: AND, OR, NOT Gates & 2x1 Multiplexer
  11. Verilog $timeformat beheersen: Precisie en Weergave-controle