Tengo un banco de pruebas Verilog que supervisa un bus de 64 bits y debo programar aleatoriamente un bit volteado (corrupción de paquetes) para que suceda cada paquete 1 en X. Me sorprendió descubrir que no inyectaba ningún tipo de corrupción, y al parecer esto se debe a los patrones en $ aleatorios?
Módulo Verilog, colocado en línea con el bus:
module test_cable #(
parameter EMPTY_BITS = 3,
parameter DATA_BITS = 64
) (
input wire clk,
input wire [DATA_BITS-1:0] eth_c2cable_data,
input wire eth_c2cable_valid,
input wire eth_c2cable_sop,
input wire [EMPTY_BITS-1:0] eth_c2cable_empty,
input wire eth_c2cable_eop,
input wire eth_c2cable_error,
output wire eth_c2cable_ready,
output wire [DATA_BITS-1:0] eth_cable2s_data,
output wire eth_cable2s_valid,
output wire eth_cable2s_sop,
output wire [EMPTY_BITS-1:0] eth_cable2s_empty,
output wire eth_cable2s_eop,
output wire eth_cable2s_error,
input wire eth_cable2s_ready
);
// Corruption control task
// 2'b00 clean
// 2'b01 corrupt 1 pkt in 2^6
// 2'b10 corrupt 1 pkt in 2^7
// 2'b11 corrupt 1 pkt in 2^8
reg [1:0] ready_control = 2'b00;
reg [31:0] random_next = 0;
task setCorruptControl;
input [1:0] bitf;
begin
ready_control <= bitf;
end
endtask
// ready bit control
reg [7:0] corrupt_at_cycle = 0;
wire [31:0] random_mask = (1'b1 << (6+ready_control))-1;
always @(posedge clk) begin
random_next <= $random;
if ((eth_c2cable_sop && eth_c2cable_valid) && ready_control > 0 && (random_next & random_mask) == 32'b0) begin
// corrupt this packet at some point. we don't know how big packet is, so somewhere in first 16 cycles
// if the packet stops before we corrupt, we'll hit the next one
corrupt_at_cycle <= random_next[24 +: 4];
$display("Scheduling corruption %t for +%d cycles %08x", $time, random_next[24 +: 4], random_next);
end else if (corrupt_at_cycle > 0 && eth_c2cable_valid) begin
corrupt_at_cycle <= corrupt_at_cycle - 1'b1;
end
if (eth_c2cable_corruption != 0) begin
$display("Corrupting wire packet with noise %016x", eth_c2cable_corruption);
end
end
// corrupt by flipping single bit in this cycle
wire [63:0] eth_c2cable_corruption = corrupt_at_cycle == 1 ? { 1'b1 << random_next[24 +: 5] } : 64'b0;
assign eth_cable2s_data = eth_c2cable_data ^ eth_c2cable_corruption;
assign eth_cable2s_valid = eth_c2cable_valid;
assign eth_cable2s_sop = eth_c2cable_sop;
assign eth_cable2s_eop = eth_c2cable_eop;
assign eth_cable2s_empty = eth_c2cable_empty;
assign eth_cable2s_error = eth_c2cable_error;
assign eth_c2cable_ready = eth_cable2s_ready;
endmodule
La corrupción de la salida de simulación siempre se programa en cero , por lo que nunca sucede:
...
Scheduling corruption 882531000 for + 0 cycles 40002780
Scheduling corruption 887190000 for + 0 cycles 002edf00
Scheduling corruption 894192000 for + 0 cycles 4049c380
Scheduling corruption 907395000 for + 0 cycles c0270a80
Scheduling corruption 948746000 for + 0 cycles 4010dd80
Scheduling corruption 959389000 for + 0 cycles 40155b80
Scheduling corruption 964957000 for + 0 cycles c0357a80
...
^ ^
Esto parece deberse a que los bits random_next [24 +: 4] y random_next [0 +: 6] coinciden con cero. Elegí arbitrariamente los bits de 24 con la esperanza de que no tuvieran correlación con los bits bajos. ¿Es esto una debilidad con el algoritmo de número pseudoaleatorio Verilog, o un problema con el simulador Icarus Verilog?
Después de mucha búsqueda de errores, modifiqué las incidencias de random_next[24 +: 4]
a random_next[28 +: 4]
y el banco de pruebas funciona.