Skip to content

Instantly share code, notes, and snippets.

@j-marjanovic
Created November 15, 2015 22:14
Show Gist options
  • Save j-marjanovic/348499e6cae3622554a4 to your computer and use it in GitHub Desktop.
Save j-marjanovic/348499e6cae3622554a4 to your computer and use it in GitHub Desktop.
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
'''
The VerilogBits provides Verilog-style representation of the numbers.
Copyright (C) 2015 Jan Marjanovic <[email protected]>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
'''
import unittest
class VerilogBits(object):
''' The VerilogBits is a simple class which helps dealing with bits vectors.
It mimics the Verilog style slicing and formating, allowing to write
protocol parsers (such as PCIe, TCP/IP, ...) quickly and efficiently. It
distinguishes from other Python bit-manipulation libraries by providing a
Verilog-style indexing on downwards vectors (e.g. bit_vector[5:0]). The
internal storage is the binary-formated string, which is probably the most
inefficient way to store the data. '''
def __init__(self, val=0, width=0):
self.val = bin(val)[2:].zfill(width)
def __getitem__(self, i):
if isinstance(i, int):
tmp = VerilogBits()
tmp.val = self.val[-1-i]
return tmp
elif isinstance(i, slice):
if i.stop > i.start:
raise NotImplementedError()
if i.start > len(self.val):
raise IndexError()
tmp = VerilogBits()
tmp.val = self.val[::-1][i.stop:i.start+1][::-1]
return tmp
def __str__(self):
return self.bin_str()
def __repr__(self):
return self.bin_str()
def __eq__(self, other):
return self.val == other.val
def to_int(self):
''' Converts VerilogBits to int '''
return int(self.val, 2)
def bin_str(self):
''' Provides Verilog-style binary representation '''
return str(len(self.val)) + "'b" + self.val
def hex_str(self):
''' Provides Verilog-style hexadecimal representation '''
width = len(self.val)
return ("{0}'h{1:0"+str(width//4)+"X}").format(width, self.to_int())
def dec_str(self):
''' Provides Verilog-style decimal representation '''
return ("{0}'d{1:d}").format(len(self.val), self.to_int())
class TestVerilogBits(unittest.TestCase):
def test_equality(self):
self.assertEqual(VerilogBits(0xAB), VerilogBits(0xAB))
self.assertEqual(VerilogBits(0xAB), VerilogBits(0x0AB))
self.assertNotEqual(VerilogBits(0xAB), VerilogBits(0xCD))
def test_slicing(self):
ab = VerilogBits(0xAB)
self.assertEqual(ab[7:4], VerilogBits(0xA))
self.assertEqual(ab[3:0], VerilogBits(0xB))
def test_unpack(self):
abcd = VerilogBits(0xABCD)
a, b, c, d = abcd[15:12], abcd[11:8], abcd[7:4], abcd[3:0]
self.assertEqual(a, VerilogBits(0xA))
self.assertEqual(b, VerilogBits(0xB))
self.assertEqual(c, VerilogBits(0xC))
self.assertEqual(d, VerilogBits(0xD))
def test_slice_up_vect(self):
with self.assertRaises(NotImplementedError):
dummy = VerilogBits(0xAB)[0:7]
def test_invalid_slice(self):
with self.assertRaises(IndexError):
dummy = VerilogBits(0xAB)[9:0]
def test_hex_str(self):
self.assertEqual(VerilogBits(0xAB).hex_str(), "8'hAB")
self.assertEqual(VerilogBits(0x00, 8).hex_str(), "8'h00")
def test_dec_str(self):
self.assertEqual(VerilogBits(0xAB).dec_str(), "8'd171")
self.assertEqual(VerilogBits(0x00, 8).dec_str(), "8'd0")
def test_to_int(self):
self.assertEqual(VerilogBits(0x0000, 16).to_int(), 0)
self.assertEqual(VerilogBits(0xAB).to_int(), 171)
if __name__ == '__main__':
unittest.main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment