Electronic – Verilog: Are there some basic rules for port settings

fpgaverilog

Iam trying to write a SPI master module by myself to learn FPGA-Verilog efficiently. Here is the spi_master module:

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

And here is the test module;

`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

the spi_master module can be compiled without error but when I try testbench I get this 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

Why is this? Also when I add: reg [15:0] rx_data; to the spi_master module this time I get this:

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

Why is this happening? I ve read somewhere that says never set inputs as regs. But editor throws exact opposite suggestions. So, to sum up, Are there basic rules for port settings in Verilog? How should I start?

And secondly, I really did not understand why we should not use registers as inputs. Why is that? Where will I store inputs? How will I read them? I think I have to use registers for inputs which is not considered as interrupts. Can someone explain it? I d really appreciate.

Best Answer

Just to start out, at the top of your spi_master module, you have rx_data declared as an input. Then at line 74 (I assume, I didn't count) you have

#1 rx_data[rx_counter] <= miso;

If rx_data is an input to spi_master, then spi_master should not be assigning any values to it. The values should be assigned by the instantiating module (or test bench) and given to the spi_master instance as inputs.

If the intent is that your receive data on the miso line (because you're the master) and then make it available in a parallel word to the code where your module is instantiated, then rx_data should be an output from this module.

I also see an issue where you have tx_data and mosi both declared as outputs. If the intent is to take tx_data in parallel, and convert it to serial data on the mosi line, then tx_data should be an input to your module.

I really did not understand why we should not use registers as inputs. Why is that? Where will I store inputs? How will I read them?

You can't make an input a reg because you aren't going to assign to it in the module where it is an input.

You will assign to it in the higher-level module. Whether you declare it as a reg or not in that module depends on how it's assigned to. If it's assigned in an always block, it must be a reg. If it's assigned in an assign statement, or it's the output from another module, then it must not be a reg.

Generally, I'd say you need to think more carefully about what's an output and what's an input to your module. Think about if you were drawing a block diagram of your design, and each instance of your module were represented by a block. If the the signal would be flowing out of the block, that's an output. If the signal would be flowing in to the block, that's an input.