4

I've been working on a VHDL project for a few weeks, and functionnality-wise everything's going very smoothly. I can simulate and program my DE0-nano FPGA devellopement board to check if what I'm doing is working, and it is. However, I'm starting to worry about the readability of the source code as the project is rapidly expanding.

As far as my experience is concerned, I'm a university student in electronical engineering and have followed many courses on electronics, but I'm a complete noob concerning VHDL. (Although I could say my knowledge of VHDL has grown immensely during these past few weeks)

THE QUESTION :

My problem is that I have several components whose ports I'd like to map individually into DIFFERENT high-level entities. Say you've got an adder.vhd, well I'd like to provide operand A from operandA.vhd and operand B from operandB.vhd, meaning that I'd like to map port A of adder.vhd into operandA.vhd, and port B of adder.vhd into operandB.vhd.

The solution I'm currently using is that I map my signals following the hierarchical order of my entities, and if operandB.vhd is buried at another level entirely than operandA.vhd, I map the signals all the way through to the highest level entity that is required, then back down into the adder.vhd, in a single port map specifying ports A and B at the same time as I believe is required.

However, I find this solution very messy as it accumulates signals in my high-level entities that are only there for routing purposes. What's more, to continue on the adder.vhd analogy, I'd like several entities to provide operandsA or B (at different times, I'm not going to drive different values on the same input ports) so applying the current solution means I'll have numerous near-duplicate assignements too.

Is there another solution ? I couldn't find any documentation on this, and I fear this is a hard constraint of the language, but I may not know quack as I'm just starting VHDL.

This may also be a design error on my side, as I'm more accustomed to actual electronic design than VHDL circuit description. Connecting a component's ports to a bunch of other different components is very natural, but may not be how VHDL works.

EXPLICATIVE BLOCK DIAGRAMS :

What I'm currently doing : https://i.stack.imgur.com/CJVjg.gif enter image description here

What I want to do : https://i.stack.imgur.com/hrNwF.gif enter image description here

EXAMPLE CODE :

--  ********************************************
--
--  TOP-LEVEL ENTITY, in a file topLevel.vhd

entity topLevel is
    port
    (
    -- Any ports, not useful for the problem at hand
    );
end entity topLevel ;

architecture topLevel_Architecture of topLevel is

    --  HERE :  I have to accumulate signals just to get my data from the two subEntityA & B to computeFromAB.
    --
    --          I can't just map subEntityA and subEntityB as low-level entites into computeFromAB, as they provide data
    --          that I need elsewhere in the circuit. Well, I could do that but then I'd still have to get the "otherSignalFromX"
    --          through the same method.
    --          
    --          I'd rather directly map SEPARATELY (if that's possible)
    --              - operandA & operandB into computeFromAB
    --              - otherSignalFromA & otherSignalFromB into topLevel

    --  The signals I use to get my data from subEntityA and subEntityB to computeFromAB
    SIGNAL operandA : std_logic_vector(7 downto 0)  := ( others => '0' ) ;
    SIGNAL operandB : std_logic_vector(7 downto 0)  := ( others => '0' ) ;

    -- Other signals that I do not need to get to computeFromAB
    SIGNAL otherSignalFromA : std_logic ;
    SIGNAL otherSignalFromB : std_logic ;

begin

-- PORT MAP : subEntityA.vhd
    subEntityA : entity work.subEntityA
    PORT MAP(
    -- The first signal I'd like to get through to computeFromAB
    operandA => operandA,
    -- Other signals
    otherSignalFromA => otherSignalFromA
    );

-- PORT MAP : subEntityB.vhd
    subEntityB : entity work.subEntityB
    PORT MAP(
    -- The second signal I'd like to get through to computeFromAB
    operandB => operandB,
    -- Other signals
    otherSignalFromB => otherSignalFromB
    );

-- PORT MAP : computeFromAB.vhd
    computeFromAB : entity work.computeFromAB
    PORT MAP(
    -- The "useful" signals
    operandA => operandA,
    operandB => operandB
    );


-- PROCESSES, ETC, OF TOPLEVEL ENTITY

end topLevel_Architecture ;



--  ********************************************
--
--  OPERAND A ENTITY, in a file subEntityA.vhd

entity subEntityA is
    port
    (
    -- The first signal I'd like to get through to computeFromAB
    operandA : OUT std_logic_vector(7 downto 0)
    -- Other signals
    otherSignalFromA : OUT std_logic ;
    );
end entity subEntityA ;

-- ARCHITECTURE, PROCESSES OF subEntityA



--  ********************************************
--
--  OPERAND B ENTITY, in a file subEntityB.vhd

entity subEntityB is
    port
    (
    -- The second signal I'd like to get through to computeFromAB
    operandB : OUT std_logic_vector(7 downto 0)
    -- Other signals
    otherSignalFromB : OUT std_logic ;
    );
end entity subEntityB ;

-- ARCHITECTURE, PROCESSES OF subEntityB


--  ********************************************
--
--  COMPUTATION FROM OPERANDS A & B ENTITY, in a file computationFromAB.vhd

entity computeFromAB is
    port
    (
    operandA : IN std_logic_vector(7 downto 0) ;
    operandB : IN std_logic_vector(7 downto 0)
    );

--  ARCHITECTURE, PROCESSES OF computeFromAB

Thanks for reading, and thanks for any input you may provide.

EDIT 1 : Thanks for removing the "dictionary" tag, no idea why it was there.

EDIT 2 : added some example code, though I'm not sure if it's any help

EDIT 3 : added illustrative block diagrams

  • 1
    Some VHDL code would say more than 1000 words ;-) Can you add some code to exemplify the issues ? – Morten Zilmer Mar 13 '16 at 18:10
  • This will take some time, as I think sending my complete VHDL project is just gonna waste people's time. I'll try and select the useful parts. – ElectronicBadger Mar 13 '16 at 18:43
  • Done. Hope this helps. – ElectronicBadger Mar 13 '16 at 19:10
  • Added block diagrams describing the problem ! – ElectronicBadger Mar 13 '16 at 20:05
  • The first block diagram does not illustrate the problem very well. You should show the connections through the hierarchy levels instead. The second block diagram looks like the solution for me. Instantiating a lot of components beside each other is a typical approach. Of course, such a solution may complicate verification of the design. – Martin Zabel Mar 14 '16 at 08:39

2 Answers2

1

Why don't you just wrap entities A + B + computeFromAb together creating entityAB. Then route otherSignalA and otherSignalB through the toplevel into entityC. The idea would be to cratea neat submodules to wrap and hide other modules. This also helps if and when you need to replicate some of the logic later on.

It might be that the signaling and design becomes a bit complex but that's usually a sure sign of the original idea being too complex. So whenever you are feeling confused with your own code then that's the time to go back to pen and paper and rething what you are actually trying to accomplish ;)

Also at some point you are not sure anymore where some signal is coming and where should it be going. That's the time you curse your signal naming conventions - if you had any - and come up with something more reasonable.

Add 100 more modules to your top level entity and you start to understand how the top level integrators feel in projects and why some of them have serious mental problems.

jarno
  • 137
  • 1
  • 10
  • Thanks for taking the time to answer. That's what I'm currently doing in the actual, more complex design I'm working on. I already have about 10 modules organized hierarchically that work exactly like you explained. My problem with this solution is that I'll have a subset of signals (here, the signals from A and B going to C) routed through entityAB and any other intermediary higher-level entity that are not really useful to AB, but rather only to A and B. Add several levels of hierarchy and you add more signals that are just there for routing purposes at every intermediate level. – ElectronicBadger Mar 14 '16 at 19:58
  • After reading much more material on VHDL, apparently the commonly used solution is to NOT USE a hierarchical design, and rather have a top-level entity that maps EVERY component of your circuit, so that you may connect your components in a "horizontal fashion" much more freely. I concieved my project as a hierarchy of modules and submodules, but I'd very much like to have lateral connections that actually ignore this hierarchy. On an actual integrated circuit, that's just connecting two wires. In VHDL, designing hierarchically and lateral connections apparently don't get along well. – ElectronicBadger Mar 14 '16 at 20:06
  • I would like to see the source for being against hierarchial design. Even with a moderate design you would end up with thousands of signals and port maps in one top level VHDL file. You would actually start having trouble with your emacs (or whatever is your text editor of choice). So I still vote strongly for creating logically meaningful smaller entities, simulating them separately for all corner cases and then combining them at top level followed by top level verification simulations. – jarno Mar 15 '16 at 07:30
  • p.s. I know signal routing can be a pain, but that's how it goes in VHDL. You have to remember that these languages come from 1980's so it's actually unbelieveble that they still even exist ;) In SW side there are GUIs and objects and all sorts of fancy script languages. But we are still banging ifs and elses with ASCII emacs. But that's out of the scope of this problem. Just had to be said. – jarno Mar 15 '16 at 07:30
  • p.p.s. one trick to ease the RTL code congestion could maybe be using std_logic_vectors or even records to tie together bunch of signals so that you only write line or two on the top level. But again, maybe the the problem lies on the system design level? Sorry for spamming! – jarno Mar 15 '16 at 07:30
  • Hey, thanks for the long answer, I don't mind the "spamming" at all. Problem IS with my design. I designed my different circuits as objects that were meant to interact with several other objects, while the "port map" in VHDL only works if a given subentity is ENTIRELY comprised in a higher-level entity. The object-oriented design seemed appropriate to me, as I had a good notion of how actual IC work, meaning a bunch of components on a board that you connect however you like. – ElectronicBadger Mar 15 '16 at 17:58
  • Now the constraint that a subentity can only communicate with its direct superior led me to the idea that I could "sacrifice" and clog up my top entity with ALL the signals that need to go between functional blocks, to keep my functional blocks as clean as possible. Of course, I'll move entities to sub-entities if I can define boundaries that their signals will never need to cross, but I haven't been able to do that yet. (of course, this is the start of the project so I'm writing the parts that have to communicate the most widely) – ElectronicBadger Mar 15 '16 at 18:03
  • To return to the original question however, I could reformulate this as "my object-oriented design requires me to communicate between any and all objects, can I do that and still keep the hierarchical description using port maps ?", the answer still apparently being to this point "no, not without clogging every step of the hierarchical ladder with a bunch of additionnals signals that don't have much to do with the highest levels" But hey, I'm still very new to VHDL so I don't even know what I'm doing. – ElectronicBadger Mar 15 '16 at 18:09
1

Your problem is one of organization, and not thinking about this as simply an interconnect of rather simple elements. As such, your latter block diagram is what you are actually doing in your code, not the former.

Here is what you should do: Put each submodule entity/architecture pair in its own file. Compile it into library work. Then in your toplevel code wire it up simply, like so:

U0 : entity work.subEntityA 
   PORT MAP(operandA         => operandA, 
            otherSignalFromA => otherSignalFromA);

U1 : entity work.subEntityB
   PORT MAP(operandB         => operandB, 
            otherSignalFromB => otherSignalFromB);

U2 : entity work.computeFromAB
   PORT MAP(operandA => operandA, 
            operandB => operandB);

U3 : entity work.C
   PORT MAP(otherSignalFromA => otherSignalFromA, 
            otherSignalFromB => otherSignalFromB );

You used the construct "entity work.module_name" in your example code, and that is good practice. Let the default binding do its job and AVOID configuration files.

As your code grows, you end up putting all 4 of these into one entity/arch pair (making another level of hierarchy) and continuing. I recommend your toplevel be wiring only. Leave the logic to the submodules.

Yes, its gets more complicated as your portlists and generic lists grow, but that is what hierarchy is for, to help you organize it.

Bob
  • 44
  • 4