1
0
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:
Guenter Dannoritzer 2008-07-31 23:09:25 +02:00
parent 045349965f
commit 6c5094d280
2 changed files with 281 additions and 1 deletions

View File

@ -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
View 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()