Verilog: ¿Existen algunas reglas básicas para la configuración del puerto?

1

Estoy intentando escribir un módulo maestro SPI por mi cuenta para aprender FPGA-Verilog de manera eficiente. Aquí está el módulo spi_master:

module spi_master(

        output [15:0] tx_data,
        input [15:0] rx_data,
        output mosi,
        input miso,
        output cs,
        output sck,
        input start

    );

     reg [15:0] tx_data;

     reg [3:0] tx_counter;
     reg [3:0] rx_counter;

     wire start;
     reg cs;
     reg mosi;
     wire miso;
     wire sck;

     initial begin


     tx_counter [3:0] = 4'b0;
     rx_counter [3:0] = 4'b0;

     end


    always @(negedge sck) begin

        if (cs == 0 && tx_counter != 4'b1111) begin
            #(5) mosi <= tx_data[tx_counter];
            #(6) tx_counter <= tx_counter + 4'b1;

        end
        else if(cs == 0 && tx_counter == 4'b1111) begin
            #(5) cs <= 1'b1;
        end
        else if (cs == 1 && tx_counter == 0) begin
            #(5) cs <= 1'b0;
        end

    end

    always @(posedge sck) begin

        if (cs == 0 && tx_counter <= 4'b1111 && tx_counter >= 4'b0001) begin
            #1 rx_data[rx_counter] <= miso;
            #2 rx_counter <= rx_counter + 4'b1;

        end

    end


endmodule

Y aquí está el módulo de prueba;

'include "spi_master.v"

module spi_master_tb(
    );

reg clk;
reg start;

reg mosi;
wire miso;

reg cs;
reg sck;

reg [15:0] tx_data;

initial begin

clk = 0;
tx_data = 16'hF0AA;
#20 start = 1'b1;
#1000 $finish;
sck = 0;

end

always begin 
    #1 clk = ~clk;
end

always @(start) begin 
    #10 sck = ~sck;   // divided clk by CLK_DIVIDER
end


spi_master SPI_block(

        tx_data,
        rx_data,
        mosi,
        miso,
        cs,
        sck,
        start

    );

endmodule

el módulo spi_master se puede compilar sin error, pero cuando intento testbench me sale este error:

ERROR:HDLCompiler:1660 - "C:/Users/aozel/Desktop/FPGA Projects/myModule/../Test2/spi_master.v" Line 74: Procedural assignment to a non-register rx_data is not permitted, left-hand side should be reg/integer/time/genvar

¿Por qué es esto? También cuando agrego: reg [15:0] rx_data; al módulo spi_master esta vez, obtengo esto:

ERROR:HDLCompiler:661 - "C:/Users/aozel/Desktop/FPGA Projects/myModule/../Test2/spi_master.v" Line 24: Non-net port rx_data cannot be of mode input

¿Por qué sucede esto? He leído en algún lugar que dice nunca establecer entradas como registros. Pero el editor arroja exactamente sugerencias opuestas. Entonces, para resumir, ¿hay reglas básicas para la configuración de puertos en Verilog? ¿Cómo debo empezar?

Y, en segundo lugar, realmente no entendí por qué no deberíamos usar registros como entradas. ¿Porqué es eso? ¿Dónde almacenaré las entradas? ¿Cómo los leeré? Creo que tengo que usar registros para entradas que no se consideran como interrupciones. ¿Alguien puede explicarlo? Realmente lo apreciaría.

    
pregunta Alper91

1 respuesta

4

Para comenzar, en la parte superior de su módulo spi_master , ha declarado rx_data como entrada. Luego, en la línea 74 (supongo que no conté) tienes

#1 rx_data[rx_counter] <= miso;

Si rx_data es una entrada para spi_master , entonces spi_master no debería asignarle ningún valor. Los valores deben ser asignados por el módulo de creación de instancias (o banco de pruebas) y dados a la instancia spi_master como entradas.

Si la intención es que reciba datos en la línea miso (porque usted es el maestro) y luego haga que esté disponible en una palabra paralela al código donde se crea una instancia de su módulo, entonces rx_data debería ser un salida de este módulo.

También veo un problema donde tienes tx_data y mosi declarados como salidas. Si la intención es tomar tx_data en paralelo y convertirlo a datos en serie en la línea mosi , entonces tx_data debería ser una entrada para su módulo.

  

Realmente no entendí por qué no deberíamos usar registros como entradas. ¿Porqué es eso? ¿Dónde almacenaré las entradas? ¿Cómo los leeré?

No puede hacer que una entrada sea un registro porque no va a asignársela en el módulo donde es una entrada.

Le asignará en el módulo de nivel superior. Si lo declara como un registro o no en ese módulo depende de cómo se asigna. Si se asigna en un bloque always , debe ser un registro. Si se asigna en una declaración assign , o es la salida de otro módulo, entonces no debe ser un registro.

En general, diría que debe pensar más detenidamente sobre qué es una salida y qué es una entrada para su módulo. Piense si estaba dibujando un diagrama de bloques de su diseño, y cada instancia de su módulo estaba representada por un bloque. Si la señal saliera del bloque, eso es una salida. Si la señal fluiría hacia el bloque, eso es una entrada.

    
respondido por el The Photon

Lea otras preguntas en las etiquetas