3

I'm trying to understand how pins should be defined in SystemVerilog.

I have:

  • a common dataBus
  • a ramController module which can send or receive data on its ioData pins.
  • a top level module which can write to the ramController (e.g. prepare a display buffer)
  • a vgaController which mostly receives data from the ramController but also has a command mode which allows it to be configured using data on the dataBus

The ioData pins in the ramController are bi-directional but also need to be tri-state so that the ramController can be "off the bus" when dataBus is being used to send commands to the vgaController

module RAMController(
    inout wire[15 : 0 ] ioData,
    ..
);
..
    logic [15 : 0 ] ioDataCopy;
    assign ioData = ( chipSelect ) ? ioDataCopy : 16'hzzzzzzzzzzzzzzzz;

Even if vgaController never writes to the dataBus, does it's pins need to be inout in order to be input or HiZ?

module VGAController(
    inout  wire  [15 : 0 ] iData;
);
..
logic [15 : 0 ] iDataCopy    = 0;
assign iData = ( chipSelect ) ? iDataCopy : 16'bzzzzzzzzzzzzzzzz;

Is dataBus simply a set of wire values in the top module?

module Top(
..
);
..
wire   [15 : 0 ] dataBus;

I may be going about this completely wrong. Can someone please help me in defining a system containing multiple modules that share the same bus.

1 Answer 1

2

It is difficult to say if you did it right or wrong without a reproducible example. However, some of your assertions are basically correct. I assume that your dataBus is same as your ioData at the controller level. In this case if both controllers are instantiated in 'top' and are connected correctly, you should be all set. You have to make sure that there is always only a single driver for the bus, so that 'chipSelect' prevents from multiple driving of the bus.

So, here is an example that demonstrates the above.

module Top();
  wire   [15 : 0 ] dataBus;
  logic[1:0] select;
  
  RAMController rc(.ioData(dataBus), .chipSelect(select == 1 ? 1 : 0));
  VGAController vc(.ioData(dataBus), .chipSelect(select == 2 ? 1 : 0));
  
  always @*
    $display("%0t select: %b, data: %b", $time, select, dataBus);
  
  initial begin
    select = 0;
    #1 select = 1;
    #1 select = 0;
    #1 select = 2;
    #1 select = 0;
    #1 $finish;
  end
  
endmodule

module RAMController(
    inout wire[15 : 0 ] ioData,
    input logic chipSelect 
    //...
);
  logic [15 : 0 ] ioDataCopy = 1;
  assign ioData = ( chipSelect ) ? ioDataCopy : 'z;
endmodule

module VGAController(
    inout wire[15 : 0 ] ioData,
    input logic chipSelect 
    //...
);
  logic [15 : 0 ] ioDataCopy = 2;
  assign ioData = ( chipSelect ) ? ioDataCopy : 'z;
endmodule

and the result:

0 select: 00, data: xxxxxxxxxxxxxxxx
0 select: 00, data: zzzzzzzzzzzzzzzz
1 select: 01, data: zzzzzzzzzzzzzzzz
1 select: 01, data: 0000000000000001
2 select: 00, data: 0000000000000001
2 select: 00, data: zzzzzzzzzzzzzzzz
3 select: 10, data: zzzzzzzzzzzzzzzz
3 select: 10, data: 0000000000000010
4 select: 00, data: 0000000000000010
4 select: 00, data: zzzzzzzzzzzzzzzz

To be more verbose you could use tri definition instead of wire. There is no difference between them, but makes the code more readable, IMHO.

tri [15:0] dataBus;
...
tri [15:0] ioData;
Sign up to request clarification or add additional context in comments.

1 Comment

Thankyou @Serge. I will try and dumb down my project and possibly update my question. I'm getting ""Top" must drive a to-level pin but is driving <nothing>" now. It's hard finding time to focus on this outside of work too :-( I definitely prefer the tri definition though - that is a lot clearer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.