Re: [myhdl-list] MEP - keep hierarchy in conversion
Brought to you by:
jandecaluwe
From: Per K. <bas...@gm...> - 2013-10-01 09:30:26
|
Hi! I haven't tried your patch out (we're still at 0.7 plus some patches), but I'd just like to offer some encouragement! What you are proposing would be very useful, I think! /Per On Sun, Sep 29, 2013 at 8:21 PM, David Holl <da...@ad...> wrote: > There was an old thread regarding MEP 110, but I've come up with an > alternative "solution", and I'm looking for your comments. (call it MEP > 110-alt?) > > tl;dr --- If you're interested, > > Introduction: Same as MEP 110. (Especially for floor planning...) > ----------------------- > Analysis: Same as MEP 110. (Yep, everything gets flattened by default...) > ----------------------- > Proposed Solution: (with implementation) > > I did not follow the proposed solution in MEP 110, because that would've > required that I change [any of] my components to be "top-module > convertible". (I'm using a form of signal containers --similar to MEP > 107-- which which would've required many changes (in my code) to achieve > "top-module convertibility".) > > What I did was I started from the flattened hierarchy in > conversion/_toVerilog.py, but instead of calling the usual > _writeSigDecls, _convertGens, I wrote my own convoluted output code: > ... > if self.partitioned_output: > _write_partitioned_output(self.partitioned_output, vfile, > vpath, self.timescale, h, intf, siglist, memlist, genlist, doc) > else: > _writeFileHeader(vfile, vpath, self.timescale) > _writeModuleHeader(vfile, intf, doc) > _writeSigDecls(vfile, intf, siglist, memlist) > _convertGens(genlist, vfile) > _writeModuleFooter(vfile) > ... > > > To activate this alternative output, just > set toVerilog.partitioned_output=True: > toVerilog.name='test_partition' > toVerilog.partitioned_output=True # the default is False > toVerilog(_test_top, clk, AAA, BBB, ZZZ, TTT, VVV) > > Without any other changes to a hardware description, this alternative code > will produce identical, flattened output. (right down to the arbitrary > ordering of signals and generators...) > > However, you may now group any related logic together, as needed. I call > a group of logic a "partition", and these partitions may be nested. > Instead of the word "partition" you could call it a "module" instead, > since the concept is almost identical to Verilog module's. In the > following description, it will appear that I'm flipping between "partition" > and "module" when really, I'm describing how that partitions in python > impact the created Verilog modules. (but for simplistic purposes, since I > guarantee each "partition" will create a unique Verilog "module", feel free > to call em' what you want...) > > There are 2 ways to assign related hardware into partitions. > ----------------------- > 1) The first is via python's "with" statement. I'll show a few examples: > > example 1.a) A simple partition... > from myhdl import Signal, partition, ... > > @always(clk.posedge) > def clgc(): > c.next = a + b > > with partition('A'): > @always(clk.posedge) > def clgd(): > d.next = c + e > > @always(clk.posedge) > def clge(): > e.next = a * b > > @always(clk.posedge) > def clgf(): > f.next = more stuff... > > > What "partition" does is annotate all generators (and shadow signals...) > with your text label. Then the "partitioned-output" code uses these > annotations move related logic into a Verilog module, and instantiate that > module from the top-level module. Module ports are automatically created > for any signals that need to cross between modules. > > This code still creates only 1 output .v file containing all modules. (I > didn't care if it was 1 file or multiple files, but for me, 1 file was > "easier" to move/copy around in my opinion.) > > The top module will include all of the signals, except for "e" --- because > in this code, e is only used within partition A. Therefore "e" will appear > as a driven "reg" within a submodule called A. (and that submodule "A" is > instantiated in the top level as "part_A"...) > > > > example 1.b) Partitions may be nested. > > @always(clk.posedge) > def clgc(): > c.next = a + b > > with partition('A'): > @always(clk.posedge) > def clgd(): > d.next = c + e > > with partition('B'): > @always(clk.posedge) > def clge(): > e.next = a * b > > @always(clk.posedge) > def clgf(): > f.next = more stuff... > > > This code will create 3 modules total: the top module, a module called > "A", and a module called "A_B". > > > example 1.c) Partitions having the same name will be renamed to stay > unique! > > If you want related code to be grouped into a partition, all of that code > must be contained in the same python "with" block. For example: > > from myhdl import Signal, partition, ... > > @always(clk.posedge) > def clgc(): > c.next = a + b > > with partition('A'): # This will be renamed to A0 > @always(clk.posedge) > def clgd(): > d.next = c + e > > with partition('A'): # This will be renamed to A1 > @always(clk.posedge) > def clge(): > e.next = a * b > > > Rationale: When you start nesting partitions, partition names are > guaranteed to produce unique module instances and not accidentally group > unrelated logic together. > > > example 1.d) Partitions are nestable across your python function calls, > and renaming will happen to keep sub > > For example, unrelated nested partitions may use the same name without > fear of their logic being accidentally grouped together. > > from myhdl import Signal, partition, ... > > def my_module_alice(...): > # ... > with partition('SM'): > # This happens to enclose a state machine. > # The name SM isn't descriptive enough, but if you > # want descriptive Verilog output, then you should > # use descriptive names. > # ... > # ... > return instances() > > def my_module_bob(...): > # ... > with partition('SM'):# This encloses an unrelated state machine. > # ... > # ... > return instances() > > def top(...): > @always(clk.posedge) > def clgc(): > c.next = a + b > > with partition('CRYPTO'): > alice_inst = alice(...) > bob0_inst = bob(...) > bob1_inst = bob(...) > > with partition('CRYPTO_SM2'): > # I made this CRYPTO_SM2 name, just to be a jerk. > @always(clk.posedge) > def clgd(): > d.next = c + e > > > This code would produce 6 instantiated modules in the generated Verilog > output: > module top(...); > module CRYPTO(...); > module CRYPTO_SM0(...); // this is from alice_inst > module CRYPTO_SM1(...); // this is from bob0_inst > module CRYPTO_SM2(...); // this is from bob1_inst > module CRYPTO_SM2_(...); // renamed CRYPTO_SM2 to not conflict with > CRYPT_SM2 from bob1_inst > > Admittedly, the generated names CRYPTO_SM... in this example aren't very > clear, but the point here is that your python functions (like alice() and > bob()) have a guaranteed means to group logic into a Verilog module without > accidental commingling of unrelated from other modules. > > The "top" module instantates "CRYPTO" and "CRYPTO_SM2_". Then "CRYPTO" > instantiates "CRYPTO_SM0", "CRYPTO_SM1", and "CRYPTO_SM2". > > > example 1.e) Partitions support Verilog 2001 attributes (and if someone > wants to add VHDL support...) > > with partition('A') as this_part: # This will be renamed to A0 > this_part.attr_add('KEEP_HIERARCHY', 'TRUE') > this_part.attr_add('DONT_TOUCH', 'TRUE') > > @always(clk.posedge) > def clgd(): > d.next = c + e > > This will produce output that instantiates module A as: > > (* KEEP_HIERARCHY="TRUE", DONT_TOUCH="TRUE" *) part_A A(clk, c, e, d); > > // The generated module for instance A is called "part_A". > > (MyHDL also has a nifty feature to include doc strings as embedded > comments. I have some back-end support for attaching a string to a > partition, to be output as a comment in the code, but I haven't turned it > on yet.) > > ----------------------- > 2) The second way to group logic into a partition is with a python > decorator. > > example 2) Using decorators in addition to "with" blocks. > > The decorator syntax uses the same rules as the with-blocks. (All > partitions will be unique, and possibly suffixed with a number to maintain > uniqueness in the Verilog code. Partitions may be nested. Use descriptive > names if you want descriptive output.) > > Here, I'll intermix the decorator and with syntax: > > def my_module_alice(...): > # ... > with partition('SM'): > # This happens to enclose a state machine. > # The name SM isn't descriptive enough, but if you > # want descriptive Verilog output, then you should > # use descriptive names. > # ... > # ... > return instances() > > @partition('AES') # <---- partition a la decorator. > def my_module_bob(...): > # ... > with partition('SM'):# This encloses an unrelated state machine. > # ... > # ... > return instances() > > def top(...): > @always(clk.posedge) > def clgc(): > c.next = a + b > > with partition('CRYPTO'): > alice_inst = alice(...) > bob0_inst = bob(...) > bob1_inst = bob(...) > > with partition('CRYPTO_SM2'): > # I made this CRYPTO_SM2 name, just to be a jerk. > @always(clk.posedge) > def clgd(): > d.next = c + e > > The above code will generate ~8 modules: > module top(...); > module CRYPTO(...); > module CRYPTO_SM(...); // this is from alice_inst > module CRYPTO_AES0(...); // decorator on bob() > module CRYPTO_AES0_SM(...); // this is from bob0_inst > module CRYPTO_AES1(...); // decorator on bob() > module CRYPTO_AES1_SM(...); // this is from bob1_inst > module CRYPTO_SM2(...); // renamed CRYPTO_SM2 to not conflict with > CRYPT.SM from bob1_inst > > > ----------------------- END OF EXAMPLES > > Limitations: I hope there aren't any. I put enough care to accomodate > ConcatSignal's, _SliceSignal's, const [undriven] _Signal's, etc... And if > a signal gets pushed into a sub-partition where it is both driven and read, > as well as output from that sub-partition, the generator will automatically > make a separate wire just for the output port, that is driven from your > signal. (This prevents "Output port is read internally..." warnings for > partition-generated modules. I don't do this for the top-level though, to > preserve the same interface as current MyHDL output.) > > Component Conversion: No additional restrictions beyond that of MyHDL. > There is still the same requirement on your top-level to be "top-level > convertible", but there is flexibility for your lower levels. > > Component Parameters: What parameters? All of your parameters were > already digested by python+MyHDL magic, and I'm operating on the flattened > hierarchy. If you invoke the same sub-partition (sub-module) multiple > times, it will be replicated in the output, but every time it appears, it > will use the globally-unique signal names that MyHDL has already assigned. > (ie, I don't change your signal names.) > > Any drawbacks: > This may/will produce larger output code than the proposed solution in MEP > 110. The existing MEP 110 solution will create 1 copy of each module, and > instantiate it multiple times (as long as each instantiation shares the > same port signal widths, etc...). In contrast, this "110.alt" solution > will create a whole copy of a module every time it is instantiated. (But > each copy inherits the unique signal names assigned by MyHDL's flattening > algorithm.) However, the larger output size from this "110.alt" isn't that > much larger than MyHDL's native flat output. (depending on your signal > usage...) > > Benefits: > You can have hierarchical output with minimal changes to your code, > and you control exactly how your logic is partitioned into the hierarchy. > Just sprinkle a few @partition(...) or "with partition(...):" statements > wherever you need in your design. > > Known pitfalls: I have not tried or tested TristateSignal's for "inout" > ports, and I've only tested on a very narrow subset of MyHDL's feature set. > (I was was already bitten by ConcatSignal's, _SliceSignal's, and lists of > signals accidentally being inferred as memories... However, I expect these > areas to work as expected now.) > > > But if anyone is interested, here's the code, and I'm open for feedback. > > I attached patches against myhdl-0.8.tar.gz available from > https://sourceforge.net/projects/myhdl/files/myhdl/0.8/ > > Of the 2 patches, myhdl-0.8-fix_modbv.patch is my poor-man's fix for > modbv, because I needed modbv. This patch is most likely obsoleted by > Jan's real fix in the repo. > > The other patch (myhdl-0.8-partitions.patch) contains my crude first draft > supporting the described hierarchy. Yes, this code is ugly. Don't look at > it yet. It is a quick mock-up of some functionality I really wanted. But > give it a try if you're interested and let me know what it breaks on... Or > if you really want to dive into the code, feel free to do so. > > On my systems, I apply & install these patches as follows: (gunzip the > .patch files first) > > gunzip myhdl-0.8-fix_modbv.patch.gz > gunzip myhdl-0.8-partitions.patch.gz > tar zxf myhdl-0.8.tar.gz \ > && cd myhdl-0.8 \ > && patch -p1 < ../myhdl-0.8-fix_modbv.patch \ > && patch -p1 < ../myhdl-0.8-partitions.patch \ > && python setup.py build \ > && python setup.py install --user -O2 \ > && cd .. \ > && rm -rf myhdl-0.8 > > This installs myhdl into python's standard location for my home directory, > but feel free to leave off --user to install to the main system path, or > wherever else you want. > > To test drive the functionality, try running test_partition.py. Set > toVerilog.partitioned_output=False > to see the normal output, and > toVerilog.partitioned_output=True > to see the partitioned output. And if you are curious, try > toVerilog.partitioned_output="I promise I will never die." > to enable the partitioned output code, but tell it to ignore the partition > annotations. > > > (typos and all, I'm hitting send...) > > - David > > > > On Wed, May 1, 2013 at 6:44 PM, Oscar Daniel Diaz <osc...@gm...>wrote: > >> El Wed, 01 May 2013 10:55:55 +0200 >> Jan Decaluwe <ja...@ja...> escribió: >> >> > On 04/29/2013 05:25 PM, Oscar Daniel Diaz wrote: >> > >> > > Given that the converter is called recursively several times, >> > > multiple files are generated and its contents are used for component >> > > declaration (VHDL). Recursive calls must avoid file replication (for >> > > VHDL case means avoid multiple package file generation). This is >> > > done by keeping generated code in memory before pushing to files. >> > > >> > > Attribute "no_component_files" : >> > > * False : all components code is saved to disk as soon as >> > > possible. >> > > * True : discard components code, only save top-module file. >> > >> > Not sure what is meant here exactly. Why would we need component >> > declarations, as opposed to simply using direct instantation? >> > For a case like this, this seems much simpler and less verbose >> > to me. >> >> Since keep hierarchy conversion requires multiple files to generate >> (top-module and components to instantiate), this flag prevents >> generation of those components. Suppose you make some changes only in >> the top-module, this flag allows to only generate top-module file. >> >> When I change from VHDL '87 syntax (doing recursive calls to get >> component declaration) to '93 syntax, that flag would prevent >> those recursive calls. >> >> -- >> Oscar Díaz >> Key Fingerprint = 904B 306C C3C2 7487 650B BFAC EDA2 B702 90E9 9964 >> gpg --keyserver subkeys.pgp.net --recv-keys 90E99964 >> >> >> _______________________________________________ >> myhdl-list mailing list >> myh...@li... >> https://lists.sourceforge.net/lists/listinfo/myhdl-list >> >> > > > ------------------------------------------------------------------------------ > October Webinars: Code for Performance > Free Intel webinars can help you accelerate application performance. > Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most > from > the latest Intel processors and coprocessors. See abstracts and register > > http://pubads.g.doubleclick.net/gampad/clk?id=60133471&iu=/4140/ostg.clktrk > _______________________________________________ > myhdl-list mailing list > myh...@li... > https://lists.sourceforge.net/lists/listinfo/myhdl-list > > |