1 votos

Verilog: ¿Existen algunas reglas básicas para la configuración de los puertos?

Estoy tratando de escribir un módulo maestro SPI por mí mismo 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 pruebo el 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é? También cuando añado: 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é ocurre esto? He leído en algún sitio que dice que nunca hay que poner las entradas como regs. Pero el editor lanza sugerencias exactamente opuestas. Así que, para resumir, ¿hay reglas básicas para la configuración de puertos en Verilog? ¿Cómo debería empezar?

Y en segundo lugar, realmente no entendí por qué no debemos utilizar los registros como entradas. ¿Por qué? ¿Dónde voy a almacenar las entradas? ¿Cómo las voy a leer? Creo que tengo que usar registros para las entradas que no se consideran como interrupciones. ¿Alguien puede explicarlo? Se lo agradezco mucho.

4voto

RWH Puntos 21

Para empezar, en la parte superior de su spi_master tiene rx_data declarado como entrada. Luego, en la línea 74 (supongo, no he contado) 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 instanciador (o el banco de pruebas) y entregados al spi_master como entradas.

Si la intención es que sus datos se reciban en el miso (porque usted es el maestro) y luego hacerlo disponible en una palabra paralela al código donde su módulo es instanciado, entonces rx_data debería ser una salida de este módulo.

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

La verdad es que no entendí por qué no hay que utilizar los registros como entradas. ¿Por qué? ¿Dónde voy a almacenar las entradas? ¿Cómo las leeré?

No puedes hacer que una entrada sea un reg porque no la vas a asignar en el módulo donde es una entrada.

La asignará en el módulo superior. Que lo declare como reg o no en ese módulo depende de cómo se asigne. Si se asigna en un módulo always debe ser un reg. Si se asigna en un bloque assign o es la salida de otro módulo, entonces no debe ser un reg.

En general, yo diría que tienes que pensar más cuidadosamente sobre lo que es una salida y lo que es una entrada de tu módulo. Piensa en un diagrama de bloques de tu diseño y en que cada instancia de tu módulo está representada por un bloque. Si la señal sale del bloque, es una salida. Si la señal fluye hacia el bloque, es una entrada.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X