SystemVerilog nace para solucionar las limitaciones de Verilog cuando los diseños digitales empiezan a crecer en tamaño (SoC, CPUs, GPUs) y complejidad (pipelines, múltiples dominios de reloj) además de difíciles de verificar con Verilog clásico.
Por eso, a principios de los 2000 Accellera combina Verilog + Superlog (Synopsys) y en 2005 se estandariza como IEEE 1800. A partir de ahí SystemVerilog sustituye a Verilog como estándar moderno. Actualmente Verilog 2001 prácticamente no evoluciona; SystemVerilog es el estándar vivo.
SystemVerilog no reemplaza Verilog -todo Verilog 2001 es compatible con SystemVerilog- si no que lo extiende añadiendo construcciones de diseño y nuevas herramientas de verificación con características de lenguaje de programación moderno.
Mejor lenguaje de diseño añadiendo nuevos tipos de variables, por ejemplo las tipo logic que evita errores de múltiples drivers (wire vs reg) permitiendo un código más limpio y seguro. Añade también nuevo bloques always_comb, always_ff, always_latch separando lógica secuencial y combinacional y permitiendo detectar errores de diseño automáticamente.
Parametrización y reutilización; parámetros tipados e interfaces.
Verificación potente (gran salto); aquí está la mayor razón de su existencia.
Código más legible y fácil de mantener.
Como circuito Hola Mundo describiremos un multiplexor 2x1 y otro multiplexor 4x1 instanciado el primero.
Nótese las variables tipo logic frente al tradicional wire de Verilog
module mux_2x1(
input logic in0, in1, sel,
output logic out
);
logic w0, w1;
assign out = w0 | w1;
assign w0 = in0 & ~sel;
assign w1 = in1 & sel;
endmodule
La forma de instanciar no cambia respecto a Verilog.
module mux_4x1(
logic in0, in1, in2, in3, // INPUTS
logic sel0, sel1, // SELECTION
logic out); // OUTPUT
logic w0, w1;
mux_2x1 M0 (.in0(in0), .in1(in1), .sel(sel0), .out(w0));
mux_2x1 M1 (.in0(in2), .in1(in3), .sel(sel0), .out(w1));
mux_2x1 M2 (.in0(w0), .in1(w1), .sel(sel1), .out(out));
endmodule
Este nuevo tipo de bloques always son una de las novedades de SystemVerilog.
Las ventajas son numerosas, por ejemplo, no hay que declarar la lista de sensibilidades (lo hace el simulador automáticamente), detecta latches, mejora la legibilidad del código, detecta errores, etc.
// always_comb + procedural assignment
module mux_2x1 (
input logic in0, // entrada 0
input logic in1, // entrada 1
input logic sel, // selector
output logic out // salida
);
logic w0, w1;
always_comb begin
out = w0 | w1;
w0 = in0 & ~sel;
w1 = in1 & sel;
end
endmodule
// always_comb + declaración if-else
module mux_2x1 (
input logic in0, // entrada 0
input logic in1, // entrada 1
input logic sel, // selector
output logic out // salida
);
always_comb begin
if (sel)
out = in1;
else
out = in0;
end
endmodule
// always_comb + declaración case
module mux_2x1 (
input logic a, // entrada 0
input logic b, // entrada 1
input logic sel, // selector
output logic y // salida
);
always_comb begin
case (sel)
1'b0: y = a;
1'b1: y = b;
default: y = a; // defensivo
endcase
end
endmodule