Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

What is the logic behind inout ports and other Verilog idiosyncrasies?

64 views
Skip to first unread message

Jeffrey Turner

unread,
May 23, 2002, 9:50:34 PM5/23/02
to
I am simulating a microprocessor and have internal buses.
I have tried to connect a module to a bus, but only get
inane error messages - I'm using iverilog. Here goes:

module CPU_submodule0(addr_bus, data_bus, read, clk);

input [31:0] addr_bus;
input read;
inout [31:0] data_bus;
reg [31:0] submodule0_data;
reg [31:0] addr_reg; // This is just silly!

always @(posedge clk)
begin
addr_reg <= addr_bus;
if(addr_reg == `SUBMOD0_ADDR)
@(negedge clk)
begin
if(read)
submodule0_data <= data_bus;
else
data_bus <= submodule0_data;
end
end
endmodule

Now even though data_bus is supposedly inout I get an
error because it's not declared as a register and I'm
assigning to it. If I declare it as a register, I get
an error message because I'm using it as an input. I
have written tons of VHDL - actually most of an original
microprocessor design and bidirectional signals were
never a problem. What gives with Verilog? I find it
to be an overly verbose attempt at an HDL. In VHDL
if I didn't care whether a signal was rising or falling
I could just say 'pchanging <signal>', in Verilog it
seems I need 'posedge <signal> or negedge <signal>' and
i don't know how to impliment this for a bus.

Verilog seems to be a popular language, but I seriously
wonder why. Do people just like typing?

--Jeff Turner
Principal Engineer
Luna-Tech Systems

Kevin Neilson

unread,
May 24, 2002, 1:39:50 AM5/24/02
to
I've heard Verilog maligned before, but never for being too verbose.
There's a trick to tristate buses: you pretty much have to use the ?:
construct. I'm pretty sure what you have isn't synthesizable because you
have two edge sensitivity statements in one process. Here's the basic cpu
i/f (some declarations left out):

inout [7:0] cpu_data;
assign cpu_data = read ? cpu_data_out : 8'bz; // this synthesizes as
tristate buffers
wire [7:0] cpu_data_in = cpu_data; // this is the read bus
always@(cpu_addr or reg0 or reg1)
case (cpu_addr) // synthesis parallel_case
R_REG0_ADDR: cpu_data_out = reg0;
R_REG1_ADDR: cpu_data_out = reg1;
default: cpu_data_out = 'bx;
endcase
always@(posedge write)
case (cpu_addr) // synthesis parallel_case
R_REG0_ADDR: reg0 <= cpu_data_in;
R_REG1_ADDR: reg1 <= cpu_data_in;
endcase

-Kevin

"Jeffrey Turner" <jtu...@localnet.com> wrote in message
news:3CED9C6A...@localnet.com...

Tom Nielson

unread,
May 24, 2002, 4:23:25 AM5/24/02
to

Verilog has a differnent notion of signalling than VHDL. Whereas VHDL uses
the resolved types to represent tri-state logic, Verilog has wires and
registers. Wires are used in continuous assignments (similar to a concurrent
assignment) and registers hold their states between assignments, like
signals in VHDL. Blocks with sensitivity lists (e.g. clocked blocks), case
statements and most behavioral code will use registers. Wire must be
continually driven from a continuous assignment or they are unknown (or
high-z, simulator dependent). Both wires and registers have strengths, and
multiple drivers are allowed. The result of having multiple drivers on a net
will be determined by a resolution table... similar in concept to the
std_logic type. So, when you want multiple drivers on a tristate bus, you
assign high-impedance "z" to all inactive drivers and your bus data to the
active driver.

example: three drivers, high-true read and write enables

inout [7:0] data_bus;
wire [7:0] data_bus; // this is redundant, but allowed, inputs are implied
wires
reg [7:0] dev0_data;
reg [7:0] dev1_data;
reg [7:0] dev2_data;

// Wire-up the output drivers using continuous assignments - if you use
registers, latches are inferred
// when you synthesize... which is probably not what you want. Remeber,
to use the blocking assignment
// or you'll get into trouble when you use these assigned wires
elsewhere.
assign data_bus = (address == dev0_addr) && read ? dev0_data[7:0] : 8'hz;
// ? is the conditional operator
assign data_bus = (address == dev1_addr) && read ? dev1_data[7:0] : 8'hz;
// syntax:
assign data_bus = (address == dev2_addr) && read ? dev2_data[7:0] : 8'hz;
// assign <wire> = <condition> ? <true assignment> : <false assignment>;

always@(posedge clk) // now register the input data
begin
if ((address == dev0_addr) && write ) dev0_data <= data_bus;
if ((address == dev1_addr) && write ) dev1_data <= data_bus;
if ((address == dev2_addr) && write ) dev2_data <= data_bus;
end

The code that you wrote looks like a suspended process in VHDL, except for
the sensitivity list (which would not be allowed). This type of contruct
only operates on registers. Input ports and inouts are implied wires (think
about it). Outputs must be declared and can be reg or wire (which is why
they must be declared). Try not to think in terms of VHDL and signals, focus
on wires, flip-flops and latches. Verilog provides a much more explicit
description of real hardware than VHDL. You can get an excellent jumpstart
to Verilog (at least Verilog '97) by reading "Verilog HDL: A Guide to
Digital Design and Synthesis" by Samir Palnitkar (a little pricy, but has an
excellent presentation).

If you want to execute a block on any signal transition, use:
always@(<signal_name>)

or as in your example:

always@(clk) signal1 <= signal2;

I'll tell you what's silly and verbose:

process (clk)
begin
if clk'event and clk = '1' then
signal1 <= signal2;
end if;
end
end process;

-Tom N.

"Jeffrey Turner" <jtu...@localnet.com> wrote in message
news:3CED9C6A...@localnet.com...

Marco Fioretti

unread,
May 24, 2002, 4:15:11 AM5/24/02
to
Kevin Neilson wrote:
>
> I've heard Verilog maligned before, but never for being too verbose.

Same here. Let's not start a flame war, but normally verbosity is one
of the most often mentioned weaknesses of *VHDL* (even among some VHDL
designers).
Apart from that, I also recommend Kevin's suggestions.

Ciao,
Marco Fioretti

Rick Filipkiewicz

unread,
May 24, 2002, 9:38:04 AM5/24/02
to

Tom Nielson wrote:

> Verilog has a differnent notion of signalling than VHDL. Whereas VHDL uses
> the resolved types to represent tri-state logic, Verilog has wires and
> registers. Wires are used in continuous assignments (similar to a concurrent

<snip>

At the risk of sounding pedantic I think the use of ``register'' above causes
confusion to both newbies and those folk who have seen the light and are making
the change from VHDL (and s/w types to whom a "register" is the source of ALU
operands and the place ALU results are stored).

The Verilog data type is the "reg" and doesn't necessarily imply a h/w
"register" i.e. a place to store a bit of information that can only change on a
clock transition. [It really would have been better if the Verilog designers had
chosen some other name for this data type]

To illustrate:

reg foo;

// define foo as a h/w "register"
always (posedge clk)
foo <= bar0 & bar1;

// define foo as a "latch"

always @(clk or bar0 or bar1)
if (clk)
foo <= bar0 & bar1;

// define foo as the output of some combinatorial logic that's difficult to
specify
// using continuous assigns or is more compactly described using procedural
constructs.

wire [7:0] in;

reg [7:0] temp;
reg [2:0] sel;
integer i;

always @(in or sel) begin // somewhat artificial
for (i = 0; i < 8; i = i +1) // why oh why doesn't Verilog have "++" and
"+=" !
temp[i] <= (sel == i) ? ~in[sel] : in[sel];
foo <= |temp;
end


Rick Filipkiewicz

unread,
May 24, 2002, 11:38:29 AM5/24/02
to

of course this ....

>
> temp[i] <= (sel == i) ? ~in[sel] : in[sel];

should really have been this ...

temp[i] <= (sel == i) ? ~in[i] : in[i];

In other words ``invert the bit pointed to by sel''. Note that this example also
shows that "reg" variables can be temporaries and just vanish from the final result.
Another way of illustrating this is to use a "named" always block - which gives it
its own scope - and define the temp var locally:

always @(in or sel) begin: myname
reg [7:0] temp;
integer i;
begin
temp = 0; // Probably not needed but good practice to avoid accidental
latches.
for (i=0; i < 8; i = i + 1)
if (sel == i)
temp = (1'b1 << i);
end
foo = |(in ^ temp);
end

Jeffrey Turner

unread,
May 25, 2002, 7:34:35 PM5/25/02
to
Marco Fioretti wrote:

What do you mean not verbose? You declare the ports in the port list
then declare them again as input, outpur or inout and if they're output
you declare them a third time as reg. If that isn't redundancy...

--Jeffrey Turner

Jeffrey Turner

unread,
May 25, 2002, 7:42:44 PM5/25/02
to
Kevin Neilson wrote:

> I've heard Verilog maligned before, but never for being too verbose.
> There's a trick to tristate buses: you pretty much have to use the ?:
> construct. I'm pretty sure what you have isn't synthesizable because you
> have two edge sensitivity statements in one process.


I want the address read in one half the cycle and the data going
in or out in the other half. I suspect I need _another_ register.
Now tell me that's terse.

> Here's the basic cpu
> i/f (some declarations left out):
>
> inout [7:0] cpu_data;
> assign cpu_data = read ? cpu_data_out : 8'bz; // this synthesizes as
> tristate buffers


I saw this trick elsewhere and adopted it, it seems silly tho'.

The thing is I only have/want one bus for both addresses and data.


> wire [7:0] cpu_data_in = cpu_data; // this is the read bus
> always@(cpu_addr or reg0 or reg1)
> case (cpu_addr) // synthesis parallel_case
> R_REG0_ADDR: cpu_data_out = reg0;
> R_REG1_ADDR: cpu_data_out = reg1;
> default: cpu_data_out = 'bx;


Are you sure you want 'bx and not 'bz?

Rick Filipkiewicz

unread,
May 26, 2002, 5:30:47 AM5/26/02
to

Jeffrey Turner wrote:

> Kevin Neilson wrote:
>
> > I've heard Verilog maligned before, but never for being too verbose.
> > There's a trick to tristate buses: you pretty much have to use the ?:
> > construct. I'm pretty sure what you have isn't synthesizable because you
> > have two edge sensitivity statements in one process.
>
> I want the address read in one half the cycle and the data going
> in or out in the other half. I suspect I need _another_ register.
> Now tell me that's terse.
>

Jeffrey,

Before making statements like this stop and think for a while. Verilog is a
Hardware Description Language so just try and imagine what real h/w is needed
to realise what you want to do ...

>
> > Here's the basic cpu
> > i/f (some declarations left out):
> >
> > inout [7:0] cpu_data;
> > assign cpu_data = read ? cpu_data_out : 8'bz; // this synthesizes as
> > tristate buffers
>
> I saw this trick elsewhere and adopted it, it seems silly tho'.
>
> The thing is I only have/want one bus for both addresses and data.

... for example no real chip in this universe connects a bi-dir IO direct into
the chip's internal logic i.e direct to the metal layer traces (quite apart
from the fact that the internals of most chips run at a much lower voltage than
the IOs the noise injection would be horrendous).

They all use something like this:


enable -------------------------
|
|
IOout --------->------ | Tri stateable buffer | -->----

\

\

|----<>----- [Chip pad] IOsignal

/
IOin------<------------ | Input buffer |------<-------- /

And so now the Verilog standard IO template:

output IOsignal;
assign IOsignal = enable ? IOout : 'bz;
wire IOin = IOsignal;

Is no longer "silly" or a "trick" but is describing h/w that exists out there
in the real world aka its synthesisable.

Of course out in the real world the description doesn't go far enough since
further specs are need for buffer drive strength, IO voltage standards,
hysteresis, voltage tolerance, etc etc.

Of course you can always re-mux once the signals are inside the chip, and then
watch the speed fall away to nothing.

Jeffrey Turner

unread,
May 26, 2002, 1:15:39 PM5/26/02
to
Rick Filipkiewicz wrote:

I was describing the internals of a chip. For example, the Instruction
cache:

module Icache(clock, Ibus);
inout [31:0] Ibus;
input clock;
reg [40:0] cache [511:0];
reg [31:0] addr_in;
reg [31:0] instr_out;
wire have_valid_instr;

// My thinking goes like this:
// always @(posedge clock)
// addr_in <= Ibus;
// Then internal logic which searches the cache...
// always @(negedge clock)
// assign Ibus = have_valid_instr ? instr_out : 32'bz;

endmodule

Of course that doesn't compile - but it IS a real world example.

--Jeffrey Turner

Rick Filipkiewicz

unread,
May 26, 2002, 7:34:56 PM5/26/02
to

Jeffrey Turner wrote:

>
>
> I was describing the internals of a chip. For example, the Instruction
> cache:
>
> module Icache(clock, Ibus);
> inout [31:0] Ibus;
> input clock;
> reg [40:0] cache [511:0];
> reg [31:0] addr_in;
> reg [31:0] instr_out;
> wire have_valid_instr;
>
> // My thinking goes like this:
> // always @(posedge clock)
> // addr_in <= Ibus;
> // Then internal logic which searches the cache...
> // always @(negedge clock)
> // assign Ibus = have_valid_instr ? instr_out : 32'bz;
>
> endmodule
>
> Of course that doesn't compile - but it IS a real world example.
>
> --Jeffrey Turner

O.k. consider this:

o To be sampled on the positive edge of the clock the address has to become valid
sometime during the low phase of the clock.

o If there is a valid instruction then its driven onto Ibus by the negative edge of
the clock => the instruction read from the cache is valid in the low phase of the
clock.

=> both addresses and cache hit data are valid at the same time on the same bus,
which I would contend is not real world ... *unless* you arrange for addresses to be
valid in the low phase of every alternate clock and use the high phase of the clock
for bus turn around between the address drivers and cache read data drivers.

an you are still faced with writing data on cache refills. Probably best to do these
in the high clock phase following an address ...

The result being that with a tristate bus you can only do one cache access every 2
clocks whereas if the address/writedata/readdata busses are demux'ed you can do one
every clock. The actual degradation in overall CPU performance will depend on the
cache miss rate but I'd guess at a 30-40% loss.

If you're not yet concerned about synthesis why go to the complexity of a tri-state
bus esp. when it impacts so severely on the critical I-cache path ?

Why, also, make life difficult using both edges of a clock instead of using a x2 (or
x3, x4 etc) clock and keeping to the synchronous paradigm ?


Marco Fioretti

unread,
May 27, 2002, 6:51:17 AM5/27/02
to
Jeffrey Turner wrote:

>
> What do you mean not verbose? You declare the ports in the port list
> then declare them again as input, outpur or inout and if they're output
> you declare them a third time as reg. If that isn't redundancy...
>

You are right, but I was referring mostly to the body (often the biggest
part)
of the code. Signals declarations inside processes, longer "posedge"
statements,
etc.. Not to mention the need to declare the portlists of all the
components,
libraries...

Marco Fioretti

Rick Filipkiewicz

unread,
May 27, 2002, 2:45:50 PM5/27/02
to

Marco Fioretti wrote:

If you're using emacs with verilog-mode then large chunks of this are taken
care of by the `AUTO' macros e.g.

AUTOARG: to construct port lists.

AUTOINST: to construct instantiations of modules.

AUTOWIRE: To add wire definitions for module output ports.

AUTOSENSE: To automatically contruct a sensitivity list for a combinatorial
always block

etc. etc.


Petter Gustad

unread,
May 27, 2002, 6:06:28 PM5/27/02
to
Jeffrey Turner <jtu...@localnet.com> writes:

> What do you mean not verbose? You declare the ports in the port list
> then declare them again as input, outpur or inout and if they're output
> you declare them a third time as reg. If that isn't redundancy...

You don't declare all outputs as regs.

Petter
--
________________________________________________________________________
Petter Gustad 8'h2B | (~8'h2B) - Hamlet in Verilog http://gustad.com

Marco Fioretti

unread,
May 28, 2002, 4:43:21 AM5/28/02
to
Rick Filipkiewicz wrote:

>
> If you're using emacs with verilog-mode then large chunks of this are taken
> care of by the `AUTO' macros e.g.
>

Of course, and there is probably something similar for VHDL too. The
verbosity problem
remains, however, when you have to *read* and surf the code.

Ciao,
Marco

Jeffrey Turner

unread,
Jun 4, 2002, 8:49:09 PM6/4/02
to
Rick Filipkiewicz <ri...@algor.co.uk> wrote in message news:<3CF17120...@algor.co.uk>...

> Jeffrey Turner wrote:
>
> >
> >
> > I was describing the internals of a chip. For example, the Instruction
> > cache:
> >
> > module Icache(clock, Ibus);
> > inout [31:0] Ibus;
> > input clock;
> > reg [40:0] cache [511:0];
> > reg [31:0] addr_in;
> > reg [31:0] instr_out;
> > wire have_valid_instr;
> >
> > // My thinking goes like this:
> > // always @(posedge clock)
> > // addr_in <= Ibus;
> > // Then internal logic which searches the cache...
> > // always @(negedge clock)
> > // assign Ibus = have_valid_instr ? instr_out : 32'bz;
> >
> > endmodule
> >
> > Of course that doesn't compile - but it IS a real world example.
> >
> > --Jeffrey Turner
>
> O.k. consider this:
>
> o To be sampled on the positive edge of the clock the address has to become valid
> sometime during the low phase of the clock.

Yes, the valid address has to be ready by the set-up time before the clock
edge.

> o If there is a valid instruction then its driven onto Ibus by the negative edge of
> the clock => the instruction read from the cache is valid in the low phase of the
> clock.

True, but it need only be asserted long enough to be read by the
instruction decode logic, and/or read into an instruction register.

> => both addresses and cache hit data are valid at the same time on the same bus,
> which I would contend is not real world ... *unless* you arrange for addresses to be
> valid in the low phase of every alternate clock and use the high phase of the clock
> for bus turn around between the address drivers and cache read data drivers.

No, because you do not necessarily have to dedicate the entire
half cycle to one or the other.

> an you are still faced with writing data on cache refills. Probably best to do these
> in the high clock phase following an address ...
>
> The result being that with a tristate bus you can only do one cache access every 2
> clocks whereas if the address/writedata/readdata busses are demux'ed you can do one
> every clock. The actual degradation in overall CPU performance will depend on the
> cache miss rate but I'd guess at a 30-40% loss.

At the outrageous cost of having two buses.

> If you're not yet concerned about synthesis why go to the complexity of a tri-state
> bus esp. when it impacts so severely on the critical I-cache path ?

I hadn't required a tri-state bus. I merely needed a bus which is
bi-directional. That is what inout seems to imply, but looks are
_apparently_ deceiving.

> Why, also, make life difficult using both edges of a clock instead of using a x2 (or
> x3, x4 etc) clock and keeping to the synchronous paradigm ?

Because, it's easier and cheaper in real estate and logic to only
have one bus running around the chip.

--Jeffrey Turner
Luna-Tech Systems

Jeffrey Turner

unread,
Jun 4, 2002, 8:59:14 PM6/4/02
to
"Tom Nielson" <tnie...@rcn.com> wrote in message news:<ackssc$skf$1...@bob.news.rcn.net>...

> I'll tell you what's silly and verbose:
>
> process (clk)
> begin
> if clk'event and clk = '1' then
> signal1 <= signal2;
> end if;
> end
> end process;

This is verilog. You've just substituted process for always.
if (prising clk) is simple VHDL. And there's no confusing

signal1 <= signal2;

vs.

signal1 = signal2;

If you're simply commenting that VHDL expects end process; vs. end
then you're nitpicking.

--Jeff Turner

Marco Fioretti

unread,
Jun 5, 2002, 3:20:25 AM6/5/02
to
Jeffrey Turner wrote:
> > process (clk)
> > begin
> > if clk'event and clk = '1' then
> > signal1 <= signal2;
> > end if;
> > end
> > end process;
>
> This is verilog. You've just substituted process for always.
> if (prising clk) is simple VHDL. And there's no confusing
>
> signal1 <= signal2;
>
> vs.
>
> signal1 = signal2;
>


Tom is right. In verilog the code above is simply:

always @(posedge clk)
signal1 <= signal2;

much less than what written above.

About non blocking assigment (<=) being confused with blocking
assignment:

my understanding is that the non blocking assignment simply eliminates
the
needs for all those signals for temporary calculations local to a VHDL
process
which make the process code itself 2/three times longer ( = more
difficult
to understand/maintain). Once you have got the difference between the
two operators
you write much less to get the same function.

Ciao,
Marco

0 new messages