Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: amaranth-lang/amaranth
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 599615ee3a34
Choose a base ref
...
head repository: amaranth-lang/amaranth
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: ac13a5b3c92d
Choose a head ref
  • 1 commit
  • 3 files changed
  • 1 contributor

Commits on Dec 11, 2021

  1. sim._pyrtl: reject very large values.

    A check that rejects very large wires already exists in back.rtlil
    because they cause performance and correctness issues with Verilog
    tooling. Similar performance issues exist with the Python simulator.
    
    This commit also adjusts back.rtlil to use the OverflowError
    exception, same as in sim._pyrtl.
    
    Fixes #588.
    whitequark committed Dec 11, 2021
    Copy the full SHA
    ac13a5b View commit details
Showing with 31 additions and 10 deletions.
  1. +3 −7 amaranth/back/rtlil.py
  2. +17 −3 amaranth/sim/_pyrtl.py
  3. +11 −0 tests/test_sim.py
10 changes: 3 additions & 7 deletions amaranth/back/rtlil.py
Original file line number Diff line number Diff line change
@@ -9,10 +9,6 @@
__all__ = ["convert", "convert_fragment"]


class ImplementationLimit(Exception):
pass


_escape_map = str.maketrans({
"\"": "\\\"",
"\\": "\\\\",
@@ -143,9 +139,9 @@ def wire(self, width, port_id=None, port_kind=None, name=None, attrs={}, src="")
# bits. In practice, wires larger than 2**16 bits, although accepted, cause performance
# problems without an immediately visible cause, so conservatively limit wire size.
if width > 2 ** 16:
raise ImplementationLimit("Wire created at {} is {} bits wide, which is unlikely to "
"synthesize correctly"
.format(src or "unknown location", width))
raise OverflowError("Wire created at {} is {} bits wide, which is unlikely to "
"synthesize correctly"
.format(src or "unknown location", width))

self._attributes(attrs, src=src, indent=1)
name = self._make_name(name, local=False)
20 changes: 17 additions & 3 deletions amaranth/sim/_pyrtl.py
Original file line number Diff line number Diff line change
@@ -70,6 +70,19 @@ class _ValueCompiler(ValueVisitor, _Compiler):
"zmod": lambda lhs, rhs: 0 if rhs == 0 else lhs % rhs,
}

def on_value(self, value):
# Very large values are unlikely to compile or simulate in reasonable time.
if len(value) > 2 ** 16:
if value.src_loc:
src = "{}:{}".format(*value.src_loc)
else:
src = "unknown location"
raise OverflowError("Value defined at {} is {} bits wide, which is unlikely to "
"simulate in reasonable time"
.format(src, len(value)))

return super().on_value(value)

def on_ClockSignal(self, value):
raise NotImplementedError # :nocov:

@@ -332,14 +345,15 @@ def on_statements(self, stmts):
self.emitter.append("pass")

def on_Assign(self, stmt):
gen_rhs = f"({(1 << len(stmt.rhs)) - 1} & {self.rhs(stmt.rhs)})"
gen_rhs_value = self.rhs(stmt.rhs) # check for oversized value before generating mask
gen_rhs = f"({(1 << len(stmt.rhs)) - 1} & {gen_rhs_value})"
if stmt.rhs.shape().signed:
gen_rhs = f"sign({gen_rhs}, {-1 << (len(stmt.rhs) - 1)})"
return self.lhs(stmt.lhs)(gen_rhs)

def on_Switch(self, stmt):
gen_test = self.emitter.def_var("test",
f"{(1 << len(stmt.test)) - 1} & {self.rhs(stmt.test)}")
gen_test_value = self.rhs(stmt.test) # check for oversized value before generating mask
gen_test = self.emitter.def_var("test", f"{(1 << len(stmt.test)) - 1} & {gen_test_value}")
for index, (patterns, stmts) in enumerate(stmt.cases.items()):
gen_checks = []
if not patterns:
11 changes: 11 additions & 0 deletions tests/test_sim.py
Original file line number Diff line number Diff line change
@@ -840,3 +840,14 @@ def test_bug_595(self):
with open(os.path.devnull, "w") as f:
with sim.write_vcd(f):
sim.run()

def test_bug_588(self):
dut = Module()
a = Signal(32)
b = Signal(32)
z = Signal(32)
dut.d.comb += z.eq(a << b)
with self.assertRaisesRegex(OverflowError,
r"^Value defined at .+?/test_sim\.py:\d+ is 4294967327 bits wide, "
r"which is unlikely to simulate in reasonable time$"):
Simulator(dut)