Thread: [myhdl-list] Dream Mux (still a dream for now)
Brought to you by:
jandecaluwe
From: George P. <ge...@ga...> - 2006-09-29 11:42:38
|
Hi Jan, I've been experimenting with ways to make my Wishbone bus components more robust and modular (as well as less tedious and error-prone to write, theres quite a few signals). I've had a lot of success using dicts to bundle signals together, but something is preventing me from taking this concept all the way. Basically, I want a 2:1 Mux that routes one of the signal bundles to its output. I pasted a "dream" Mux block at the end of my email. I want it to assign every named signal in sigs_out, to its named counterpart in either sigs0 and sigs1, depending on the state of the select line. The signal bundles are Python dictionaries and could look something like this: # -- Begin Code Paste -------------------------------------- sel = Signal(bool(0)) # Input Bundle 0 sigs0 = {} sigs0['dat'] = Signal(intbv(0)[8:]) sigs0['adr'] = Signal(intbv(0)[16:]) sigs0['cyc'] = Signal(bool(0)) sigs0['stb'] = Signal(bool(0)) # Input Bundle 1 sigs1 = {} sigs1['dat'] = Signal(intbv(0)[8:]) sigs1['adr'] = Signal(intbv(0)[16:]) sigs1['cyc'] = Signal(bool(0)) sigs1['stb'] = Signal(bool(0)) # Output Bundle sigs_out = {} sigs_out['dat'] = Signal(intbv(0)[8:]) sigs_out['adr'] = Signal(intbv(0)[16:]) sigs_out['cyc'] = Signal(bool(0)) sigs_out['cyc'] = Signal(bool(0)) MUX_INST = DreamMux(sigs0, sigs1, sigs_out, sel) # -- End Code Paste -------------------------------------- I'm curious as to why the code below doesn't work (it causes a "Requirement Violation, see below), and if it can be made to work. I really want this functionality. I think I've developed my Python chops enough to try working on your MyHDL sourcecode myself, but I'm still unsure as to how it all works. I just put your code through Doxygen which is going to help a lot, but could you give me some hints and maybe enlighten me a little about what would have to change? This has to be possible! :) Thanks, George # -- Begin Code Paste -------------------------------------- def DreamMux(sigs0, sigs1, sigs_out, sel): # I'd love to be able to do this, # but currently get errors in MyHDL: # sigs_out, sigs0, and sigs1 are dicts def Muxer(): while True: yield sel if sel: # For all signals in sigs_out # connect them to their counterparts in sigs1 for k in sigs_out.keys(): sigs_out[k].next = sigs1[k] else: # For all signals in sigs_out # connect them to their counterparts in sigs0 for k in sigs_out.keys(): sigs_out[k].next = sigs0[k] MUXER = Muxer() return instances() # -- End Code Paste -------------------------------------- Traceback (most recent call last): File "myhdl_class_wbc_Master_Slave.py", line 282, in ? toVerilog(top, clk_i) File "/usr/lib/python2.4/site-packages/myhdl/_toVerilog/_convert.py", line 118 , in __call__ _convertGens(genlist, vfile) File "/usr/lib/python2.4/site-packages/myhdl/_toVerilog/_convert.py", line 271 , in _convertGens compiler.walk(ast, v) File "/tmp/python.340/usr/lib/python2.4/compiler/visitor.py", line 106, in wal k File "/tmp/python.340/usr/lib/python2.4/compiler/visitor.py", line 63, in preo rder File "/tmp/python.340/usr/lib/python2.4/compiler/visitor.py", line 57, in disp atch File "/usr/lib/python2.4/site-packages/myhdl/_toVerilog/_convert.py", line 712 , in visitModule self.visit(stmt) File "/tmp/python.340/usr/lib/python2.4/compiler/visitor.py", line 57, in disp atch File "/usr/lib/python2.4/site-packages/myhdl/_toVerilog/_convert.py", line 892 , in visitFunction self.visit(stmt) File "/tmp/python.340/usr/lib/python2.4/compiler/visitor.py", line 57, in disp atch File "/usr/lib/python2.4/site-packages/myhdl/_toVerilog/_convert.py", line 647 , in visitIf self.mapToIf(node, *args) File "/usr/lib/python2.4/site-packages/myhdl/_toVerilog/_convert.py", line 694 , in mapToIf self.visit(suite) File "/tmp/python.340/usr/lib/python2.4/compiler/visitor.py", line 57, in disp atch File "/usr/lib/python2.4/site-packages/myhdl/_toVerilog/_convert.py", line 817 , in visitStmt self.visit(stmt) File "/tmp/python.340/usr/lib/python2.4/compiler/visitor.py", line 57, in disp atch File "/usr/lib/python2.4/site-packages/myhdl/_toVerilog/_convert.py", line 567 , in visitFor self.require(node, f in (range, downrange), "Expected (down)range call") File "/usr/lib/python2.4/site-packages/myhdl/_toVerilog/__init__.py", line 113 , in require self.raiseError(node, _error.Requirement, msg) File "/usr/lib/python2.4/site-packages/myhdl/_toVerilog/__init__.py", line 108 , in raiseError raise ToVerilogError(kind, msg, info) myhdl.ToVerilogError: in file myhdl_class_wbc_Master_Slave.py, line 90: Requirement violation: Expected (down)range call |
From: Jan D. <ja...@ja...> - 2006-10-01 13:03:18
|
George Pantazopoulos wrote: > Hi Jan, > > I've been experimenting with ways to make my Wishbone bus components > more robust and modular (as well as less tedious and error-prone to > write, theres quite a few signals). I've had a lot of success using > dicts to bundle signals together, but something is preventing me from > taking this concept all the way. > > Basically, I want a 2:1 Mux that routes one of the signal bundles to its > output. > > I pasted a "dream" Mux block at the end of my email. I want it to assign > every named signal in sigs_out, to its named counterpart in either sigs0 > and sigs1, depending on the state of the select line. > I'm curious as to why the code below doesn't work (it causes a > "Requirement Violation, see below), and if it can be made to work. I > really want this functionality. > > I think I've developed my Python chops enough to try working on your > MyHDL sourcecode myself, but I'm still unsure as to how it all works. I > just put your code through Doxygen which is going to help a lot, but > could you give me some hints and maybe enlighten me a little about what > would have to change? This has to be possible! :) George: Before doing anything else I would like to know whether you find the following solution acceptable. You could use dicts that hold signals to be muxed as follows: # begin code from myhdl import * def mux(z, a, b, sel): @always_comb def logic(): if sel: z.next = b else: z.next = a return logic def DreamMux(sigs0, sigs1, sigs_out, sel): muxes = [mux(sigs_out[k], sigs0[k], sigs1[k], sel) for k in sigs_out] return muxes # end code Then there's the issue of the top-level interface. There you can't use dicts because the ports have to be mapped to Verilog primitives. However, this issue is different from your main concern and again, it's only an issue at the very top-level. As an example, this would be a top-level wrapper around the DreamMux design: # begin code # top-level with "flat" interface def Top(dat0, adr0, cyc0, stb0, dat1, adr1, cyc1, stb1, dat_out, adr_out, cyc_out, stb_out, sel): sigs0 = dict(dat=dat0, adr=adr0, cyc=cyc0, stb=stb0) sigs1 = dict(dat=dat1, adr=adr1, cyc=cyc1, stb=stb1) sigs_out = dict(dat=dat_out, adr=adr_out, cyc=cyc_out, stb=stb_out) top_inst = DreamMux(sigs0, sigs1, sigs_out, sel) return top_inst # end code You can verify that it converts as follows: # begin code # conversion sel = Signal(bool(0)) dat0, dat1, dat_out = [Signal(intbv(0)[8:]) for i in range(3)] adr0, adr1, adr_out = [Signal(intbv(0)[16:]) for i in range(3)] cyc0, cyc1, cyc_out = [Signal(bool(0)) for i in range(3)] stb0, stb1, stb_out = [Signal(bool(0)) for i in range(3)] toVerilog(Top, dat0, adr0, cyc0, stb0, dat1, adr1, cyc1, stb1, dat_out, adr_out, cyc_out, stb_out, sel) # end code Best regards, Jan -- Jan Decaluwe - Resources bvba - http://www.jandecaluwe.com Losbergenlaan 16, B-3010 Leuven, Belgium From Python to silicon: http://myhdl.jandecaluwe.com |
From: George P. <ge...@ga...> - 2006-10-01 15:31:43
|
> George: > > Before doing anything else I would like to know whether you find the > following solution acceptable. > > You could use dicts that hold signals to be muxed as follows: > > # begin code > from myhdl import * > > def mux(z, a, b, sel): > @always_comb > def logic(): > if sel: > z.next = b > else: > z.next = a > return logic > > > def DreamMux(sigs0, sigs1, sigs_out, sel): > > muxes = [mux(sigs_out[k], sigs0[k], sigs1[k], sel) for k in sigs_out] > > return muxes > # end code > > Hi Jan, Thanks for your reply. Unfortunately, even though the above does convert, I think it leaves a lot to be desired because it produces long-winded, hard to follow Verilog code. I think it's important for the Verilog code to stay reaonably readable and MyHDL already does a great job in that respect. As far as the top-level interface, having it completely flat is inconvenient for me, but I can live with it for now. I'm going to try to find my own solution, and I'll let you know if I come up with anything. Yeah, Python hacking! :-) Thanks, George > Then there's the issue of the top-level interface. There you can't > use dicts because the ports have to be mapped to Verilog primitives. > However, this issue is different from your main concern and > again, it's only an issue at the very top-level. > > As an example, this would be a top-level wrapper around the > DreamMux design: > > # begin code > # top-level with "flat" interface > def Top(dat0, adr0, cyc0, stb0, > dat1, adr1, cyc1, stb1, > dat_out, adr_out, cyc_out, stb_out, sel): > > sigs0 = dict(dat=dat0, adr=adr0, cyc=cyc0, stb=stb0) > sigs1 = dict(dat=dat1, adr=adr1, cyc=cyc1, stb=stb1) > sigs_out = dict(dat=dat_out, adr=adr_out, cyc=cyc_out, stb=stb_out) > > top_inst = DreamMux(sigs0, sigs1, sigs_out, sel) > > return top_inst > # end code > > You can verify that it converts as follows: > > # begin code > # conversion > sel = Signal(bool(0)) > dat0, dat1, dat_out = [Signal(intbv(0)[8:]) for i in range(3)] > adr0, adr1, adr_out = [Signal(intbv(0)[16:]) for i in range(3)] > cyc0, cyc1, cyc_out = [Signal(bool(0)) for i in range(3)] > stb0, stb1, stb_out = [Signal(bool(0)) for i in range(3)] > > toVerilog(Top, > dat0, adr0, cyc0, stb0, > dat1, adr1, cyc1, stb1, > dat_out, adr_out, cyc_out, stb_out, sel) > # end code > > Best regards, > > Jan > > |
From: Jan D. <ja...@ja...> - 2006-10-01 18:44:58
|
George: A couple of points: > Hi Jan, > > Thanks for your reply. Unfortunately, even though the above does > convert, I think it leaves a lot to be desired because it produces > long-winded, hard to follow Verilog code. Mm. The code for 4 muxes, as can be expected. With Python 2.5, we'll be able to write mux behavior with one-liners: z.next = b if sel else a which implies that the convertor will then simply produce 4 assign statements (using the Verilog one-liner counterpart). > I think it's important for the > Verilog code to stay reaonably readable and MyHDL already does a great > job in that respect. For the code that is converted, yes. Even of higher quality than what many a Verilog coder produces. But - I keep hammering on the same nail - not all code is/needs to be converted, and that can be used to one's advantage. In the sense that you can produce synthesizable Verilog even when your MyHDL code uses features for which there is no Verilog counterpart or no support in the synthesis tool. Obviously in such cases the Verilog output will not reflect the MyHDL input code - it will be at a much "lower level". But it will do the same thing! In summary, "readability" of the Verilog output is only my 3rd goal. The first is correctness, and the second is conversion power. As I try to show, the finest conversion results are sometimes obtained when no code is converted at all! (Because it has been taken care of before, by the elaboration with the Python interpreter.) And when, consequently, the Verilog output seems unrelated to the MyHDL input. Some of these ideas are explored on the following page: http://myhdl.jandecaluwe.com/doku.php/cookbook:sinecomp A very good example of what I'm trying to say is here: http://myhdl.jandecaluwe.com/doku.php/cookbook:bitonic The latter page shows that you can use structural recursion even when your target language or synthesis tool don't support recursion at all. > I'm going to try to find my own solution, and I'll let you know if I > come up with anything. Yeah, Python hacking! :-) Fine. But note that your original code is most likely not what you want, because it's only sensitive to the control signal. For proper combinatorial behavior, it should be sensitive to the data signals as well. Regards, Jan -- Jan Decaluwe - Resources bvba - http://www.jandecaluwe.com Losbergenlaan 16, B-3010 Leuven, Belgium From Python to silicon: http://myhdl.jandecaluwe.com |
From: George P. <ge...@ga...> - 2006-10-01 18:57:42
|
> Mm. The code for 4 muxes, as can be expected. > > With Python 2.5, we'll be able to write mux behavior with one-liners: > > z.next = b if sel else a > > which implies that the convertor will then simply produce 4 assign > statements (using the Verilog one-liner counterpart). > > That sounds interesting. For synchronous logic, I'd like that to produce one 'always' block in Verilog as opposed to N blocks. > > In summary, "readability" of the Verilog output is only my 3rd goal. > The first is correctness, and the second is conversion power. As I > try to show, the finest conversion results are sometimes obtained > when no code is converted at all! (Because it has been taken care > of before, by the elaboration with the Python interpreter.) And when, > consequently, the Verilog output seems unrelated to the MyHDL input. > > Some of these ideas are explored on the following page: > > http://myhdl.jandecaluwe.com/doku.php/cookbook:sinecomp > > A very good example of what I'm trying to say is here: > > http://myhdl.jandecaluwe.com/doku.php/cookbook:bitonic > > The latter page shows that you can use structural recursion even > when your target language or synthesis tool don't support recursion > at all. > > Indeed! I've been having fun with that lately :-) Your cookbook examples are very rich with powerful and practical techniques. The more I re-read them the more I learn. Great job! How difficult would it be to enhance the Verilog converter so it accepts dict lookups in generators? I really want to have the ability to do this: @always(sigs['clk'].posedge) def Proc(): sigs['dat'].next = 0 Thanks and keep up the good work, George |
From: Jan D. <ja...@ja...> - 2006-10-02 20:28:13
|
George Pantazopoulos wrote: > > How difficult would it be to enhance the Verilog converter so it accepts > dict lookups in generators? > > I really want to have the ability to do this: > > @always(sigs['clk'].posedge) > def Proc(): > > sigs['dat'].next = 0 > George: To meaningfully the assess the difficulty of this I believe we should move from examples (which are useful to get the ball rolling) to a comprehensive spec of what really is required. For example, the example above would require read lookup based on a constant key. The first example you posted would require much more: - read lookup on a loop variable key - support for the keys() method of dicts, used in a for-loop - I understand that because of readibility, you would want to map the for-loop to a Verilog loop in the output Of course, there are many more things that can be done with dicts and that are potentially useful in modeling. Before we know what should be supported, what not, and how it should map to Verilog if applicable, little can be said about implementation difficulty. Discussing about a spec will make it possible to understand the issues better, and perhaps even come up with a better solution for what you want to achieve. Best regards, Jan -- Jan Decaluwe - Resources bvba - http://www.jandecaluwe.com Losbergenlaan 16, B-3010 Leuven, Belgium From Python to silicon: http://myhdl.jandecaluwe.com |
From: George P. <ge...@ga...> - 2006-10-02 22:15:35
|
> > Discussing about a spec will make it possible to understand > the issues better, and perhaps even come up with a better > solution for what you want to achieve. > I agree. I've been doing some pathfinding on my own, evaluating different methods of making the MyHDL code more readable while using (and unit testing) hardware modules with many signals. I've also done some experiments using classes for hardware blocks and theres a synergistic effect with using signal bundles (dicts). What I do know is that bundling signals using dicts seems to be a good wa= y to group related signals and manage complexity. The problem areas with using signal bundles as I seem them currently are: Top-level modules for conversion to synthesizable Verilog: - Probably not much of a problem in practice, but I'll have to experimen= t. Using toVerilog with cosimulation: - Since toVerilog() requires a flat signal list, this is problematic. There may be a way to get around this by using some advanced Pythoning= =20 (such as the function wrapping features in 2.5). I'll have to experiment. Being required to unbundle signals for use in generators, since toVerilog doesn't currently support directly using dicts in generators: def module(sigs): # 'sigs' may contain more signals than we acutally unbundle and use. # This is actually clearer than using the dict directly, # since it describes the signal from the perspective of this module. # Also, it's easier to type. clk_i =3D sigs['clk'] dat_o =3D sigs['drd'] dat_i =3D sigs['dwr'] @always(clk_i.posedge) def proc(): ... return instances() - This isn't too much of a problem. I've often found that unbundling the signals enhances readability anyway. Note this works fine in unit tests without cosimulation. But if cosimulation doesn't support it, then the unit tests can't really use it in practice. - Being able to manipulate all signals in a dict while inside a generator, and have the generated Verilog only contain a single 'always' block. This seems to be a strongly desireable feature, but as you said is a lot harder to implement than the previous item. I'm not quite sure how to start off a discussion on specs. Could you give me a hint to get started? Even with these problem areas, I've had considerable success already in m= y experiments, using classes and bundled signals. Python and MyHDL really give me a lot of freedom to be creative. I'm working on a ring buffer module that uses classes, signal bundling, and some more of my 'home grown' ideas. Would it be helpful if I posted the code and unit test sometime later? Regards, George --=20 George Pantazopoulos http://www.gammaburst.net |
From: Tom D. <TD...@di...> - 2006-10-02 04:46:13
|
> Thanks for your reply. Unfortunately, even though the above does > convert, I think it leaves a lot to be desired because it produces > long-winded, hard to follow Verilog code. I think it's important for the > Verilog code to stay reaonably readable and MyHDL already does a great > job in that respect. As far as the top-level interface, having it > completely flat is inconvenient for me, but I can live with it for now. > I'm going to try to find my own solution, and I'll let you know if I > come up with anything. Yeah, Python hacking! :-) > Just my 2 cents worth... I've never been concerned with what the generated Verilog code looks like. As a matter of fact, as long as it synthesizes (and simulates) properly, I would never look at it. Tom |