1
0
mirror of https://github.com/myhdl/myhdl.git synced 2025-01-24 21:52:56 +08:00

**Constant** signals (#423)

* Added `Constant` signal object

* Corrected *_shortversion*
ToDo: replace by single global variable in myhdl/myhdl/__init__.py

* one more *_shortversion* ...
This commit is contained in:
Josy Boelen 2023-10-19 17:00:26 +02:00 committed by GitHub
parent 4081474f75
commit 15104a0f8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 106 additions and 49 deletions

View File

@ -180,8 +180,8 @@ class _Signal(object):
self._val = deepcopy(self._init)
self._next = deepcopy(self._init)
self._name = self._driven = None
self._read = False # dont clear self._used
self._inList = False
self._read = False # dont clear self._used
self._inList = False
self._numeric = True
for s in self._slicesigs:
s._clear()
@ -268,7 +268,7 @@ class _Signal(object):
@read.setter
def read(self, val):
if not val in (True, ):
if not val in (True,):
raise ValueError('Expected value True, got "%s"' % val)
self._markRead()
@ -552,7 +552,7 @@ class _Signal(object):
def __setitem__(self, key, val):
raise TypeError("Signal object doesn't support item/slice assignment")
# continues assignment support
# continuous assignment support
def assign(self, sig):
self.driven = "wire"
@ -637,6 +637,38 @@ class _SignalWrap(object):
def apply(self):
return self.sig._apply(self.next, self.timeStamp)
class Constant(_Signal):
''' effective constants '''
def __init__(self, val=None):
super(Constant, self).__init__(val)
# override some essentials
def __repr__(self):
return "Constant(" + repr(self._val) + ")"
# there is support for the 'next' attribute
@property
def next(self):
return None
@next.setter
def next(self, val):
raise PermissionError("A 'Constant' can not be changed!")
# neither can it be driven
# support for the 'driven' attribute
@property
def driven(self):
return None
@driven.setter
def driven(self, val):
# quietly ignore?
pass
# for export
SignalType = _Signal

View File

@ -49,7 +49,7 @@ traceSignals -- function that enables signal tracing in a VCD file
toVerilog -- function that converts a design to Verilog
"""
__version__ = "0.11.42"
__version__ = "0.11.43"
class StopSimulation(Exception):
@ -139,7 +139,7 @@ class ToVHDLWarning(ConversionWarning):
# def showwarning(message, category, filename, lineno, *args):
# print("** %s: %s" % (category.__name__, message), file=sys.stderr)
#warnings.showwarning = showwarning
# warnings.showwarning = showwarning
from ._bin import bin
@ -147,7 +147,7 @@ from ._concat import concat
from ._intbv import intbv
from ._modbv import modbv
from ._join import join
from ._Signal import posedge, negedge, Signal, SignalType
from ._Signal import posedge, negedge, Signal, SignalType, Constant
from ._ShadowSignal import ConcatSignal
from ._ShadowSignal import TristateSignal
from ._simulator import now
@ -169,7 +169,6 @@ from .conversion import toVHDL
from ._tristate import Tristate
__all__ = ["bin",
"concat",
"intbv",
@ -179,6 +178,7 @@ __all__ = ["bin",
"negedge",
"Signal",
"SignalType",
"Constant",
"ConcatSignal",
"TristateSignal",
"now",

View File

@ -21,7 +21,7 @@
from types import FunctionType
from myhdl import AlwaysCombError
from myhdl._Signal import _Signal, _isListOfSigs
from myhdl._Signal import _Signal, _isListOfSigs, Constant
from myhdl._util import _isGenFunc
from myhdl._instance import _getCallInfo
from myhdl._always import _Always
@ -62,9 +62,9 @@ class _AlwaysComb(_Always):
for n in self.inputs:
s = self.symdict[n]
if isinstance(s, _Signal):
if isinstance(s, _Signal) and not isinstance(s, Constant):
senslist.append(s)
elif _isListOfSigs(s):
elif _isListOfSigs(s) and not isinstance(s[0], Constant):
senslist.extend(s)
self.senslist = tuple(senslist)
if len(self.senslist) == 0:
@ -79,4 +79,3 @@ class _AlwaysComb(_Always):
func()
yield senslist

View File

@ -43,7 +43,7 @@ from myhdl._extractHierarchy import (_HierExtr, _isMem, _getMemInfo,
_UserVhdlCode, _userCodeMap)
from myhdl._instance import _Instantiator
from myhdl._Signal import _Signal, _WaiterList, posedge, negedge
from myhdl._Signal import _Signal, _WaiterList, posedge, negedge, Constant
from myhdl._enum import EnumType, EnumItemType
from myhdl._intbv import intbv
from myhdl._modbv import modbv
@ -65,7 +65,7 @@ from myhdl.conversion._VHDLNameValidation import _nameValid, _usedNames
from myhdl import bin as tobin
_version = myhdl.__version__.replace('.', '')
_shortversion = _version.replace('dev', '')
_shortversion = _version.replace('dev', '')[:-2] # loose the subminor version number
_converting = 0
_profileFunc = None
_enumPortTypeSet = set()
@ -498,11 +498,21 @@ def _writeSigDecls(f, intf, siglist, memlist):
# the original exception
# raise ToVHDLError(_error.UndrivenSignal, s._name)
# changed to a warning and a continuous assignment to a wire
warnings.warn("%s: %s" % (_error.UndrivenSignal, s._name),
category=ToVHDLWarning
)
constwires.append(s)
print("signal %s: %s%s;" % (s._name, p, r), file=f)
if isinstance(s, Constant):
if isinstance(s._val, intbv):
if s._init:
print('constant %s: %s%s := %dX"%s" /* %s */;' % (s._name, p, r, s._nrbits, str(s._init), int(s._init)), file=f)
else:
print('constant %s: %s%s := %dX"0";' % (s._name, p, r, s._nrbits), file=f)
else:
print("constant %s: %s%s := %s;" % (s._name, p, r, "'1'" if s._init else "'0'"), file=f)
else:
warnings.warn("%s: %s" % (_error.UndrivenSignal, s._name),
category=ToVHDLWarning
)
constwires.append(s)
print("signal %s: %s%s;" % (s._name, p, r), file=f)
for m in memlist:
if not m._used:
continue
@ -520,7 +530,7 @@ def _writeSigDecls(f, intf, siglist, memlist):
p = _getTypeString(m.elObj)
t = "t_array_%s" % m.name
if not toVHDL.initial_values:
if not toVHDL.initial_values and not isinstance(m.mem[0], Constant):
val_str = ""
else:
sig_vhdl_objs = [inferVhdlObj(each) for each in m.mem]
@ -542,7 +552,10 @@ def _writeSigDecls(f, intf, siglist, memlist):
val_str = ' := (\n ' + _val_str + ')'
print("type %s is array(0 to %s-1) of %s%s;" % (t, m.depth, p, r), file=f)
print("signal %s: %s%s;" % (m.name, t, val_str), file=f)
if isinstance(m.mem[0], Constant):
print("constant %s: %s%s;" % (m.name, t, val_str), file=f)
else:
print("signal %s: %s%s;" % (m.name, t, val_str), file=f)
print(file=f)
@ -890,7 +903,7 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
lpre, lsuf = self.inferCast(node.dest.vhd, node.left.vhd)
if isinstance(node.right, ast.Name):
rpre, rsuf = self.inferCast(node.dest.vhd, node.right.vhd)
self.write("(")
self.write(lpre)
self.visit(node.left)
@ -921,13 +934,13 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
node.operand.vhd = node.vhd
self.visit(node.operand)
return
pre, suf = self.inferCast(node.vhd, node.vhdOri)
if isinstance(node.op, ast.UAdd):
op = ""
else:
op = opmap[type(node.op)]
if isinstance(node.operand, ast.Constant):
self.write("(")
self.write(op)
@ -950,13 +963,13 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
node.operand.vhd = node.vhd
self.visit(node.operand)
return
pre, suf = self.inferCast(node.vhd, node.vhdOri)
if isinstance(node.op, ast.UAdd):
op = ""
else:
op = opmap[type(node.op)]
if isinstance(node.operand, ast.Num):
self.write("(")
self.write(op)
@ -1441,7 +1454,7 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
self.mapToCase(node)
else:
self.mapToIf(node)
def visit_Match(self, node):
self.write("case ")
self.visit(node.subject)
@ -1454,7 +1467,7 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
self.dedent()
self.writeline()
self.write("end case;")
def visit_match_case(self, node):
self.writeline()
self.write("when ")
@ -1472,10 +1485,10 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
self.dedent()
def visit_MatchValue(self, node):
baseobj = self.getObj(node.subject)
baseobj = self.getObj(node.subject)
item = node.value
obj = self.getObj(item)
if isinstance(obj, EnumItemType):
itemRepr = obj._toVHDL()
elif hasattr(baseobj, '_nrbits'):
@ -1506,12 +1519,12 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
self.write("others")
else:
raise AssertionError("Unknown name %s or pattern %s" % (node.name, node.pattern))
def visit_MatchOr(self, node):
for i, pattern in enumerate(node.patterns):
pattern.subject = node.subject
self.visit(pattern)
if not i == len(node.patterns)-1:
if not i == len(node.patterns) - 1:
self.write(" | ")
def mapToCase(self, node):

View File

@ -20,7 +20,7 @@
import myhdl
_version = myhdl.__version__.replace('.', '')
_shortversion = _version.replace('dev', '')
_shortversion = _version.replace('dev', '')[:-2]
_package = """\
library ieee;
@ -191,4 +191,4 @@ package body pck_myhdl_%(version)s is
end pck_myhdl_%(version)s;
""" % {'version' : _shortversion}
""" % {'version': _shortversion}

View File

@ -45,7 +45,7 @@ from myhdl.conversion._misc import (_error, _kind, _context,
_ConversionMixin, _Label, _genUniqueSuffix, _isConstant)
from myhdl.conversion._analyze import (_analyzeSigs, _analyzeGens, _analyzeTopFunc,
_Ram, _Rom)
from myhdl._Signal import _Signal
from myhdl._Signal import _Signal, Constant
from myhdl._ShadowSignal import _TristateSignal, _TristateDriver
from myhdl._block import _Block
@ -340,14 +340,20 @@ def _writeSigDecls(f, intf, siglist, memlist):
print("%s %s%s%s = %s;" %
(k, p, r, s._name, _intRepr(s._init)), file=f)
elif s._read:
# the original exception
# raise ToVerilogError(_error.UndrivenSignal, s._name)
# changed to a warning and a continuous assignment to a wire
warnings.warn("%s: %s" % (_error.UndrivenSignal, s._name),
category=ToVerilogWarning
)
constwires.append(s)
print("wire %s%s;" % (r, s._name), file=f)
if isinstance(s, Constant):
c = int(s.val)
c_len = s._nrbits
c_str = "%s" % c
print("localparam %s%s = %s'd%s;" % (r, s._name, c_len, c_str), file=f)
else:
# the original exception
# raise ToVerilogError(_error.UndrivenSignal, s._name)
# changed to a warning and a continuous assignment to a wire
warnings.warn("%s: %s" % (_error.UndrivenSignal, s._name),
category=ToVerilogWarning
)
constwires.append(s)
print("wire %s%s;" % (r, s._name), file=f)
# print(file=f)
for m in memlist:
if not m._used:
@ -392,9 +398,16 @@ def _writeSigDecls(f, intf, siglist, memlist):
for n, each in enumerate(m.mem)])
initial_assignments = (
'initial begin\n' + val_assignments + '\nend')
print("%s %s%s%s [0:%s-1];" % (k, p, r, m.name, m.depth), file=f)
else:
# can assume it is a localparam array
# build the initial values list
vals = []
w = m.mem[0]._nrbits
for s in m.mem:
vals.append('{}\'d{}'.format(w, _intRepr(s._init)))
print("%s %s%s%s [0:%s-1];" % (k, p, r, m.name, m.depth),
file=f)
print('localparam {} {} {} [0:{}-1] = {{{}}};'.format(p, r, m.name, m.depth, ', '.join(vals)), file=f)
if initial_assignments is not None:
print(initial_assignments, file=f)
@ -1100,11 +1113,11 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
self.write("default")
else:
raise AssertionError("Unknown name %s or pattern %s" % (node.name, node.pattern))
def visit_MatchOr(self, node):
for i, pattern in enumerate(node.patterns):
self.visit(pattern)
if not i == len(node.patterns)-1:
if not i == len(node.patterns) - 1:
self.write(" | ")
def mapToCase(self, node, *args):

View File

@ -15,7 +15,7 @@ from myhdl._block import _Block
_version = myhdl.__version__.replace('.', '')
# strip 'dev' for version
_version = _version.replace('dev', '')
_version = _version.replace('dev', '')[:-2]
_simulators = {}

View File

@ -7,7 +7,7 @@ from myhdl import (block, Signal, intbv, always, toVHDL, toVerilog)
from myhdl import __version__
_version = __version__.replace('.', '')
_shortversion = _version.replace('dev', '')
_shortversion = _version.replace('dev', '')[:-2]
@block