Electronic – Birectional I/O pin in verilog

fpgaverilog

I'm wanting eventually to interface some memory to my fpga.
This will require pins on the fpga that can both read data and write output to the ram.

I'm far away from doing any of that yet, but as a learning exercise wanted make a simple module in verilog that when a direction signal is '1' output a signal to a pin, and when it is '0' reads a value from that pin.

But I can't get anything to compile. I'm not completely inexperienced with verilog but feel I'm missing something fundamental here rather than just having a simple typo in my example.

This code doesn't compile, I'm looking for either how to make it work, or even just a pointer to what I'm fundamentally missing to make bidirectional signals work. If it matters I'm using xilinx tools and plan to synthesize this to an xc3s50 or similar.

// This doesn't compile...
module test(
    input  clock,           // The standard clock
     input  direction,  // Direction of io, 1 = set output, 0 = read input
     input  data_in,        // Data to send out when direction is 1
     output data_out,       // Result of input pin when direction is 0
     inout  io_port     // The i/o port to send data through
     );

always @(posedge clock)
begin

    // If direction is 1 then set 
    if (direction == 1)
    begin
        io_port <= data_out;
    end

    if (direction == 0)
    begin
         data_in <= io_port;
    end
end

endmodule

edit The errors I get are –

ERROR:HDLCompilers:247 - "test.v" line 16 Reference to scalar wire 'io_port' is not a legal reg or variable lvalue
ERROR:HDLCompilers:106 - "test.v" line 16 Illegal left hand side of nonblocking assignment
ERROR:HDLCompilers:247 - "test.v" line 21 Reference to scalar wire 'data_in' is not a legal reg or variable lvalue
ERROR:HDLCompilers:106 - "test.v" line 21 Illegal left hand side of nonblocking assignment

Best Answer

Inouts are actually "wire" so you can't use any procedural/sequential assignments (where the left hand side must be a reg). Generally speaking:

  • input : internally must always be of type net, externally the inputs can be connected to a variable of type reg or net.
  • output : internally can be of type net or reg, externally the outputs must be connected to a variable of type net.
  • inout : internally or externally must always be type net, can only be connected to a variable net type.

A common approach is to have an "enable" signal for the output of your inout, and to drive to high impedance if the output is not enabled. In your case direction is playing that role.

So try this instead:

module test(
    input  clk,      // The standard clock
    input  direction,  // Direction of io, 1 = set output, 0 = read input
    input  data_in,    // Data to send out when direction is 1
    output data_out,   // Result of input pin when direction is 0
    inout  io_port     // The i/o port to send data through
    );

    reg a, b;    

    assign io_port  = direction ? a : 1'bz;
    assign data_out = b;

    always @ (posedge clk)
    begin
       b <= io_port;
       a <= data_in;
    end

endmodule

The hardware corresponding to the above code would look something like this:

enter image description here