1
0
mirror of https://github.com/myhdl/myhdl.git synced 2025-01-24 21:52:56 +08:00
myhdl/myhdl/_ShadowSignal.py
2019-03-12 18:34:14 +02:00

336 lines
10 KiB
Python

# This file is part of the myhdl library, a Python package for using
# Python as a Hardware Description Language.
#
# Copyright (C) 2003-2015 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
""" Module that provides the ShadowSignal classes
"""
import warnings
from copy import deepcopy
from myhdl._Signal import _Signal
from myhdl._Waiter import _SignalWaiter, _SignalTupleWaiter
from myhdl._intbv import intbv
from myhdl._simulator import _siglist
from myhdl._bin import bin
# shadow signals
class _ShadowSignal(_Signal):
__slots__ = ('_waiter', )
def __init__(self, val):
_Signal.__init__(self, val)
# self._driven = True # set this in conversion analyzer
# remove next attribute assignment
@_Signal.next.setter
def next(self, val):
raise AttributeError("ShadowSignals are readonly")
class _SliceSignal(_ShadowSignal):
__slots__ = ('_sig', '_left', '_right')
def __init__(self, sig, left, right=None):
# XXX error checks
if right is None:
_ShadowSignal.__init__(self, sig[left])
else:
_ShadowSignal.__init__(self, sig[left:right])
self._sig = sig
self._left = left
self._right = right
if right is None:
gen = self._genfuncIndex()
else:
gen = self._genfuncSlice()
self._waiter = _SignalWaiter(gen)
def _genfuncIndex(self):
sig, index = self._sig, self._left
set_next = _Signal.next.fset
while 1:
set_next(self, sig[index])
yield sig
def _genfuncSlice(self):
sig, left, right = self._sig, self._left, self._right
set_next = _Signal.next.fset
while 1:
set_next(self, sig[left:right])
yield sig
def _setName(self, hdl):
if self._right is None:
if hdl == 'Verilog':
self._name = "%s[%s]" % (self._sig._name, self._left)
else:
self._name = "%s(%s)" % (self._sig._name, self._left)
else:
if hdl == 'Verilog':
self._name = "%s[%s-1:%s]" % (self._sig._name, self._left, self._right)
else:
self._name = "%s(%s-1 downto %s)" % (self._sig._name, self._left, self._right)
def _markRead(self):
self._read = True
self._sig._read = True
def _markUsed(self):
self._used = True
self._sig._used = True
def toVerilog(self):
if self._right is None:
return "assign %s = %s[%s];" % (self._name, self._sig._name, self._left)
else:
return "assign %s = %s[%s-1:%s];" % (self._name, self._sig._name, self._left, self._right)
def toVHDL(self):
if self._right is None:
return "%s <= %s(%s);" % (self._name, self._sig._name, self._left)
else:
return "%s <= %s(%s-1 downto %s);" % (self._name, self._sig._name, self._left, self._right)
class ConcatSignal(_ShadowSignal):
__slots__ = ('_args', '_sigargs', '_initval')
def __init__(self, *args):
assert len(args) >= 2
self._args = args
self._sigargs = sigargs = []
nrbits = 0
val = 0
for a in args:
if isinstance(a, intbv):
w = a._nrbits
v = a._val
elif isinstance(a, _Signal):
sigargs.append(a)
w = a._nrbits
if isinstance(a._val, intbv):
v = a._val._val
else:
v = a._val
elif isinstance(a, bool):
w = 1
v = a
elif isinstance(a, str):
w = len(a)
v = int(a, 2)
else:
raise TypeError("ConcatSignal: inappropriate argument type: %s"
% type(a))
nrbits += w
val = val << w | v & (1 << w) - 1
self._initval = val
ini = intbv(val)[nrbits:]
_ShadowSignal.__init__(self, ini)
gen = self.genfunc()
self._waiter = _SignalTupleWaiter(gen)
def genfunc(self):
set_next = _Signal.next.fset
args = self._args
sigargs = self._sigargs
nrbits = self._nrbits
newval = intbv(self._initval)[nrbits:]
while 1:
hi = nrbits
for a in args:
if isinstance(a, bool):
w = 1
else:
w = len(a)
lo = hi - w
# note: 'a in sigargs' is equivalence check, not identity
if isinstance(a, _Signal):
if isinstance(a._val, intbv):
newval[hi:lo] = a[w:]
else:
newval[hi:lo] = a
hi = lo
set_next(self, newval)
yield sigargs
def _markRead(self):
self._read = True
for s in self._sigargs:
s._markRead()
def _markUsed(self):
self._used = True
for s in self._sigargs:
s._markUsed()
def toVHDL(self):
lines = []
ini = intbv(self._initval)[self._nrbits:]
hi = self._nrbits
for a in self._args:
if isinstance(a, bool):
w = 1
else:
w = len(a)
lo = hi - w
if w == 1:
if isinstance(a, _Signal):
if a._type == bool: # isinstance(a._type , bool): <- doesn't work
lines.append("%s(%s) <= %s;" % (self._name, lo, a._name))
else:
lines.append("%s(%s) <= %s(0);" % (self._name, lo, a._name))
else:
lines.append("%s(%s) <= '%s';" % (self._name, lo, bin(ini[lo])))
else:
if isinstance(a, _Signal):
lines.append("%s(%s-1 downto %s) <= %s;" % (self._name, hi, lo, a._name))
else:
lines.append('%s(%s-1 downto %s) <= "%s";' %
(self._name, hi, lo, bin(ini[hi:lo], w)))
hi = lo
return "\n".join(lines)
def toVerilog(self):
lines = []
ini = intbv(self._initval)[self._nrbits:]
hi = self._nrbits
for a in self._args:
if isinstance(a, bool):
w = 1
else:
w = len(a)
lo = hi - w
if w == 1:
if isinstance(a, _Signal):
if a._type == bool:
lines.append("assign %s[%s] = %s;" % (self._name, lo, a._name))
else:
lines.append("assign %s[%s] = %s[0];" % (self._name, lo, a._name))
else:
lines.append("assign %s[%s] = 'b%s;" % (self._name, lo, bin(ini[lo])))
else:
if isinstance(a, _Signal):
lines.append("assign %s[%s-1:%s] = %s;" % (self._name, hi, lo, a._name))
else:
lines.append("assign %s[%s-1:%s] = 'b%s;" %
(self._name, hi, lo, bin(ini[hi:lo], w)))
hi = lo
return "\n".join(lines)
# Tristate signal
class BusContentionWarning(UserWarning):
pass
warnings.filterwarnings('always', r".*", BusContentionWarning)
# def Tristate(val, delay=None):
# """ Return a new Tristate(default or delay 0) or DelayedTristate """
# if delay is not None:
# if delay < 0:
# raise TypeError("Signal: delay should be >= 0")
# return _DelayedTristate(val, delay)
# else:
# return _Tristate(val)
def TristateSignal(val):
return _TristateSignal(val)
class _TristateSignal(_ShadowSignal):
__slots__ = ('_drivers', '_orival')
def __init__(self, val):
self._drivers = []
# construct normally to set type / size info right
_ShadowSignal.__init__(self, val)
self._orival = deepcopy(val) # keep for drivers
# reset signal values to None
self._next = self._val = self._init = None
self._waiter = _SignalTupleWaiter(self._resolve())
def driver(self):
d = _TristateDriver(self)
self._drivers.append(d)
return d
def _resolve(self):
# set_next = _ShadowSignal._set_next
senslist = self._drivers
while 1:
yield senslist
res = None
for d in senslist:
if res is None:
res = d._val
elif d._val is not None:
warnings.warn("Bus contention", category=BusContentionWarning)
res = None
break
self._next = res
_siglist.append(self)
def toVerilog(self):
lines = []
for d in self._drivers:
if d._driven:
lines.append("assign %s = %s;" % (self._name, d._name))
return "\n".join(lines)
def toVHDL(self):
lines = []
for d in self._drivers:
if d._driven:
lines.append("%s <= %s;" % (self._name, d._name))
return "\n".join(lines)
class _TristateDriver(_Signal):
__slots__ = ('_sig',)
def __init__(self, sig):
_Signal.__init__(self, sig._orival)
# reset signal values to None
self._next = self._val = self._init = None
self._sig = sig
@_Signal.next.setter
def next(self, val):
if isinstance(val, _Signal):
val = val._val
if val is None:
self._next = None
else:
# restore original value to cater for intbv handler
self._next = self._sig._orival
self._setNextVal(val)
_siglist.append(self)