Thread: [myhdl-list] Wrap-around support in MyHDL
Brought to you by:
jandecaluwe
From: Jan D. <ja...@ja...> - 2011-05-13 15:19:53
|
Recently, there has been a lot of activity regarding "wrap-around" types. I have looked at the proposals. My own thoughts on the matter have evolved also. Here is my analysis and proposal. Background ---------- One my main critiques on the mainstream use of Verilog/VHDL is the focus on "representational" types for integer arithmetic. In other words, the starting point is a bit vector representation to which an integer interpretation is added later. The hidden assumption is that this is necessary for implementation efficiency. I believe that MyHDL has convincingly demonstrated that there is a better way by taking a top-down perspective. In MyHDL, integer arithmetic simply works as expected. The convertor takes care of representational details as required by the Verilog/VHDL target. This is not just a semantic discussion. In MyHDL, you don't need castings, manual sign extentions or resizings to get integer arithmetic to work. In Verilog/VHDL, it's the name of the game. Best of all, there is no implementation efficiency price to pay. Understandably, I would like to use a similar approach when considering to introduce new types: first look at the modelling aspect, that is, how a designer would prefer to use a type, and only then move to conversion and efficiency concerns. Wrap-around type proposals -------------------------- There is no question that there is a genuine need for the elegant modeling of wrap-around behavior in hardware modeling. The question is whether this is important enough to warrant dedicated language support. In the past, I have suggested that this need may not be that high. For example, in the common case of an incrementer (or decrementor), it is often necessary to decode the end count anyway: if count == N: count.next = 0 # decode action else: count.next = count + 1 However, I would agree that even then it could be clearer to keep the incrementer description separate from the decoding: if count == N: # decode action count.next = (count + 1) % N I have also argued that the modulo operator offers an explicit and elegant high-level solution to describe wrap-around behavior in a one-liner. Chris F has pointed out that this doesn't work for the case of a signed integer. He has proposed a .wrap() method as a solution. Both the modulo operator and a wrap() method have some disadvantages. Through they are explicit in good Python style, there is a conflict with another good principle: DRY (Don't Repeat Yourself). If wrap-around is the desired behavior, it is probably a property of an object and its type, not of a particular assignment. The two techniques have another problem that I have successfully managed to keep out of spotlights in earlier discussions :-) I believe a common use case would be an incrementor/decrementer as an intbv variable, using augmented assignment: count += 1 The two techniques above cannot support this. Tom D has proposed a 'wrap' parameter to the intbv constructor, with default False. When True, it would modify the assignment behavior as desired. This proposal addresses the issues mentioned above, but has some problems itself. An additional parameter makes object construction heavier. Also, the use of a default value suggests that one type of behavior is the rule, and the other the exception. I don't like the idea of modifying the fundamental behavior of a type in such a way. If wrap-around behavior is considered important enough to warrant direct language support, it should be as easy to use as other behaviors. Finally, a parameter cannot support the following conversion trick: a = intbv(0)[N:] to construct a "N bits wide" positive intbv, even though such "closer to hardware" objects are probably popular candidates for wrap-around behavior. The most important problem that I have with the current proposals is still elsewhere: they go against the MyHDL-specific philosophy that I outlined in the background. The starting point of the proposals is that wrap-around behavior will only supported on "full range" bit-vectors. This is likely influenced by implicit assumptions of efficient hardware implementation. In my modeling work, I use wrap-around counters all the time. However, more often than not, their bounds are not powers of 2. I suspect this is the same for many designers. As I have argued earlier, we should look at modeling first, and at hardware efficiency later. In previous cases, such as the intbv type, we have been able to achieve much easier modeling without having to pay a price in efficiency. Ada modular types ----------------- Recently I got introduced to Ada modular types. These are natural integer types with wrap-around behaviour. The wrap-around behavior of modular types is based on the sound mathematical concept of modulo arithmetic. Therefore, the modulus is not limited to powers of 2. The rationale behind modular types is interesting. For example: "The modulus of a modular type need not be a power of two although it often will be. It might, however, be convenient to use some obscure prime number as the modulus perhaps in the implementation of hash tables." [http://www.adaic.org/resources/add_content/standards/95rat/rat95html/rat95-p2-3.html] Another resource says: "Modular types don't need to be powers of two, but if they are the Ada compiler will select especially efficient operations to implement them." [http://www.dwheeler.com/lovelace/s17sf.htm] This is exactly the kind of reasoning I'm looking for. Ada considers module arithmetic important enough to warrant direct language support, but in the general, mathematically sound sense. On the other hand, it recognizes that powers of 2 bounds are very important. There is actually a predefined package with power of 2 based subtypes. Moreover, the compiler can select "especially efficient operations" to implement them. Interestingly, Ada even defines and/or/xor bit operations on modular types, unlike other integer types. Apparently it chooses modular types for this purpose because their "unsigned" interpretation poses less problems than bit operations on "signed" representations. In any case, the dual nature of the type - both high-level and representation-friendly - is similar to what MyHDL does with the intbv. When reading all this, I can only conclude that VHDL lost a big opportunity by forgetting about its origins. I believe the Ada example is the route to follow. Two issues still have to be addressed: 1) Ada modular types are restricted to natural values. We want to support integer values. 2) Ada modular types are types, which means that conversions would be needed to let them work with other integer-like types. (I am not entirely sure of this statement.) A proposal for MyHDL: the modbv type ------------------------------------ Ada's modular type is called 'mod'. By analogy, I am proposing a 'modbv' type in MyHDL. Behaviorally, the only difference with intbv would be how bounds are handled: out-of-bound values result in an error in the intbv, and wrap-around in the modbv. In particular, modbv would have exactly the same interface as the intbv. Wrap-around behavior would be defined as follows: val = (val - min) % (max - min) + min Unlike Ada, intbv and modbv would be subtypes of a general integer-bitvector type. Therefore, they can be mixed transparantly in expressions. This should be not problem as the bound handling only occurs at assignment time in the assigned object. This proposal addresses the issues mentioned earlier. In particular: count += 1 and count = modbv(0)[32:] would have wrap-around behavior. Implementation notes -------------------- Technically, the cleanest implementation would probably be to make both intbv and modbv a subtype of some general integer-bitvector class. In a first phase, it would probably be OK to simply subclass intbv. To make this kind of subclassing possible, the intbv class has to be made more robust. For example, at some points were it returns a literal 'intbv' object, it should use the actual subtype itself. The basic difference with intbv is bound handling. Currently, this is already done in a separate method called intbv._checkBounds(). This method should probably be renamed to intbv._handleBounds(), and then overwritten with the proper behavior in the subclass. Conversion notes ---------------- It is expected that conversion would work directly for the case of "full range" modbv objects. (Note that it is not sufficient that both bounds are powers of 2.) In a first phase, the convertor could impose that restriction. To demonstrate the advantage of the chosen approach, we could attempt to lift some restrictions for interesting use cases. For example, a common use case for wrap-around behavior would be incrementors and decrementors. The analyzer could detect such cases and mark them. For such patterns, we could then support general wrap-around for non full-range objects also. For example: count.next = count + 1 would be converted to: if count == MAX-1: count.next = MIN else: count.next = count + 1 It is probably possible to remove more restrictions in a gradual process. When doing so, we would be adding items to the list of useful features that MyHDL can fully support, even though they have no native support in Verilog/VHDL. At some point, this list of features, unique to MyHDL, could become very attractive to Verilog/VHDL designers. -- Jan Decaluwe - Resources bvba - http://www.jandecaluwe.com Python as a HDL: http://www.myhdl.org VHDL development, the modern way: http://www.sigasi.com Analog design automation: http://www.mephisto-da.com World-class digital design: http://www.easics.com |
From: Christopher F. <chr...@gm...> - 2011-05-16 11:12:56
|
<large snip, background, wrap, ada> > > A proposal for MyHDL: the modbv type > ------------------------------------ > > Ada's modular type is called 'mod'. By analogy, I am > proposing a 'modbv' type in MyHDL. Behaviorally, the only > difference with intbv would be how bounds are handled: > out-of-bound values result in an error in the intbv, and > wrap-around in the modbv. In particular, modbv would have > exactly the same interface as the intbv. Wrap-around > behavior would be defined as follows: > > val = (val - min) % (max - min) + min > > Unlike Ada, intbv and modbv would be subtypes of a general > integer-bitvector type. Therefore, they can be mixed > transparantly in expressions. This should be not problem as > the bound handling only occurs at assignment time in the > assigned object. > > This proposal addresses the issues mentioned earlier. In > particular: > > count += 1 > > and > > count = modbv(0)[32:] > > would have wrap-around behavior. > > Implementation notes > -------------------- > > Technically, the cleanest implementation would probably be > to make both intbv and modbv a subtype of some general > integer-bitvector class. In a first phase, it would > probably be OK to simply subclass intbv. > > To make this kind of subclassing possible, the intbv class > has to be made more robust. For example, at some points were > it returns a literal 'intbv' object, it should use the > actual subtype itself. > > The basic difference with intbv is bound > handling. Currently, this is already done in a separate > method called intbv._checkBounds(). This method should > probably be renamed to intbv._handleBounds(), and then > overwritten with the proper behavior in the subclass. > > Conversion notes > ---------------- > > It is expected that conversion would work directly for the > case of "full range" modbv objects. (Note that it is not > sufficient that both bounds are powers of 2.) In a first > phase, the convertor could impose that restriction. > > To demonstrate the advantage of the chosen approach, we > could attempt to lift some restrictions for interesting use > cases. For example, a common use case for wrap-around > behavior would be incrementors and decrementors. The > analyzer could detect such cases and mark them. For such > patterns, we could then support general wrap-around for non > full-range objects also. For example: > > count.next = count + 1 > > would be converted to: > > if count == MAX-1: > count.next = MIN > else: > count.next = count + 1 > > It is probably possible to remove more restrictions in a > gradual process. When doing so, we would be adding items to > the list of useful features that MyHDL can fully support, > even though they have no native support in Verilog/VHDL. At > some point, this list of features, unique to MyHDL, could > become very attractive to Verilog/VHDL designers. > > Excellent! This is a very comprehensive coverage of the topic. One additional item I think we should address. But not to be included in the above proposed implementation. In the past requests for wrap have mostly been accompanied by a request for saturate as well. Since, more interesting behaviors are being tackled we might want to mention how saturate might be handled (in the future). If this is another type (satbv) or whichever. Otherwise, I think this is a good proposal for the wrapping behavior. I like the addition of the type, derived class, to handle the behaviors. Also, the potential future addition of a new base class. Understanding that this will be future work, if deemed needed after the first pass implementation of modbv. Chris Felton |
From: Jan D. <ja...@ja...> - 2011-05-20 15:26:16
|
As you like the proposal after putting the feature back on the map, and I hear no objections, I'd like to make some progress. This is definitely a 0.8 feature, so I will open a 0.8-dev branch for development. I will also turn the proposal into a MEP. As typical, one good idea may solve other related issues. For example, for some time I have struggled with how to handle an in-place left shift: lsfr <<= 1 With intbv, this will always result in upper bound failures, making the construct unusable. With modbv, it should work as expected. Moreover, in the past for some "bit-oriented" operations, we have made exceptions for "unsigned" intbv's with a finite bound. Reasonable, but a little strange. With modbv, such exceptions may not be necessary. So it may be wise to revert the intbv behavior at some points and ask designers to use modbv for certain operations instead. Jan On 05/16/2011 01:12 PM, Christopher Felton wrote: > <large snip, background, wrap, ada> >> >> A proposal for MyHDL: the modbv type >> ------------------------------------ >> >> Ada's modular type is called 'mod'. By analogy, I am >> proposing a 'modbv' type in MyHDL. Behaviorally, the only >> difference with intbv would be how bounds are handled: >> out-of-bound values result in an error in the intbv, and >> wrap-around in the modbv. In particular, modbv would have >> exactly the same interface as the intbv. Wrap-around >> behavior would be defined as follows: >> >> val = (val - min) % (max - min) + min >> >> Unlike Ada, intbv and modbv would be subtypes of a general >> integer-bitvector type. Therefore, they can be mixed >> transparantly in expressions. This should be not problem as >> the bound handling only occurs at assignment time in the >> assigned object. >> >> This proposal addresses the issues mentioned earlier. In >> particular: >> >> count += 1 >> >> and >> >> count = modbv(0)[32:] >> >> would have wrap-around behavior. >> >> Implementation notes >> -------------------- >> >> Technically, the cleanest implementation would probably be >> to make both intbv and modbv a subtype of some general >> integer-bitvector class. In a first phase, it would >> probably be OK to simply subclass intbv. >> >> To make this kind of subclassing possible, the intbv class >> has to be made more robust. For example, at some points were >> it returns a literal 'intbv' object, it should use the >> actual subtype itself. >> >> The basic difference with intbv is bound >> handling. Currently, this is already done in a separate >> method called intbv._checkBounds(). This method should >> probably be renamed to intbv._handleBounds(), and then >> overwritten with the proper behavior in the subclass. >> >> Conversion notes >> ---------------- >> >> It is expected that conversion would work directly for the >> case of "full range" modbv objects. (Note that it is not >> sufficient that both bounds are powers of 2.) In a first >> phase, the convertor could impose that restriction. >> >> To demonstrate the advantage of the chosen approach, we >> could attempt to lift some restrictions for interesting use >> cases. For example, a common use case for wrap-around >> behavior would be incrementors and decrementors. The >> analyzer could detect such cases and mark them. For such >> patterns, we could then support general wrap-around for non >> full-range objects also. For example: >> >> count.next = count + 1 >> >> would be converted to: >> >> if count == MAX-1: >> count.next = MIN >> else: >> count.next = count + 1 >> >> It is probably possible to remove more restrictions in a >> gradual process. When doing so, we would be adding items to >> the list of useful features that MyHDL can fully support, >> even though they have no native support in Verilog/VHDL. At >> some point, this list of features, unique to MyHDL, could >> become very attractive to Verilog/VHDL designers. >> >> > > Excellent! This is a very comprehensive coverage of the topic. > > One additional item I think we should address. But not to be included > in the above proposed implementation. In the past requests for wrap > have mostly been accompanied by a request for saturate as well. Since, > more interesting behaviors are being tackled we might want to mention > how saturate might be handled (in the future). If this is another type > (satbv) or whichever. > > Otherwise, I think this is a good proposal for the wrapping behavior. I > like the addition of the type, derived class, to handle the behaviors. > Also, the potential future addition of a new base class. Understanding > that this will be future work, if deemed needed after the first pass > implementation of modbv. > > Chris Felton > > > ------------------------------------------------------------------------------ > Achieve unprecedented app performance and reliability > What every C/C++ and Fortran developer should know. > Learn how Intel has extended the reach of its next-generation tools > to help boost performance applications - inlcuding clusters. > http://p.sf.net/sfu/intel-dev2devmay -- Jan Decaluwe - Resources bvba - http://www.jandecaluwe.com Python as a HDL: http://www.myhdl.org VHDL development, the modern way: http://www.sigasi.com Analog design automation: http://www.mephisto-da.com World-class digital design: http://www.easics.com |
From: Jan D. <ja...@ja...> - 2011-05-29 21:55:32
|
On 05/20/2011 05:25 PM, Jan Decaluwe wrote: > As you like the proposal after putting the feature > back on the map, and I hear no objections, I'd like > to make some progress. > > This is definitely a 0.8 feature, so I will open > a 0.8-dev branch for development. I will also turn > the proposal into a MEP. http://myhdl.org/doku.php/meps:mep-106 -- Jan Decaluwe - Resources bvba - http://www.jandecaluwe.com Python as a HDL: http://www.myhdl.org VHDL development, the modern way: http://www.sigasi.com Analog design automation: http://www.mephisto-da.com World-class digital design: http://www.easics.com |
From: Christopher F. <chr...@gm...> - 2011-05-30 16:03:48
|
On 5/29/2011 4:55 PM, Jan Decaluwe wrote: > On 05/20/2011 05:25 PM, Jan Decaluwe wrote: >> As you like the proposal after putting the feature >> back on the map, and I hear no objections, I'd like >> to make some progress. >> >> This is definitely a 0.8 feature, so I will open >> a 0.8-dev branch for development. I will also turn >> the proposal into a MEP. > > http://myhdl.org/doku.php/meps:mep-106 > I didn't notice this in the previous draft but there is an error in the code examples; handling wrap using modulus (Wrap-around type proposals). """ if count == N: count.next = 0 some_decode_action() else: count.next = count + 1 ... if count == N: some_decode action() count.next = (count + 1) % N """ The code snippets should be count == 0 or count = N-1, count will never actually equal N in the "%" case. The first case will not act like a mod. To double check my sanity, here is a small capture from a python session: In [176]: N = 2**3 In [179]: count = intbv(0, min=0, max=N) In [180]: for ii in range(2*N): .....: if count == N: .....: print "Do some action" .....: count[:] = (count + 1) % N .....: print count 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 In [181]: N Out[181]: 8 Chris |
From: Jan D. <ja...@ja...> - 2011-05-30 20:48:34
|
On 05/30/2011 06:03 PM, Christopher Felton wrote: > I didn't notice this in the previous draft but there is an error in the > code examples; handling wrap using modulus (Wrap-around type proposals). Of course. Go ahead and edit (it's a draft :-)) -- Jan Decaluwe - Resources bvba - http://www.jandecaluwe.com Python as a HDL: http://www.myhdl.org VHDL development, the modern way: http://www.sigasi.com Analog design automation: http://www.mephisto-da.com World-class digital design: http://www.easics.com |
From: Christopher F. <chr...@gm...> - 2011-05-30 19:17:43
|
On 5/29/2011 4:55 PM, Jan Decaluwe wrote: > On 05/20/2011 05:25 PM, Jan Decaluwe wrote: >> As you like the proposal after putting the feature >> back on the map, and I hear no objections, I'd like >> to make some progress. >> >> This is definitely a 0.8 feature, so I will open >> a 0.8-dev branch for development. I will also turn >> the proposal into a MEP. > > http://myhdl.org/doku.php/meps:mep-106 > I made a couple other small edits to the mep. Typo and added a link. Feel free to remove :) Chris |
From: Christopher F. <chr...@gm...> - 2011-05-26 13:22:47
|
On 5/20/2011 10:25 AM, Jan Decaluwe wrote: > As you like the proposal after putting the feature > back on the map, and I hear no objections, I'd like > to make some progress. > > This is definitely a 0.8 feature, so I will open > a 0.8-dev branch for development. I will also turn > the proposal into a MEP. > If you like, when the 0.8-dev branch is created, I can take the existing tests that we created and move them over, as a starting point, for the modbv tests. Note: Ben did majority of the work for the previous tests :) Guess it would look something like the following (as a start). Should add additional tests for the expanded features and some tests for conversion. +++ b/myhdl/test/core/test_modbv.py class TestModbvWrap(TestCase): def testWrap(self): x = modbv(0, min=-8, max=8) x[:] = x + 1 self.assertEqual(1, x) x[:] = x + 2 self.assertEqual(3, x) x[:] = x + 5 self.assertEqual(-8, x) x[:] = x + 1 self.assertEqual(-7, x) x[:] = x - 5 self.assertEqual(4, x) x[:] = x - 4 self.assertEqual(0, x) x[:] += 15 x[:] = x - 1 self.assertEqual(-2, x) def testInit(self): self.assertRaises(ValueError, intbv, 15, min=-8, max=8) x = modbv(15, min=-8, max=8) self.assertEqual(-1, x) self.assertRaises(ValueError, intbv, 5, min=-3, max=8) modbv(5, min=-3, max=8) self.assertEqual(5, x) def testNoWrap(self): # verifies the base class does not wrap x = intbv(0, min=-8, max=8) try: x[:] += 15 self.fail() except ValueError: pass if __name__ == "__main__": unittest.main() Chris |
From: Jan D. <ja...@ja...> - 2011-05-26 18:02:52
|
On 05/26/2011 03:22 PM, Christopher Felton wrote: > On 5/20/2011 10:25 AM, Jan Decaluwe wrote: >> As you like the proposal after putting the feature >> back on the map, and I hear no objections, I'd like >> to make some progress. >> >> This is definitely a 0.8 feature, so I will open >> a 0.8-dev branch for development. I will also turn >> the proposal into a MEP. >> > > If you like, when the 0.8-dev branch is created, I can take the existing > tests that we created and move them over, as a starting point, for the > modbv tests. Note: Ben did majority of the work for the previous tests :) That would be very welcome. I have now pushed the 0.8-dev branch that includes my initial take on the feature. I have some indirect tests that suggest that it works, but no direct ones like you have. As for conversion, I have included some checks so that only "full range" modbv's are supported at this point. Feedback and bundles or patches with tests (on the 0.8-dev branch) are welcome. Jan -- Jan Decaluwe - Resources bvba - http://www.jandecaluwe.com Python as a HDL: http://www.myhdl.org VHDL development, the modern way: http://www.sigasi.com Analog design automation: http://www.mephisto-da.com World-class digital design: http://www.easics.com |