Source code for hdlConvertorAst.to.hdlUtils
from typing import Optional
from hdlConvertorAst.hdlAst._expr import HdlValueInt
[docs]
class Indent(object):
"""
indentation context
"""
[docs]
def __init__(self, autoIndentStream):
self.s = autoIndentStream
self.original_indent = None
def __enter__(self):
s = self.s
self.original_indent = s.indent_str
s.indent_cnt += 1
s.indent_str = s.indent_str + s.INDENT_STEP
def __exit__(self, exception_type, exception_value, traceback):
s = self.s
s.indent_cnt -= 1
s.indent_str = self.original_indent
[docs]
class UnIndent():
"""
unindentation context
"""
[docs]
def __init__(self, autoIndentStream):
self.s = autoIndentStream
self.original_indent = None
def __enter__(self):
s = self.s
self.original_indent = s.indent_str
assert s.indent_cnt > 0
s.indent_cnt -= 1
s.indent_str = s.indent_str[0:len(s.indent_str) - len(s.INDENT_STEP)]
def __exit__(self, exception_type, exception_value, traceback):
s = self.s
s.indent_cnt += 1
s.indent_str = self.original_indent
[docs]
class AutoIndentingStream():
[docs]
def __init__(self, stream, indent_step):
"""
:param stream: output stream
:param indent_step: string of indent
"""
self.INDENT_STEP = indent_step
self.stream = stream
self.requires_indent = True
self.indent_cnt = 0
self.indent_str = ""
[docs]
def write(self, s):
w = self.stream.write
if self.requires_indent and s != "\n":
w(self.indent_str)
w(s)
self.requires_indent = s.endswith("\n")
[docs]
def close(self):
self.stream.close()
[docs]
def iter_with_last(it):
# Ensure it's an iterator and get the first field
it = iter(it)
try:
prev = next(it)
except StopIteration:
return
for item in it:
# Lag by one item so I know I'm not at the end
yield False, prev
prev = item
# Last item
yield True, prev
[docs]
def to_unsigned(val: int, width: int) -> int:
if val < 0:
mask = (1 << width) - 1
return val & mask
else:
return val
[docs]
def _mask_fits_hex(width: int, vld_mask: Optional[int]):
# check bits for hex digit have all same value
if not vld_mask:
return True
while width:
m = vld_mask & 0xF
if m != 0 and m != 0xF:
return False
vld_mask >>= 4
width -= 4
assert width == 0, ("Width should have been multiple of 4", width)
return True
[docs]
def bit_string(v: int, width: int, vld_mask:Optional[int]=None):
"""
:param v: integer value of bitstring
:param width: number of bits in value
:param vld_mask: mask which has 1 for every valid bit in value
:return: HdlValueInt
"""
all_mask = (1 << width) - 1
if v < 0:
v = to_unsigned(v, width)
if vld_mask is None:
vld_mask = all_mask
# if vld_mask == 0:
# if width % 4 == 0:
# base = 16
# bit_string = "".join(["x" for _ in range(width//4)])
# else:
# base = 2
# bit_string = "".join(["x" for _ in range(width)])
widthFitsHexFormat = width % 4 == 0
if vld_mask == (1 << width) - 1:
# completely valid value
if widthFitsHexFormat:
# hex full valid
base = 16
bit_string = ("%0" + str(width // 4) + 'x') % (v)
else:
base = 2
bit_string = ("{0:0" + str(width) + 'b}').format(v)
else:
buff = []
if widthFitsHexFormat and _mask_fits_hex(width, vld_mask):
# hex with some "x"
base = 16
for i in range(width - 4, -1, -4):
mask = (1 << i)
maskNibble = vld_mask & mask
if maskNibble:
vNibble = v & mask
s = "%x" % (vNibble >> i)
assert len(s) == 1, s
else:
s = "x"
buff.append(s)
else:
# binary with some "x"
base = 2
for i in range(width - 1, -1, -1):
mask = (1 << i)
b = v & mask
if vld_mask & mask:
s = "1" if b else "0"
else:
s = "x"
buff.append(s)
bit_string = "".join(buff)
return HdlValueInt(bit_string, width, base)