1
0
mirror of https://github.com/myhdl/myhdl.git synced 2024-12-14 07:44:38 +08:00

_toVerilog.py: expanding initial_values kwarg to add 'skip_zero_mem_init' choice to skip generating initial block when all values are zero (#431)

This commit is contained in:
Josy Boelen 2024-06-11 13:48:35 +02:00 committed by GitHub
parent e356d8a589
commit 6520f32194
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 82 additions and 28 deletions

View File

@ -49,7 +49,7 @@ traceSignals -- function that enables signal tracing in a VCD file
toVerilog -- function that converts a design to Verilog toVerilog -- function that converts a design to Verilog
""" """
__version__ = "0.11.46" __version__ = "0.11.47"
class StopSimulation(Exception): class StopSimulation(Exception):

View File

@ -20,7 +20,7 @@
""" Block with the @block decorator function. """ """ Block with the @block decorator function. """
import inspect import inspect
#from functools import wraps # from functools import wraps
import functools import functools
import myhdl import myhdl
@ -34,8 +34,11 @@ from myhdl._Signal import _Signal, _isListOfSigs
from weakref import WeakValueDictionary from weakref import WeakValueDictionary
class _error: class _error:
pass pass
_error.ArgType = "%s: A block should return block or instantiator objects" _error.ArgType = "%s: A block should return block or instantiator objects"
_error.InstanceError = "%s: subblock %s should be encapsulated in a block decorator" _error.InstanceError = "%s: subblock %s should be encapsulated in a block decorator"
@ -87,15 +90,16 @@ def _getCallInfo():
return _CallInfo(name, modctxt, symdict) return _CallInfo(name, modctxt, symdict)
### I don't think this is the right place for uniqueifying the name. # ## I don't think this is the right place for uniqueifying the name.
### This seems to me to be a conversion concern, not a block concern, and # ## This seems to me to be a conversion concern, not a block concern, and
### there should not be the corresponding global state to be maintained here. # ## there should not be the corresponding global state to be maintained here.
### The name should be whatever it is, which is then uniqueified at # ## The name should be whatever it is, which is then uniqueified at
### conversion time. Perhaps this happens already (FIXME - check and fix) # ## conversion time. Perhaps this happens already (FIXME - check and fix)
### ~ H Gomersall 24/11/2017 # ## ~ H Gomersall 24/11/2017
_inst_name_set = set() _inst_name_set = set()
_name_set = set() _name_set = set()
def _uniqueify_name(proposed_name): def _uniqueify_name(proposed_name):
'''Creates a unique block name from the proposed name by appending '''Creates a unique block name from the proposed name by appending
a suitable number to the end. Every name this function returns is a suitable number to the end. Every name this function returns is
@ -140,6 +144,7 @@ class _bound_function_wrapper(object):
return _Block(self.bound_func, self, name, self.srcfile, return _Block(self.bound_func, self, name, self.srcfile,
self.srcline, *args, **kwargs) self.srcline, *args, **kwargs)
class block(object): class block(object):
def __init__(self, func): def __init__(self, func):
@ -304,14 +309,27 @@ class _Block(object):
Args: Args:
hdl (Optional[str]): Target HDL. Defaults to Verilog hdl (Optional[str]): Target HDL. Defaults to Verilog
path (Optional[str]): Destination folder. Defaults to current path (Optional[str]): Destination folder. Defaults to current
working dir. working dir.
name (Optional[str]): Module and output file name. Defaults to name (Optional[str]): Module and output file name. Defaults to
`self.mod.__name__` `self.mod.__name__`
initial_vales(Optional[bool(), str]):
Verilog: False: no initial values
True: all initial values, using initial blocks for memories
'skip_zero_mem_init': same as for `True` except no initial blocks are
generated for memories where all values are zero,
which is the default at start-up of (most or all) FPGAs
VHDL: True or False only ('skip_zero_mem_init' will be treated as `True` ...)
trace(Optional[bool]): Verilog only. Whether the testbench should trace(Optional[bool]): Verilog only. Whether the testbench should
dump all signal waveforms. Defaults to False. dump all signal waveforms. Defaults to False.
testbench (Optional[bool]): Verilog only. Specifies whether a testbench (Optional[bool]): Verilog only. Specifies whether a
testbench should be created. Defaults to True. testbench should be created. Defaults to True.
timescale(Optional[str]): Verilog only. Defaults to '1ns/10ps' timescale(Optional[str]): Verilog only. Defaults to '1ns/10ps'
""" """
@ -337,17 +355,17 @@ class _Block(object):
setattr(converter, k, v) setattr(converter, k, v)
return converter(self) return converter(self)
def config_sim(self, trace=False, **kwargs) : def config_sim(self, trace=False, **kwargs):
self._config_sim['trace'] = trace self._config_sim['trace'] = trace
if trace: if trace:
for k, v in kwargs.items() : for k, v in kwargs.items():
setattr(myhdl.traceSignals, k, v) setattr(myhdl.traceSignals, k, v)
myhdl.traceSignals(self) myhdl.traceSignals(self)
def run_sim(self, duration=None, quiet=0): def run_sim(self, duration=None, quiet=0):
if self.sim is None: if self.sim is None:
sim = self sim = self
#if self._config_sim['trace']: # if self._config_sim['trace']:
# sim = myhdl.traceSignals(self) # sim = myhdl.traceSignals(self)
self.sim = myhdl._Simulation.Simulation(sim) self.sim = myhdl._Simulation.Simulation(sim)
self.sim.run(duration, quiet) self.sim.run(duration, quiet)

View File

@ -359,13 +359,19 @@ def _writeSigDecls(f, intf, siglist, memlist):
if not m._used: if not m._used:
continue continue
# infer attributes for the case of named signals in a list # infer attributes for the case of named signals in a list
for i, s in enumerate(m.mem): for s in m.mem:
if not m._driven and s._driven: if not m._driven and s._driven:
m._driven = s._driven m._driven = s._driven
# once suffices
break
if not m._read and s._read: if not m._read and s._read:
m._read = s._read m._read = s._read
# once suffices
break
if not m._driven and not m._read: if not m._driven and not m._read:
continue continue
r = _getRangeString(m.elObj) r = _getRangeString(m.elObj)
p = _getSignString(m.elObj) p = _getSignString(m.elObj)
k = 'wire' k = 'wire'
@ -375,21 +381,23 @@ def _writeSigDecls(f, intf, siglist, memlist):
if toVerilog.initial_values and not k == 'wire': if toVerilog.initial_values and not k == 'wire':
if all([each._init == m.mem[0]._init for each in m.mem]): if all([each._init == m.mem[0]._init for each in m.mem]):
if toVerilog.initial_values == 'skip_zero_mem_init':
initialize_block_name = ('INITIALIZE_' + m.name).upper() pass
_initial_assignments = ( else:
''' initialize_block_name = ('INITIALIZE_' + m.name).upper()
initial begin: %s _initial_assignments = (
integer i; '''
for(i=0; i<%d; i=i+1) begin initial begin: %s
%s[i] = %s; integer i;
for(i=0; i<%d; i=i+1) begin
%s[i] = %s;
end
end end
end ''' % (initialize_block_name, len(m.mem), m.name,
''' % (initialize_block_name, len(m.mem), m.name, _intRepr(m.mem[0]._init)))
_intRepr(m.mem[0]._init)))
initial_assignments = ( initial_assignments = (
textwrap.dedent(_initial_assignments)) textwrap.dedent(_initial_assignments))
else: else:
val_assignments = '\n'.join( val_assignments = '\n'.join(

View File

@ -115,7 +115,8 @@ class _VerificationClass(object):
name = func.func.__name__ name = func.func.__name__
else: else:
warnings.warn( warnings.warn(
"\n analyze()/verify(): Deprecated usage: See http://dev.myhdl.org/meps/mep-114.html", "\n analyze()/verify(): Deprecated usage: See http://dev.myhdl.org/meps/mep-114.html"
f"\n Found hdl = {hdl} - func is: {func}",
stacklevel=2, stacklevel=2,
category=DeprecationWarning, category=DeprecationWarning,
) )

View File

@ -40,6 +40,22 @@ def ForLoopError2(a, out):
return logic return logic
@block
def ForLoopError3(a, out):
@instance
def logic():
while 1:
yield a
var = 0
for i in range(1, 4, -1):
if a[i] == 1:
var += 1
out.next = var
return logic
@block @block
def ForLoop1(a, out): def ForLoop1(a, out):
@ -386,6 +402,15 @@ def testForLoopError2():
assert False assert False
def testForLoopError3():
try:
analyze(LoopBench(ForLoopError3))
except ConversionError as e:
assert e.kind == _error.Requirement
else:
assert False
def testForLoop1(): def testForLoop1():
assert verify(LoopBench(ForLoop1)) == 0 assert verify(LoopBench(ForLoop1)) == 0

View File

@ -2,12 +2,13 @@ import os
path = os.path path = os.path
from random import randrange from random import randrange
from myhdl import (Signal, intbv, delay, instance) from myhdl import (block, Signal, intbv, delay, instance)
from myhdl.conversion import analyze from myhdl.conversion import analyze
from myhdl import ConversionError from myhdl import ConversionError
from myhdl.conversion._misc import _error from myhdl.conversion._misc import _error
@block
def ForLoopError1(a, out): def ForLoopError1(a, out):
@instance @instance
@ -23,6 +24,7 @@ def ForLoopError1(a, out):
return logic return logic
@block
def LoopBench(LoopTest): def LoopBench(LoopTest):
a = Signal(intbv(-1)[16:]) a = Signal(intbv(-1)[16:])
@ -43,7 +45,7 @@ def LoopBench(LoopTest):
def testForLoopError1(): def testForLoopError1():
try: try:
analyze(LoopBench, ForLoopError1) analyze(LoopBench(ForLoopError1))
except ConversionError as e: except ConversionError as e:
assert e.kind == _error.Requirement assert e.kind == _error.Requirement
else: else: