@@ -428,21 +428,32 @@ class Ctl(Enum):
428
428
ValueBitwidthTuple = collections .namedtuple ('ValueBitwidthTuple' , 'value bitwidth' )
429
429
430
430
431
- def infer_val_and_bitwidth (rawinput , bitwidth = None ):
431
+ def infer_val_and_bitwidth (rawinput , bitwidth = None , signed = False ):
432
432
""" Return a tuple (value, bitwidth) infered from the specified input.
433
433
434
434
:param rawinput: a bool, int, or verilog-style string constant
435
435
:param bitwidth: an integer bitwidth or (by default) None
436
+ :param signed: a bool (by default set False) to include bits for proper twos complement
436
437
:returns tuple of integers (value, bitwidth)
437
438
438
439
Given a boolean, integer, or verilog-style string constant, this function returns a
439
440
tuple of two integers (value, bitwidth) which are infered from the specified rawinput.
440
441
The tuple returned is, in fact, a named tuple with names .value and .bitwidth for feilds
441
- 0 and 1 respectively. Error checks are performed that determine if the bitwidths specified
442
- are sufficient and appropriate for the values specified. Examples can be found below ::
442
+ 0 and 1 respectively. If signed is set to true, bits will be included to ensure a proper
443
+ two's complement representation is possible, otherwise it is assume all bits can be used
444
+ for standard unsigned representation. Error checks are performed that determine if the
445
+ bitwidths specified are sufficient and appropriate for the values specified.
446
+ Examples can be found below ::
443
447
444
448
infer_val_and_bitwidth(2, bitwidth=5) == (2, 5)
445
449
infer_val_and_bitwidth(3) == (3, 2) # bitwidth infered from value
450
+ infer_val_and_bitwidth(3, signed=True) == (3, 3) # need a bit for the leading zero
451
+ infer_val_and_bitwidth(-3, signed=True) == (5, 3) # 5 = -3 & 0b111 = ..111101 & 0b111
452
+ infer_val_and_bitwidth(-4, signed=True) == (4, 3) # 4 = -4 & 0b111 = ..111100 & 0b111
453
+ infer_val_and_bitwidth(-3, bitwidth=5, signed=True) == (29, 5)
454
+ infer_val_and_bitwidth(-3) ==> Error # negative numbers require bitwidth or signed=True
455
+ infer_val_and_bitwidth(3, bitwidth=2) == (3, 2)
456
+ infer_val_and_bitwidth(3, bitwidth=2, signed=True) ==> Error # need space for sign bit
446
457
infer_val_and_bitwidth(True) == (1, 1)
447
458
infer_val_and_bitwidth(False) == (0, 1)
448
459
infer_val_and_bitwidth("5'd12") == (12, 5)
@@ -453,17 +464,19 @@ def infer_val_and_bitwidth(rawinput, bitwidth=None):
453
464
"""
454
465
455
466
if isinstance (rawinput , bool ):
456
- return _convert_bool (rawinput , bitwidth )
467
+ return _convert_bool (rawinput , bitwidth , signed )
457
468
elif isinstance (rawinput , numbers .Integral ):
458
- return _convert_int (rawinput , bitwidth )
469
+ return _convert_int (rawinput , bitwidth , signed )
459
470
elif isinstance (rawinput , six .string_types ):
460
- return _convert_verilog_str (rawinput , bitwidth )
471
+ return _convert_verilog_str (rawinput , bitwidth , signed )
461
472
else :
462
473
raise PyrtlError ('error, the value provided is of an improper type, "%s"'
463
474
'proper types are bool, int, and string' % type (rawinput ))
464
475
465
476
466
- def _convert_bool (bool_val , bitwidth = None ):
477
+ def _convert_bool (bool_val , bitwidth = None , signed = False ):
478
+ if signed :
479
+ raise PyrtlError ('error, booleans cannot be signed (covert to int first)' )
467
480
num = int (bool_val )
468
481
if bitwidth is None :
469
482
bitwidth = 1
@@ -472,23 +485,37 @@ def _convert_bool(bool_val, bitwidth=None):
472
485
return ValueBitwidthTuple (num , bitwidth )
473
486
474
487
475
- def _convert_int (val , bitwidth = None ):
488
+ def _convert_int (val , bitwidth = None , signed = False ):
476
489
if val >= 0 :
477
490
num = val
478
491
# infer bitwidth if it is not specified explicitly
492
+ min_bitwidth = len (bin (num )) - 2 # the -2 for the "0b" at the start of the string
493
+ if signed and val != 0 :
494
+ min_bitwidth += 1 # extra bit needed for the zero
495
+
479
496
if bitwidth is None :
480
- bitwidth = len (bin (num )) - 2 # the -2 for the "0b" at the start of the string
497
+ bitwidth = min_bitwidth
498
+ elif bitwidth < min_bitwidth :
499
+ raise PyrtlError ('bitwidth specified is insufficient to represent constant' )
500
+
481
501
else : # val is negative
502
+ if not signed and bitwidth is None :
503
+ raise PyrtlError ('negative constants require either signed=True or specified bitwidth' )
504
+
482
505
if bitwidth is None :
483
- raise PyrtlError (
484
- 'negative Const values must have bitwidth declared explicitly' )
506
+ bitwidth = 1 if val == - 1 else len ( bin ( ~ val )) - 1
507
+
485
508
if (val >> bitwidth - 1 ) != - 1 :
486
509
raise PyrtlError ('insufficient bits for negative number' )
510
+
487
511
num = val & ((1 << bitwidth ) - 1 ) # result is a twos complement value
488
512
return ValueBitwidthTuple (num , bitwidth )
489
513
490
514
491
- def _convert_verilog_str (val , bitwidth = None ):
515
+ def _convert_verilog_str (val , bitwidth = None , signed = False ):
516
+ if signed :
517
+ raise PyrtlError ('error, signed verilog-style string constants not supported currently' )
518
+
492
519
bases = {'b' : 2 , 'o' : 8 , 'd' : 10 , 'h' : 16 , 'x' : 16 }
493
520
passed_bitwidth = bitwidth
494
521
0 commit comments