Multidimensional Register in Modul Port List

Some of my modules implements a register bank controlled by CPU lines. Inside the module I use register banks, like reg [7:0] dac_sel[0:7];

However if I put these multidimensional register in the module port list, both CVER and IVERILOG complain. I can work around by concatenating the register bank into one long vector and write the vector in the module port list. Being able to exporting register bank would be nice.

Is this a shortcoming of the simulators or of the Verilog standard or ask I for something impossible?

Thanks

--
Uwe Bonnes                bon@elektron.ikp.physik.tu-darmstadt.de

Institut fuer Kernphysik  Schlossgartenstrasse 9  64289 Darmstadt
--------- Tel. 06151 162516 -------- Fax. 06151 164321 ----------
Reply to
Uwe Bonnes
Loading thread data ...

I'ts a feature of Verilog-2001: you cannot pass a memory (array of vectors) through a port. As you correctly say, the workaround is to make a suitable larger vector, and then split it into pieces within and outside the module.

SystemVerilog fixes this, allowing pretty much any physically realisable data type on a port. Synthesis support is not universal, though :-(

--
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@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.
Reply to
Jonathan Bromley

I can't answer the verilog question, but I can commiserate about the general problem of where to put cpu io registers/decoders that cover multiple modules.

If I put them all in one module, register assignments are simple but wiring and changes are messy. If I distribute them, duplicate assignments are possible.

For now, I prefer to distribute a logical bus to all the modules with the following fields.

address, writeData, write_stb, readData, read_stb

I infer registers and decoders in the module that uses them, and keep track of address and bit allocations using global constants.

-- Mike Treseler

Reply to
Mike Treseler

can I join in please? :-)

Which, interestingly, means that you are specifying your own bus protocol - albeit a (quite properly) very simple one - specialised to the needs of device registers.

Indeed. But how, pray, do you multiplex the various readback data values? Do you like to imply tri-state drivers, and hope that your synthesis tools will map the tri-states (across many instances) to muxes? Or do you, as I generally do, take care to ensure that all the data outputs are held to zero whenever they are not being read, and then OR them all together somehow? On one recent project I got so fed up with this problem that I arranged for each readable register to have both input and output ports for read-data:

... if (someone is trying to read from me) then my_register_read_data

Reply to
Jonathan Bromley

Me too...:-)

For readback, how about muxing (a case statement on the address) within each module that registers appear in, but include the 'Bromley zero' on the way out of the module so that you can 'or' all the module outputs together at the 'top level'. That way you get to utilise the purpose built muxes that come 'for free' in the CLBs, but keep the simplicity of the 'or' gate at the 'top level'. (BTW, I would hope that a good synthesis tool would build the 'or' with a carry chain.) Or maybe that's what you're suggesting. Cheers, Syms.

Reply to
Symon

Yes.

A big mux on the CPU interface. Only the module interface looks clean.

No. Readable code has priority over LUTs for me.

Great idea. Thanks. Andy has posted here about mutual exclusion and I could never quite follow it. Maybe this is what he was on about.

I'll give that a try. Thanks.

-- Mike Treseler

Reply to
Mike Treseler
[On multiplexing the readback values from numerous addressable registers, without the HDL code becoming a dog's dinner]

Mike's and Symon's responses got me thinking some more (a rare occurrence these days) and I came up with a couple of ideas that are probably well-known to half the population of comp.arch.fpga but are new to me.

Idea 1: Wide, extensible readback mux. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ I am pretty sure that, for FPGA architectures at least, it's more efficient to do a wide OR than a wide MUX. In other words, as I suggested earlier, make sure that all deselected registers jam their data outputs to zero, and then OR together all the data outputs. Here's a rather neat solution to the wide OR gate - much nicer than the ripple thing I suggested earlier. It depends on the use of an unconstrained array port of record types, so you'll need to check it works with your chosen synthesis tool.

-- Step 1: Package to define some types and constants. -- We define a record "T_gated_databus" to reflect the -- readback data coming out of a register. The "data" -- element is, of course, the data; "enable" is a single- -- bit enable signal that's asserted when the register -- is addressed. -- library ieee; use ieee.std_logic_1164.all; package P_databus is -- constant databus_width : positive := 32; subtype T_databus is std_logic_vector(databus_width-1 downto 0); -- type T_gated_databus is record enable : std_logic; data : T_databus; end record; constant unused_databus: T_gated_databus := ( enable => '0' , data => (others => '0') ); -- type A_gated_databus is array(natural range ) of T_gated_databus; end;

-- Step 2: Make an arbitrarily wide OR structure using -- an unconstrained array input port. Feed it as many -- T_gated_databus records as you have registers. -- At most one of those will have its enable asserted -- at any given time. The output y.enable is asserted -- when one of the input enables is asserted. -- library ieee; use ieee.std_logic_1164.all; use work.P_databus.all; entity radialmux is port ( d: in A_gated_databus ; y: out T_gated_databus ); end; architecture RTL of radialmux is begin process (d) variable vy: T_gated_databus; begin vy := unused_databus; for i in d'range loop if d(i).enable = '1' then vy.enable := '1'; vy.data := vy.data or d(i).data; end if; y regA_output , d(2) => regB_output , y => CPU_readback );

Addresses are applied once only, as generics on the instances of register-containing entities. If you add another register-containing entity, you simply add another signal to the top level architecture and bolt it in to the port map of Readback_Mux, which then grows wider to suit the extended port map. You don't even need the numbering to be contiguous: I tried this...

Readback_Mux: entity work.radialmux port map ( d(0 to 45) => (others => unused_databus) , d(46) => regA_output , d(47 to 62) => (others => unused_databus) , d(63) => regB_output , y => CPU_readback );

So you can make the port subscripts match-up with your register addresses, if it makes you feel better. Because "unused_databus" is an all-zero constant, synthesis optimises away the zero inputs.

Your mileage may vary, but I think this shows promise. The synth tool I tried made a really excellent job of this, using a tree of LUTs in the obvious optimal way. It didn't, though, use carry chains - sorry Symon!

--
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@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.
Reply to
Jonathan Bromley

Hi Jonathan, It might need a little 'massage' to get it to use the chains. The chain method can detect a single '0' on its inputs. (In normal use the chain detects all ones meaning carry...) So, we need a bunch of 4 input, i.e. LUT sized, NOR gates to feed the chain. If any input to the OR gates is high, the output of that or gate goes low, and thus the output of the chain can go high (or low depending on what constant is on the di inputs of the MUXCYs). Maybe the synthesis tool needs the thing to be coded with these NOR gates in mind to use the chains? I just instantiate them, but there you go... Anyway, interesting stuff, and very timely for my project! Ta very much! Cheers, Syms.

Reply to
Symon

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.