From: Michael Meeuwisse on
Hi,

I'm working on a little UART to get more familiar with verilog, and
right now I have the following input:

parameter width = 32; /* Must be multiple of 8 */
input [width - 1: 0] iData;

/* number of characters to send for each piece of data - 1 */
parameter chars = width / 8 - 1;

The iData first goes in a fifo for buffering and is then read back in as
oData:

wire [width - 1: 0] oData;

Since this is an UART I want to send (always, regardless of width) 8
bits at a time, so I wrote down:

reg [7: 0] xData [chars: 0];

And then try to assign oData to this:

xData <= oData;

I hope a few are now crying "You can't do that!" because that would mean
you'd know how to do this instead. Xilinx webpack gives me on that line;

Illegal left hand side of nonblocking assignment

The error is general enough for google to not find anything relevant
afaik. I don't want to do something like:

{xData[0], xData[1], ..} = oData;

Because I don't know how wide oData will be at this point. I also really
don't want to rewrite the fifo to support an other output width than
what it's input is. Even if I had to rewrite it, I'll end up with the
same problem as above at some point.

Hints & Tips are very welcome.

Thanks,

Michael
www.projectvga.org
From: Jonathan Bromley on
On Fri, 11 Apr 2008 10:44:12 +0100, Michael Meeuwisse
<mickeymeeuw(a)g_something> wrote:

>parameter width = 32; /* Must be multiple of 8 */
>input [width - 1: 0] iData;
>
>/* number of characters to send for each piece of data - 1 */
>parameter chars = width / 8 - 1;
>
>The iData first goes in a fifo for buffering and is then read back in as
>oData:
>
>wire [width - 1: 0] oData;
>
>Since this is an UART I want to send (always, regardless of width) 8
>bits at a time, so I wrote down:
>
>reg [7: 0] xData [chars: 0];
>
>And then try to assign oData to this:
>
>xData <= oData;

Yup, you can't do that! xData is a "memory" in Verilog-speak,
an array of (chars+1) distinct 8-bit variables; you can't
assign a single vector to that, any more than you could assign
an integer to a complete array in C.

The direct (but, in practice, wrong) answer is:

integer i;
...
for (i=0; i<=chars; i=i+1)
xData[i] <= oData[8*i +: 8];

The strange [a +: b] is an "indexed part select",
choosing the 8 bits of oData whose lowest-numbered
subscript is 8*i. You might expect to do...

xData[i] <= oData[8*i + 7: 8*i];

but you're not allowed to do that, because a part-select
can't have variable bounds.

However, there is probably a better way.

Copy "oData" into a wide register:

reg [width-1 : 0] byteShifter;
...
byteShifter <= oData;

and then allow it to shift down 8 bits at a time
as you pull bytes out of it:

reg [7:0] txByte;
...
// send one byte
txByte <= byteShifter[7:0];
byteShifter <= byteShifter >> 8;

The shift operation obviously puts the *next* 8 bits
of "byteShifter" into the right place for the next
txByte<=byteShifter[7:0] copy.

Armed with this idea you'll probably come up with
something a bit simpler. For example, you may
prefer to do this byte-shifting at the input end
of your FIFO, so that the FIFO is invariably
byte-wide - that would be my preference.

Generally, if you want sequential access to the
pieces of a big vector, it is much cheaper (in hardware)
to shift them into place rather than selecting them
from their original position.
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.bromley(a)MYCOMPANY.com
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
From: Michael Meeuwisse on

Jonathan Bromley wrote:
> Yup, you can't do that! xData is a "memory" in Verilog-speak,
> an array of (chars+1) distinct 8-bit variables; you can't
> assign a single vector to that, any more than you could assign
> an integer to a complete array in C.

I figured it was something like that. But since it'd translate to
hardware at some point I hoped the compiler was intelligent enough to
understand this "re-definition".

> The direct (but, in practice, wrong) answer is:
>
> integer i;
> ...
> for (i=0; i<=chars; i=i+1)
> xData[i] <= oData[8*i +: 8];
>
> The strange [a +: b] is an "indexed part select",
> choosing the 8 bits of oData whose lowest-numbered
> subscript is 8*i. You might expect to do...
>
> xData[i] <= oData[8*i + 7: 8*i];
>

Ok.. but why is this a wrong answer?

> However, there is probably a better way.
> ...
> // send one byte
> txByte <= byteShifter[7:0];
> byteShifter <= byteShifter >> 8;
>

That all makes sense. I think I can pull this off without changing too
much. I was already doing something similar for transmitting the actual
bits anyway. :)

> Armed with this idea you'll probably come up with
> something a bit simpler. For example, you may
> prefer to do this byte-shifting at the input end
> of your FIFO, so that the FIFO is invariably
> byte-wide - that would be my preference.
>

It would simplify the UART somewhat, but then I'd have to shift a number
of bytes into the fifo in one clock cycle. I'll stick to what I have for
now.

> Generally, if you want sequential access to the
> pieces of a big vector, it is much cheaper (in hardware)
> to shift them into place rather than selecting them
> from their original position.

Odd. I thought a wire from the original register would be cheaper than
logic to get the bits in place.

Thanks,

Michael
www.projectvga.org
From: Jonathan Bromley on
On Fri, 11 Apr 2008 11:43:06 +0100, Michael Meeuwisse wrote:

>> The direct (but, in practice, wrong) answer is:
>>
>> integer i;
>> ...
>> for (i=0; i<=chars; i=i+1)
>> xData[i] <= oData[8*i +: 8];
>>
>> The strange [a +: b] is an "indexed part select",
>> choosing the 8 bits of oData whose lowest-numbered
>> subscript is 8*i. You might expect to do...
>>
>> xData[i] <= oData[8*i + 7: 8*i];

>Ok.. but why is this a wrong answer?

uh, which answer? oData[8*i+7:8*i] is illegal because
it's a part select with variable bounds; in Verilog
all expressions must have a statically-determined bit
width, and although you and I can do the algebra and
see that the slice is evidently 8 bits wide, it's safer
for the language to outlaw that sort of thing. The
indexed part-select oData[8*i+:8] is legal, at least in
Verilog-2001, but creates a big multiplexer to choose
the bits - hence my comment later about using a shifter
instead.

>> Generally, if you want sequential access to the
>> pieces of a big vector, it is much cheaper (in hardware)
>> to shift them into place rather than selecting them
>> from their original position.
>
>Odd. I thought a wire from the original register would be cheaper than
>logic to get the bits in place.

Don't take my word for it - try synthesising both versions and
see what the tool shows you. For a word of only 2 or 4 bytes
the difference is likely to be marginal.
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.bromley(a)MYCOMPANY.com
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
From: Michael Meeuwisse on

Jonathan Bromley wrote:
> On Fri, 11 Apr 2008 11:43:06 +0100, Michael Meeuwisse wrote:
>>Ok.. but why is this a wrong answer?
>
> uh, which answer?

I meant the for loop. If the compiler unrolls it I don't see how this
could be a wrong. Maybe size.

>>Odd. I thought a wire from the original register would be cheaper than
>>logic to get the bits in place.
>
>
> Don't take my word for it - try synthesising both versions and
> see what the tool shows you. For a word of only 2 or 4 bytes
> the difference is likely to be marginal.

I'll give it a try soon. The solution of using a shift turned out to be
1 extra line and about 4 minor changes, so I'm currently working out the
bugs which showed up in the simulation. :)

Thanks again,

Michael
www.projectvga.org