Instrucciones iniciales
- Haremos las sesiones de este seminario en el aula de microelectrónica (situado en la primera planta del edificio 4D de la ETSIT)
- Necesito que vayáis equipados con vuestro portátil y que tengáis instalado dos programas que tenéis en recursos de poliformat. Son Questasim (que es posible que algunos de vosotros ya tengáis instalado) y un asistente de systemverilog denominado SystemVerilog-VHDL assistant. Afortunadamente, no son programas muy pesados y para poder ejecutarlos necesitaréis estar en la VPN de la universidad (si estáis fuera de la universidad) o conectados a través de UPVNET. Es necesario que añadáis una variable de entorno a vuestro windows que encontraréis disponible bajo la carpeta de questasim de recursos del poliformat del curso de formación Aula de Microelectrónica.
- Para terminar, nuestro canal de comunicación con vosotros será a partir de ahora será la página web https://dsd.webs.upv.es/ En dicha web está gravados en video los pasos que vamos a hacer en este seminario y que intentaremos ejecutar en directo. Es muy importante que vengáis equipados con auriculares!!
Diseño a verificar
Vamos a verificar una FIFO síncrona. El código ASM es el que se adjunta en la siguiente figura

Os adjunto información de cómo deberían denominarse los puertos y de entrada y salida. Es muy importante respetar este tipo de nombres sobre todo si se quiere reusar un banco de pruebas previo.

Comportamiento
El comportamiento es el mostrado en el siguiente cronograma
Punto de partida
En esta sesión nos vamos a conformar en la realización del diseño y del proyecto del banco de pruebas con systemverilog. Aunque incluimos la forma de acometer el diseño en el siguiente subapartado, es bueno disponer de un diseño de pruebas que os vamos a proporcionar
Diseño
Para la realización del diseño seguid las pautas del siguiente video en el cual el algoritmo realizado es un radicador. Con este procedimiento agilizaremos el diseño aunque no se vislumbre claramente los elementos del control-path y del data-path; pero también es importante que sepáis hacer ese traslado directo de ASM a systemVerilog.
Como alternativa, y para agilizar el tránsito hacia la verificación y poder avanzar, se os proporciona un código no sintetizable que nos sirva como DUV de nuestro banco de verificación UVM. De paso nos podrá servir como modelo de alto nivel que explique el comportamiento de la FIFO deseada utilizando un tipo de dato queue de SV.
module FIFO_no_sintetizable
( input CLOCK, RESET_N, CLEAR_N,
input [7:0] DATA_IN,
input READ,WRITE,
output [7:0] DATA_OUT,
output [4:0] USE_DW,
output F_EMPTY_N,F_FULL_N);
logic [7:0] cola [$:32] ;
logic [7:0] DATA_OUT_LOGIC;
logic [4:0] USE_DW_LOGIC;
logic F_EMPTY_N_LOGIC,F_FULL_N_LOGIC;
assign DATA_OUT=DATA_OUT_LOGIC;
assign USE_DW=USE_DW_LOGIC;
assign F_EMPTY_N=F_EMPTY_N_LOGIC;
assign F_FULL_N=F_FULL_N_LOGIC;
always_ff @(negedge RESET_N, posedge CLOCK)
if (!RESET_N)
begin
cola.delete();
DATA_OUT_LOGIC=0;
USE_DW_LOGIC=0;
F_FULL_N_LOGIC=1;
F_EMPTY_N_LOGIC=0;
end
else
if (!CLEAR_N)
begin
cola.delete();
DATA_OUT_LOGIC=0;
USE_DW_LOGIC=0;
F_FULL_N_LOGIC=1;
F_EMPTY_N_LOGIC=0;
end
else
begin
case ({READ,WRITE})
2'b01: cola.push_front(DATA_IN);
2'b10: DATA_OUT_LOGIC=cola.pop_back();
2'b11: begin
cola.push_front(DATA_IN);
DATA_OUT_LOGIC=cola.pop_back();
end
endcase
USE_DW_LOGIC=cola.size();
F_FULL_N_LOGIC=!(cola.size()==32);
F_EMPTY_N_LOGIC=!(cola.size()==0);
end
property llenado ;
(@(posedge CLOCK) not (WRITE==1'b1 && F_FULL_N==1'b0 &&READ==1'b0));
endproperty
sobrellenado:assert property (llenado) else $error("estas escribiendo sobre una fifo llena");
property vaciado ;
(@(posedge CLOCK) not (READ==1'b1 && F_EMPTY_N==1'b0&& WRITE==1'b0)) ;
endproperty
sobrevaciado:assert property (vaciado) else $error("estas leyendo de una fifo vacia");
endmodule
veamos
Verificación
Este va a ser nuestro gran objetivo de la tarea.
Ya para empezar a realizar el banco de pruebas, proponemos un punto de partida totalmente clásico mediante un modulo que contiene un initial en donde se sucenden unos casos de test que están implementados mediante unos task (un buen representante de este vivel superior podría ser el task denominado test_B, que a su vez anidan en su interior unos tasks de nivel intermedio (como por ejemplo llenar_simple), que asu vez contienne en su interior tasks de operaciones básicas de escritura y lectura de la FIFO (solo_escritura y solo_lectura serían ejemplos de este nivel de task ).
// Code`timescale 1 ns/ 1 ps
module FIFO_tb_v0();
parameter DEPTH=32, WIDTH=8;
localparam ADDRESS=$clog2(DEPTH-1);
logic clock, reset, rden,wren,clear;
logic [WIDTH-1:0] data_in;
logic [ADDRESS-1:0] use_dw;
logic [4:0] rdaddress;
logic [4:0] wraddress;
logic full,empty;
logic [WIDTH-1:0] data_out;
//Modelo de la FIFO
logic [7:0] FIFO_ideal [$]; //Definida con una cola
mailbox FIFO_ideal_mbox = new(); //definida con un mailbox
// Instancia del DUV
FIFO_no_sintetizable DUV (.CLOCK(clock),
.RESET_N(reset),
.DATA_IN(data_in),
.READ(rden),
.WRITE(wren),
.CLEAR_N(1'b1),
.F_FULL_N(full),
.F_EMPTY_N(empty),
.USE_DW(use_dw),
.DATA_OUT(data_out));
// Casos de Test
initial
begin
$info("INICIO VALIDACION");
inicializacion();
$info("*** TEST 1: Escritura simple");
test_A();
$info("*** FIN TEST 1 ****");
$info ("*** TEST 2: LLenado simple de la FIFO");
resetON();
llenar_simple();
$info("*** FIN TEST 2 ****");
$info("*** TEST 3: Escritura y lectura simultanea con FIFO vacia");
resetON();
lectura_escritura(10,10);
$info("*** FIN TEST 3 ****");
$info("*** TEST 3: Escritura y lectura simultanea con FIFO llena");
resetON();
test_B();
$info("*** FIN TEST 3 ****");
$info("*** TEST 4: Llenado y vaciado de la FIFO");
resetON();
test_C();
$info("*** FIN TEST 4 ****");
$info("*** TEST 5: Escritura y lectura aleatoria con FIFO vacia, llena y a mitad.");
resetON();
test_D();
$info("*** FIN TEST 5 ****");
repeat(5) @(posedge clock);
$info("FIN VALIDACION");
$stop;
end
initial begin
$dumpfile("FIFO_TB.vcd");
$dumpvars(0,FIFO_tb_v0.DUV);
end
assign clear = 1'b1;
// Generación de reloj
initial
begin
clock = 1'b0;
forever #10 clock = !clock;
end
// Inicialización de las entradas
task init_inputs();
begin
data_in <='0;
wren <= 1'b0;
rden <= 1'b0;
end
endtask
// Generación de reset
task resetON();
begin
#10 reset=1'b0;
FIFO_ideal={};
repeat(5) @(posedge clock);
#7 reset=1'b1;
end
endtask
// Escritura de datos en la FIFO.
// La entrada define el número de datos a escribir
task solo_escritura(input integer n_escrituras);
begin
logic [7:0] dato;
wren<=1'b0;
@(negedge clock)
wren<=1'b1;
repeat (n_escrituras) begin
dato = $random%256;
data_in = dato;
FIFO_ideal.push_front(dato);
@(negedge clock);
end
wren <= 1'b0;
end
endtask
// Lectura de datos de la FIFO, el número de datos a leer
// Monitoriza la salida.
task solo_lectura(input integer n_lecturas);
logic [7:0] dato;
begin
rden <= 1'b0;
@(negedge clock);
rden <= 1'b1;
repeat (n_lecturas) begin
@(negedge clock);
dato = FIFO_ideal.pop_back();
assert (dato == data_out) else $error("ERROR el dato leido %h no coincide con el esperado %h", dato, data_out);
end
rden <= 1'b0;
end
endtask
// Lectura y escritura de datos simultanea. Se definen cuantos datos a leer y a escribir.
task lectura_escritura( input integer n_lecturas, input integer n_escrituras);
fork
solo_escritura(n_escrituras);
solo_lectura(n_lecturas);
join
endtask
//Monitor de palabras en la fifo
// palabras en la fifo
integer palabras;
always @(posedge clock, negedge reset)
if (!reset) palabras=0;
else if (!clear) palabras=0;
else
case({wren,rden})
2'b01: palabras = palabras-1;
2'b10: palabras = palabras+1;
endcase
// Asserciones de control de la FIFO
always @(negedge clock)
begin
if (reset && clear) begin
assert ((!empty)?(palabras == 0):(palabras != 0)) else $error("ERROR señal de FIFO vacía activada incorrectamente");
assert ((!full)? (palabras == 32):(palabras != 32)) else $error("ERROR señal de FIFO llena activada incorrectamente");
assert (palabras <= 32) else $error("ERROR FIFO con tamaño incorrecto");
assert (palabras[4:0] == use_dw) else $error("ERROR USE_DW no funciona como se espera");
end
end
//empiezan los tasks de alto nivel:casos de test
task inicializacion;
begin
$display("Inicializacion de las entradas");
init_inputs;
$display(" reset inicial");
resetON();
end
endtask
// Escritura simple de dos valores y una lectura.
task test_A;
begin
$display(" escribo dos valores");
solo_escritura(1);
solo_escritura(1);
$display("leo un valor");
solo_lectura(1);
end
endtask
// Escritura y lectura simultanea con fifo llena.
task test_B;
begin
llenar_simple;
lectura_escritura(10,10);
end
endtask
// Test de llenado y vaciado.
task test_C;
begin
llenar_simple;
vaciado_simple();
lectura_escritura(10,10);
end
endtask
task test_D;
begin
vaciado_simple();
rd_wr_random(100);
llenar_simple;
rd_wr_random(100);
vaciado_simple();
solo_escritura(15);
rd_wr_random(100);
end
endtask
// Escrituras y lecturas aleatorias.
task rd_wr_random(integer numero);
begin
integer caso;
repeat(numero) begin
caso = $random%3;
case (caso)
0: if (empty) solo_lectura(1);
1: if (full) solo_escritura(1);
2: lectura_escritura(1,1);
endcase
end
end
endtask
// Task de llenado de la FIFO
task llenar_simple();
logic [7:0]cuenta;
begin
cuenta<=8'b0;
while (full==1'b1)
begin
solo_escritura(1);
cuenta++;
end
end
endtask
// Task de vaciado de la FIFO
task vaciado_simple();
logic [7:0]cuenta;
begin
cuenta<=8'b0;
while (empty==1'b1)
begin
solo_lectura(1);
cuenta++;
end
end
endtask
endmodule
// or browse Examples
//Monitor de palabras en la fifo
// palabras en la fifo
integer palabras;
always_ff @(posedge clock, negedge reset)
if (!reset) palabras=0;
else if (!clear) palabras=0;
else
case({wren,rden})
2'b01: palabras = palabras-1;
2'b10: palabras = palabras+1;
endcase
// Asserciones de control de la FIFO
always @(negedge clock)
begin
if (reset && clear) begin
assert ((!empty)?(palabras == 0):(palabras != 0)) else $error("ERROR señal de FIFO vacía activada incorrectamente");
assert ((!full)? (palabras == 32):(palabras != 32)) else $error("ERROR señal de FIFO llena activada incorrectamente");
assert (palabras <= 32) else $error("ERROR FIFO con tamaño incorrecto");
assert (palabras[4:0] == use_dw) else $error("ERROR USE_DW no funciona como se espera");
end
end
//empiezan los tasks de alto nivel:casos de test
task inicializacion;
begin
$display("Inicializacion de las entradas");
init_inputs;
$display(" reset inicial");
resetON();
end
endtask
// Escritura simple de dos valores y una lectura.
task test_A;
begin
$display(" escribo dos valores");
solo_escritura(1);
solo_escritura(1);
$display("leo un valor");
solo_lectura(1);
end
endtask
// Escritura y lectura simultanea con fifo llena.
task test_B;
begin
llenar_simple;
lectura_escritura(10,10);
end
endtask
// Test de llenado y vaciado.
task test_C;
begin
llenar_simple;
vaciado_simple();
lectura_escritura(10,10);
end
endtask
task test_D;
begin
vaciado_simple();
rd_wr_random(100);
llenar_simple;
rd_wr_random(100);
vaciado_simple();
solo_escritura(15);
rd_wr_random(100);
end
endtask
// Escrituras y lecturas aleatorias.
task rd_wr_random(integer numero);
begin
integer caso;
repeat(numero) begin
caso = $random%3;
case (caso)
0: if (empty) solo_lectura(1);
1: if (full) solo_escritura(1);
2: lectura_escritura(1,1);
endcase
end
end
endtask
// Task de llenado de la FIFO
task llenar_simple();
logic [7:0]cuenta;
begin
cuenta<=8'b0;
while (full==1'b1)
begin
solo_escritura(1);
cuenta++;
end
end
endtask
// Task de vaciado de la FIFO
task vaciado_simple();
logic [7:0]cuenta;
begin
cuenta<=8'b0;
while (empty==1'b1)
begin
solo_lectura(1);
cuenta++;
end
end
endtask
endmodule
// or browse Examples
El diagrama de bloques de este banco de pruebas sería:

Para que podáis reproducir todo esta verificación con esta fifo no sintetizable y poder disponer completamente del proyecto preparado para questasim, incorporamos el siguiente laboratorio virtual que está preparado para que cuando se ejecute, al final os proporcione un zip con todos los ficheros disponibles en formato adecuado para questasim. Este será vuestro punto de partida!! y vamos a intentar realizar mediante test aleatorios el mismo grado de cobertura funcional o incluso superior que lo que está conseguido mediante este banco de pruebas con tests directos que os proporcionamos.
