Anatomía de un literal con tamaño
Un literal de Verilog tiene hasta tres partes:
8'b1010_1100
│ │ │
│ │ └─ digits in the chosen base
│ └─── base specifier: b (binary), h (hex), d (decimal), o (octal)
└────── width in bits (decimal)
Leyendo de izquierda a derecha: "un valor de 8 bits, escrito en binario, con los dígitos 10101100". Eso es 172 en decimal, 0xAC en hex, los mismos bits sea cual sea la forma en que los escribas. El ancho le dice al compilador exactamente cuántos bits reservar; la base le dice cómo interpretar los dígitos.
Los guiones bajos son separadores visuales. 32'b1010_1100_0011_0101 es lo mismo que 32'b1010110000110101. Úsalos.
Las cuatro bases
Hex (h) es el estándar para cualquier cosa más ancha que 4 bits. Binario (b) es el estándar cuando quieres leer patrones de bits directamente. Decimal (d) es para cuentas con significado humano. Octal (o) existe pero casi nunca lo verás.
Los dígitos hex no distinguen mayúsculas: 8'hAB y 8'hab son idénticos.
¿Qué pasa cuando el valor no encaja?
Si tus dígitos no llenan el ancho declarado, Verilog extiende con ceros por la izquierda:
8'b101 // equivalent to 8'b00000101 (= 5)
8'hF // equivalent to 8'h0F (= 15)
Si tus dígitos exceden el ancho declarado, Verilog trunca los bits altos con un aviso:
4'hFF // truncates to 4'hF, simulator warns
4'b10000 // truncates to 4'b0000
El aviso es tu amigo. No lo suprimas.
Con tamaño vs sin tamaño
Un literal sin ancho:
'd10 // unsized, takes default size (≥32 bits)
10 // also unsized - no base means decimal
Los literales sin tamaño por defecto van a 32 bits en la mayoría de las herramientas. Esta es la fuente de toda una clase de bugs:
reg [7:0] count;
if (count == -1) ... // -1 is unsized 32-bit; comparison gets weird
La solución es escribir 8'hFF en vez de -1, o 8'd255, o {8{1'b1}}. Pone siempre tamaño a los literales cuando se usen en expresiones específicas de ancho.
El único sitio donde los literales sin tamaño están bien son los contadores enteros en loops for de testbench, donde el entero es lo bastante ancho como para que no pase nada sorprendente.
Literales con signo
Por defecto, los literales con tamaño son sin signo:
8'd255 // unsigned 255
8'b1111_1111 // unsigned 255 - same bit pattern, just written differently
Si quieres que el literal se interprete como con signo, añade s después del apóstrofe:
8'sd10 // signed 10
8'sb1111_1111 // signed -1 (two's complement)
La bandera s importa para:
- Los operadores
<<<y>>>(desplazamientos aritméticos) - hacen sign-extend de los operandos con signo. - Operadores de comparación en expresiones mixtas con signo.
- Los casts
$signed/$unsigned.
Para la mayoría de la aritmética ordinaria sobre señales de bus, dejarás la s fuera.
Literales numéricos con X y Z
Un dígito literal puede ser x (desconocido) o z (alta impedancia):
8'bx es una forma corta para "los 8 bits desconocidos" - el valor se propaga para llenar el ancho declarado. Los dígitos x son comunes en los casos default de máquinas de estados y en inicialización. Cubrimos la semántica en X and Z Values.
Dónde aparecen los literales con tamaño en la práctica
Una vez que empiezas a escribir módulos reales, los literales con tamaño aparecen por todas partes:
// Bus widths
input wire [31:0] addr;
wire [31:0] zero = 32'h0;
wire [31:0] all_ones = 32'hFFFF_FFFF;
// State encodings
localparam IDLE = 3'd0;
localparam BUSY = 3'd1;
localparam DONE = 3'd2;
// Masks
wire is_msb_set = data & 32'h8000_0000;
// Comparisons
if (counter == 8'd255) ...
// Reset values
always @(posedge clk) begin
if (reset) data_out <= 8'd0;
else data_out <= data_in;
end
El patrón es consistente: escribe el ancho, escribe la base, escribe los dígitos. Cada literal que uses tiene la misma forma.
Una prueba
Ya tienes todo lo que necesitas para escribir cualquier constante que un módulo Verilog pudiera querer. La última pieza de la historia de tipos de datos es qué pasa cuando una señal no es un 0 o 1 limpio - los valores x y z.
Preguntas frecuentes
¿Qué significa 8'b1010 en Verilog?
Es un literal binario con tamaño: un valor de 8 bits cuya representación binaria es 00001010. El número antes del apóstrofe es el ancho en bits; la letra después del apóstrofe es la base (b binario, h hex, d decimal, o octal); los dígitos después son el valor. El literal se rellena con ceros a la izquierda si los dígitos no llenan el ancho.
¿Cuál es la diferencia entre números con tamaño y sin tamaño en Verilog?
Un literal con tamaño como 8'd10 es exactamente de 8 bits de ancho. Un literal sin tamaño como 'd10 o simplemente 10 por defecto va a 32 bits, que normalmente son demasiados. Mezclar literales sin tamaño en expresiones específicas de ancho causa bugs sutiles - prefiere literales con tamaño en todas partes fuera de código de test desechable.
¿Cómo se escribe un número hex en Verilog?
Usa el especificador de base 'h: 8'hFF es un valor de 8 bits de 255. Los dígitos hex no distinguen mayúsculas; 8'hff y 8'hFF son idénticos. Puedes agrupar dígitos con guiones bajos para legibilidad: 32'hDEAD_BEEF. Los guiones bajos los ignora el parser.
¿Cómo funcionan los guiones bajos en los números de Verilog?
Los guiones bajos son separadores visuales que el parser ignora. 32'b1010_1100_0011_0101 es exactamente el mismo valor que 32'b1010110000110101 pero mucho más fácil de leer. El primer carácter después del prefijo de base no puede ser un guion bajo, pero puedes ponerlos en cualquier otro sitio en la cadena de dígitos.
¿Cómo se escribe un número con signo en Verilog?
Añade s después del apóstrofe: 8'sd10 es un decimal con signo de 8 bits valor 10, y 8'sb1111_1111 es un -1 con signo. Por defecto, los literales con tamaño son sin signo; el modificador s lo invierte. La mayoría de la aritmética usa operandos sin signo - recurre a con signo solo cuando realmente necesites que los valores negativos se propaguen a través de <, >>> y operadores similares.