Simulación de pines inout desde un testbench

Diseño HDL con este lenguaje. Módulos y testbenchs. Estilos y trucos de codificación, etc. NOTA: dado que hay entornos como ISE que soportan Verilog pero no SystemVerilog, señalad dentro de un post que de lo que se va a tratar es SystemVerilog si es el caso.
Responder
wilco2009
Veroboard
Mensajes: 16
Registrado: 17 Ago 2018, 10:53

Simulación de pines inout desde un testbench

Mensaje por wilco2009 » 18 Ago 2018, 16:24

A ver si me aclaro con este tema, ya que hace tiempo que lo voy sorteando pero no acabo de aclararme.
Alguien me puede explicar cómo se simula el valor de una entrada en un pin inout. Si se asigna a pelo bien da error cuando lo intentas simular, bien no te hace ni caso.

Yo sorteo el tema utilizando force, pero creo que no es una buena práctica.

Avatar de Usuario
mcleod_ideafix
Site Admin
Mensajes: 80
Registrado: 14 Ago 2018, 01:15

Re: Simulación de pines inout desde un testbench

Mensaje por mcleod_ideafix » 19 Ago 2018, 18:56

wilco2009 escribió:
18 Ago 2018, 16:24
A ver si me aclaro con este tema, ya que hace tiempo que lo voy sorteando pero no acabo de aclararme.
Alguien me puede explicar cómo se simula el valor de una entrada en un pin inout. Si se asigna a pelo bien da error cuando lo intentas simular, bien no te hace ni caso.

Yo sorteo el tema utilizando force, pero creo que no es una buena práctica.
¿Puedes poner un código de ejemplo de lo que te gustaría poder simular? ¿Y en qué lenguaje? Porque lo has puesto en el foro de ISE, pero creo que tu pregunta va más encaminada a cómo se simula en Verilog, no es eso?

wilco2009
Veroboard
Mensajes: 16
Registrado: 17 Ago 2018, 10:53

Re: Simulación de pines inout desde un testbench

Mensaje por wilco2009 » 20 Ago 2018, 12:46

Efectivamente la pregunta está mal situada. Debería moverse al foro de Verilog.

Tenemos un interface como el de abajo, en el que una CPLD está conectada por un lado a todos los pines de una SRAM paralela, por el otro al bus del sistema y por último a un puerto SPI de un microcontrolador.

Código: Seleccionar todo

	
	wire [7:0] RAM_Data;
	
	PSRAMArduino uut (
		.Enable_Arduino(Enable_Arduino), 
		.Arduino_Data_out_Bit(Arduino_Data_out_Bit), 
		.Arduino_Data_in_Bit(Arduino_Data_in_Bit), 
		.Arduino_Clk(Arduino_Clk), 
		.Arduino_download(Arduino_download), 
		.Arduino_upload(Arduino_upload), 
		.RAM_Addr(RAM_Addr), 
		.RAM_Data(RAM_Data), 
		.RAM_WR(RAM_WR), 
		.RAM_OE(RAM_OE), 
		.RAM_CS(RAM_CS), 
		.Computer_Addr(Computer_Addr), 
		.Computer_Data(Computer_Data), 
		.Computer_WR(Computer_WR), 
		.Computer_OE(Computer_OE), 
		.Computer_CS(Computer_CS), 
		.nReset(nReset)
	);
El microcontrolador puede leer o escribir datos en la SRAM a través del puerto SPI pasando por la CPLD que los convierte a paralelo y que es la que conecta con la SRAM.

El problema viene cuando quiero simular los datos que vienen desde la SRAM hacia la CPLD. Si no hago nada, la entrada es 8'bzzzzzzzz, ya que la entrada es un inout con la siguiente definición:

Código: Seleccionar todo

assign RAM_Data = (Enable_Arduino==1'b0) && (Arduino_WR==1'b0)?	Computer_Data:
							8'bzzzzzzzz;
Si declaro RAM_Data como wire [7:0] me da un error al assignarla (como es lógico), pero si la declaro como reg [7:0] me da error cuando intento arrancar la simulación diciendo "non-net variable can't be connected to inout port RAM_Data".

Por lo que me veo obligado a utilizar wire y asignar con force.
¿No hay alternativa, o esta es la manera natural de hacerlo?

Código: Seleccionar todo

		#10;
		force RAM_Data = 8'b11101010;
		#10;
		Arduino_download = 1;
		#10;
		for (i=0;i<=15;i=i+1)
		begin
			Arduino_Clk = !Arduino_Clk;
			#10;
		end

Avatar de Usuario
mcleod_ideafix
Site Admin
Mensajes: 80
Registrado: 14 Ago 2018, 01:15

Re: Simulación de pines inout desde un testbench

Mensaje por mcleod_ideafix » 21 Ago 2018, 12:45

Entonces, lo que tú quieres es un módulo que permita simular una RAM, tal como una 62256 (creo que es la que usas, no?) de 32K x 8, y con pines de entrada/salida, de forma que la puedas incorporar a tu simulación, no?

A ver si esto te vale:

Código: Seleccionar todo

module ram_62256 (
  input wire [14:0] a,
  input wire cs_n,
  input wire oe_n,
  input wire we_n,
  inout wire [7:0] d
  );
  
  reg [7:0] ram[0:32767];
  assign d = (cs_n == 1'b0 && oe_n == 1'b0 && we_n == 1'b1)? ram[a] : 8'hZZ;
  always @* begin
    if (cs_n == 1'b0 && we_n == 1'b0)
      ram[a] = d;
  end
endmodule
En tu testbench, conecta esta RAM a tu controlador tal y como lo harías en el circuito real, y arranca la simulación. Ten en cuenta que al principio, lo que leas de la RAM será todo XXXXXXXX porque no habrá valor definido. Si por la razón que sea quieres inicializar toda la RAM a 0, justo después del reg [7:0] ram [0:32767] pon esto:

Código: Seleccionar todo

integer i;
initial begin
  for (i=0;i<32768;i=i+1)
    ram[i] = 8'h00;
end

Avatar de Usuario
mcleod_ideafix
Site Admin
Mensajes: 80
Registrado: 14 Ago 2018, 01:15

Re: Simulación de pines inout desde un testbench

Mensaje por mcleod_ideafix » 21 Ago 2018, 13:17

Un ejemplo de testbench para esta RAM (imitando un poco la forma en la que el la ROM del ZX Spectrum chequea la RAM al principio):

https://www.edaplayground.com/x/2yv9

Fíjate que el truco está en que aquello a lo que conectes un puerto inout sea siempre un wire, y nunca un reg, y que este wire (dato, en el ejemplo) tenga siempre un valor (con assign). En este caso, ese valor es o bien un dato que proviene de un registro (dato_escrito), cuando queremos escribir, o bien "alta impedancia" cuando lo que queremos es leer. En este último caso, leeríamos directamente desde el wire al que conectas el puerto (dato)

Testbench:

Código: Seleccionar todo

module test_ram;
  reg [14:0] direccion;
  wire [7:0] dato;
  reg we_n = 1'b1;
  reg oe_n = 1'b1;
  reg [7:0] dato_leido, dato_escrito;
  
  assign dato = (we_n == 1'b0)? dato_escrito : 8'hZZ;
  
  ram_62256 la_ram (
    .a(direccion),
    .cs_n(1'b0),
    .oe_n(oe_n),
    .we_n(we_n),
    .d(dato)
  );
  
  initial begin
    direccion = 0;
    we_n = 1;
    oe_n = 1;
    dato_escrito = 8'h80;
    // Paso 1: guardamos el valor 80h en toda la memoria
    repeat (32768) begin
      #10; // un poco de tiempo para que el dato esté estable
      we_n = 0;
      #10; // otro poco de tiempo para que se escriba el dato
      we_n = 1;
      direccion = direccion + 1;
    end
    
    direccion = 0;
    we_n = 1;
    oe_n = 1;
    // Paso 2: leemos el valor guardado, restamos 1, y volvemos a guardar
    repeat (32768) begin
      oe_n = 0;
      #10; // un poco de tiempo para que el dato esté estable
      dato_leido = dato;
      #10; // otro poco de tiempo para que se escriba el registro dato_leido
      oe_n = 1;      
      dato_escrito = dato_leido + 8'hFF;  // restamos 1
      #10; // un poco de tiempo para que el dato esté estable
      we_n = 0;
      #10; // otro poco de tiempo para que se escriba el dato
      we_n = 1;
      direccion = direccion + 1;
    end

    direccion = 0;
    we_n = 1;
    oe_n = 0;
    // Paso 3: comprobar que en todas las celdas el valor es 7Fh
    repeat (32768) begin
      #10; // un poco de tiempo para que el dato esté estable
      dato_leido = dato;
      #10; // otro poco de tiempo para que se escriba el registro dato_leido
      if (dato_leido != 8'h7F) begin
        $display ("Error en direccion %h. Leido: %h\n", direccion, dato_leido);
        $finish;
      end
      direccion = direccion + 1;
    end
    $display ("Todo correcto!\n");
    $finish;
  end
endmodule

Responder

Volver a “Verilog / SystemVerilog”