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;


    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;

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


    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;




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;


always begin 
    #1 clk = ~clk;

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

spi_master SPI_block(




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.

  • 2
    \$\begingroup\$ There are hundreds of different coding standards out there, but for what it is worth, I prefix inputs with i_signal_name, outputs with o_signal_name and bidirectional ports with io_signal_name. I capitalize the signal name on the top-level / for ports that connect to the outside world. Perhaps adopting a similar nomenclature will help you out. Tx/ Rx naming is always unclear. \$\endgroup\$ – Krunal Desai Dec 28 '15 at 17:38
  • 1
    \$\begingroup\$ It's also a good idea to avoid inouts aside from the top module. It's a much better idea to break out separate input, output, and oe/tristate signals. This is because FPGAs cannot implement tristate logic the fabric, only in the IOBs. If you switch to tristate logic to early, then there are some things that you will not be able to do, such as an internal I2C bus or multiple I2C devices sharing the same pins. \$\endgroup\$ – alex.forencich Dec 28 '15 at 23:54

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.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.