mirror of
https://github.com/myhdl/myhdl.git
synced 2024-12-14 07:44:38 +08:00
Added signed() member function to intbv
The intbv class got a signed() member function added. The function will classify the value of an intbv instance as unsigned or signed based on the min/max settings. If a value is classified as unsigned, the bit pattern is interpreted as a 2's-complement value and returned. If the value is classified as signed, the value will be returned as is. The signed() function will return the value as integer. Added test cases verify the proper function of the signed() function.
This commit is contained in:
parent
045349965f
commit
6c5094d280
@ -436,4 +436,58 @@ class intbv(object):
|
||||
|
||||
def __repr__(self):
|
||||
return "intbv(" + repr(self._val) + ")"
|
||||
|
||||
|
||||
|
||||
def signed(self):
|
||||
''' return integer with the signed value of the intbv instance
|
||||
|
||||
The intbv.signed() function will classify the value of the intbv
|
||||
instance either as signed or unsigned. If the value is classified
|
||||
as signed it will be returned unchanged as integer value. If the
|
||||
value is considered unsigned, the value will be returned as
|
||||
integer value, with the sign being considered by the msb. The msb
|
||||
is the msb as specified by _nrbits.
|
||||
|
||||
The classification is based on the following possible combinations
|
||||
of the min and max value.
|
||||
|
||||
----+----+----+----+----+----+----+----
|
||||
-3 -2 -1 0 1 2 3
|
||||
1 min max
|
||||
2 min max
|
||||
3 min max
|
||||
4 min max
|
||||
5 min max
|
||||
6 min max
|
||||
7 min max
|
||||
8 neither min nor max is set
|
||||
9 only max is set
|
||||
10 only min is set
|
||||
|
||||
From the above cases, # 1 and 2 are considered unsigned and the
|
||||
signed() function will convert the value to a signed number.
|
||||
Decision about the sign will be done based on the msb. The msb is
|
||||
based on the _nrbits value.
|
||||
|
||||
So the test will be if min >= 0 and _nrbits > 0. Then the instance
|
||||
is considered unsigned and the value is change based on the msb.
|
||||
'''
|
||||
|
||||
# value is considered unsigned
|
||||
if self.min >= 0 and self._nrbits > 0:
|
||||
|
||||
msb = self._nrbits-1
|
||||
|
||||
sign = ((self._val >> msb) & 0x1) > 0
|
||||
|
||||
# mask off the bits msb-1:lsb, they are always positive
|
||||
mask = (1<<msb) - 1
|
||||
retVal = self._val & mask
|
||||
# if sign bit is set, subtract the value of the sign bit
|
||||
if sign:
|
||||
retVal -= 1<<msb
|
||||
|
||||
else: # value is returned just as is
|
||||
retVal = self._val
|
||||
|
||||
return retVal
|
||||
|
226
myhdl/test/core/test_signed.py
Executable file
226
myhdl/test/core/test_signed.py
Executable file
@ -0,0 +1,226 @@
|
||||
#!/usr/bin/env python
|
||||
# This file is part of the myhdl library, a Python package for using
|
||||
# Python as a Hardware Description Language.
|
||||
#
|
||||
# Copyright (C) 2008 Jan Decaluwe
|
||||
#
|
||||
# The myhdl library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 2.1 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
""" Run the intbv.signed() unit tests. """
|
||||
|
||||
__author__ = "Jan Decaluwe <jan@jandecaluwe.com>"
|
||||
__revision__ = "$Revision$"
|
||||
__date__ = "$Date$"
|
||||
|
||||
import unittest
|
||||
from unittest import TestCase
|
||||
|
||||
from myhdl._intbv import intbv
|
||||
from myhdl._concat import concat
|
||||
|
||||
class TestIntbvSigned(TestCase):
|
||||
'''Test cases to verify the intbv.signed() member function'''
|
||||
|
||||
def testPlainIntbvInstance(self):
|
||||
'''Test a plain intbv instance with .signed()
|
||||
|
||||
----+----+----+----+----+----+----+----
|
||||
-3 -2 -1 0 1 2 3
|
||||
|
||||
min max
|
||||
min max
|
||||
min max
|
||||
min max
|
||||
min max
|
||||
min max
|
||||
min max
|
||||
neither min nor max is set
|
||||
only max is set
|
||||
only min is set
|
||||
|
||||
'''
|
||||
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# in the following cases the .signed() function should classify the
|
||||
# value of the intbv instance as unsigned and return a value based
|
||||
# on the msb.
|
||||
#
|
||||
|
||||
# intbv with positive range, pos number, and msb not set, return signed()
|
||||
# Expect the number to be returned
|
||||
a = intbv(0x3b, min=0, max=0x7c)
|
||||
b = a.signed()
|
||||
self.assertEqual(b, 0x3b)
|
||||
|
||||
# intbv with positive range, pos number, and msb set, return signed()
|
||||
# Expect the number to be converted to a negative number
|
||||
a = intbv(7, min=0, max=8)
|
||||
b = a.signed()
|
||||
self.assertEqual(b, -1)
|
||||
|
||||
a = intbv(6, min=0, max=8)
|
||||
b = a.signed()
|
||||
self.assertEqual(b, -2)
|
||||
|
||||
a = intbv(5, min=0, max=8)
|
||||
b = a.signed()
|
||||
self.assertEqual(b, -3)
|
||||
|
||||
# set bit #3 and increase the range that the set bit is considered
|
||||
# the sign bit
|
||||
# Expect to return -4
|
||||
a = intbv(4, min=0, max=5)
|
||||
b = a.signed()
|
||||
self.assertEqual(b, -4)
|
||||
|
||||
a = intbv(4, min=0, max=6)
|
||||
b = a.signed()
|
||||
self.assertEqual(b, -4)
|
||||
|
||||
a = intbv(4, min=0, max=7)
|
||||
b = a.signed()
|
||||
self.assertEqual(b, -4)
|
||||
|
||||
a = intbv(4, min=0, max=8)
|
||||
b = a.signed()
|
||||
self.assertEqual(b, -4)
|
||||
|
||||
# here it is not the sign bit anymore
|
||||
# Expect the value to be 4
|
||||
a = intbv(4, min=0, max=9)
|
||||
b = a.signed()
|
||||
self.assertEqual(b, 4)
|
||||
|
||||
# intbv with positive range, value = 0, return signed()
|
||||
# Expect the number to be returned
|
||||
a = intbv(0, min=0, max=0x8)
|
||||
b = a.signed()
|
||||
self.assertEqual(b, 0)
|
||||
|
||||
|
||||
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# in these cases the .signed() function should classify the
|
||||
# value of the intbv instance as signed and return the value as is
|
||||
#
|
||||
|
||||
# intbv without range, pos number, return signed()
|
||||
# Expect value to be returned as is
|
||||
a = intbv(8)
|
||||
b = a.signed()
|
||||
self.assertEqual(b, 8)
|
||||
|
||||
# intbv without range, neg number, return signed()
|
||||
# Expect value to be returned as is
|
||||
a = intbv(-8)
|
||||
b = a.signed()
|
||||
self.assertEqual(b, -8)
|
||||
|
||||
# set bit #3 and increase the range that the set bit is actually the
|
||||
# msb, but due to the negative range not considered signed
|
||||
# Expect to return 4
|
||||
a = intbv(4, min=-1, max=5)
|
||||
b = a.signed()
|
||||
self.assertEqual(b, 4)
|
||||
|
||||
a = intbv(4, min=-1, max=6)
|
||||
b = a.signed()
|
||||
self.assertEqual(b, 4)
|
||||
|
||||
a = intbv(4, min=-1, max=7)
|
||||
b = a.signed()
|
||||
self.assertEqual(b, 4)
|
||||
|
||||
a = intbv(4, min=-1, max=8)
|
||||
b = a.signed()
|
||||
self.assertEqual(b, 4)
|
||||
|
||||
# intbv with negative range, pos number, and msb set, return signed()
|
||||
# Expect the number to returned as is
|
||||
a = intbv(7, min=-1, max=8)
|
||||
b = a.signed()
|
||||
self.assertEqual(b, 7)
|
||||
|
||||
a = intbv(6, min=-1, max=8)
|
||||
b = a.signed()
|
||||
self.assertEqual(b, 6)
|
||||
|
||||
a = intbv(5, min=-1, max=8)
|
||||
b = a.signed()
|
||||
self.assertEqual(b, 5)
|
||||
|
||||
|
||||
# intbv with symmetric (min = -max) range, pos value, msb set
|
||||
# return signed()
|
||||
# Expect value returned as is
|
||||
a = intbv(4, min=-8, max=8)
|
||||
b = a.signed()
|
||||
self.assertEqual(b, 4)
|
||||
|
||||
# intbv with symmetric (min = -max) range, neg value,
|
||||
# return signed()
|
||||
# Expect value returned as is
|
||||
a = intbv(-4, min=-8, max=8)
|
||||
b = a.signed()
|
||||
self.assertEqual(b, -4)
|
||||
|
||||
# intbv with symmetric (min=-max) range, value = 0,
|
||||
# return signed()
|
||||
# Expect value returned as is
|
||||
a = intbv(0, min=-8, max=8)
|
||||
b = a.signed()
|
||||
self.assertEqual(b, 0)
|
||||
|
||||
|
||||
|
||||
def testSlicedSigned(self):
|
||||
'''Test a slice with .signed()
|
||||
|
||||
This test can actually be simplified, as a slice will always have
|
||||
min=0 and max > min, which will result in an intbv instance that
|
||||
will be considered unsigned by the intbv.signed() function.
|
||||
'''
|
||||
a = intbv(4, min=-8, max=8)
|
||||
b = a[4:]
|
||||
self.assertEqual(b, 4)
|
||||
b = a[4:].signed()
|
||||
self.assertEqual(b, 4) # msb is not set with a 4 bit slice
|
||||
|
||||
b = a[3:]
|
||||
self.assertEqual(b, 4)
|
||||
b = a[3:].signed()
|
||||
self.assertEqual(b, -4) # msb is set with 3 bits sliced
|
||||
|
||||
|
||||
def testSignedConcat(self):
|
||||
'''Test the .signed() function in connection with the concatenate
|
||||
function
|
||||
'''
|
||||
|
||||
# concat 3 bits
|
||||
# Expect the signed function to return a negative value
|
||||
a = concat(True, True, True).signed()
|
||||
self.assertEqual(a, -1)
|
||||
|
||||
# concate a 3 bit intbv with msb set and two bits
|
||||
# Expect a negative number
|
||||
b = concat(intbv(5,min=0,max=8), True, True).signed()
|
||||
self.assertEqual(b, -9)
|
||||
|
||||
|
||||
|
||||
########################################################################
|
||||
# main
|
||||
#
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
Loading…
x
Reference in New Issue
Block a user