Skip to content

Elif without preceding If causes Syntax error when Elif has a complex condition #700

Open
@alanvgreen

Description

@alanvgreen

I'm getting a syntax error when using a function call that creates a signal inside an Elif.

I can understand why this kind of function call might be problematic in a Python DSL, however I'm raising a bug because this code looks like it ought to be valid. If it's breaking a rule, I'm not sure what the rule is.

from amaranth import *
from amaranth.back import verilog

class Stepper(Elaboratable):
  def __init__(self):
    self.output = Signal(3)
    self.up = Signal()
    self.down = Signal()
    self.ports = [self.output, self.up, self.output]

  def edge_detect(self, m, input):
    last = Signal()
    m.d.sync += last.eq(input)
    detected = input & ~last
    return detected

  def elaborate(self, platform):
    m = Module()
    with m.If(self.edge_detect(m, self.up)):
      m.d.sync += self.output.eq(self.output+1)
    with m.Elif(self.edge_detect(m, self.down)):
      m.d.sync += self.output.eq(self.output-1)
    return m

s = Stepper()
verilog.convert(s, name='Top', ports=s.ports)

fails with:

[/usr/local/lib/python3.7/dist-packages/amaranth/back/verilog.py](https://localhost:8080/#) in convert(elaboratable, name, platform, ports, emit_src, strip_internal_attrs, **kwargs)
     48         warnings.warn("Implicit port determination is deprecated, specify ports explictly",
     49                       DeprecationWarning, stacklevel=2)
---> 50     fragment = ir.Fragment.get(elaboratable, platform).prepare(ports=ports, **kwargs)
     51     verilog_text, name_map = convert_fragment(fragment, name, emit_src=emit_src)
     52     return verilog_text

[/usr/local/lib/python3.7/dist-packages/amaranth/hdl/ir.py](https://localhost:8080/#) in get(obj, platform)
     35                 code = obj.elaborate.__code__
     36                 obj._MustUse__used = True
---> 37                 new_obj = obj.elaborate(platform)
     38             elif hasattr(obj, "elaborate"):
     39                 warnings.warn(

[<ipython-input-20-74600c1d41a4>](https://localhost:8080/#) in elaborate(self, platform)
     19     with m.If(self.edge_detect(m, self.up)):
     20       m.d.sync += self.output.eq(self.output+1)
---> 21     with m.Elif(self.edge_detect(m, self.down)):
     22       m.d.sync += self.output.eq(self.output-1)
     23     return m

[/usr/lib/python3.7/contextlib.py](https://localhost:8080/#) in __enter__(self)
    110         del self.argElif s, self.kwds, self.func
    111         try:
--> 112             return next(self.gen)
    113         except StopIteration:
    114             raise RuntimeError("generator didn't yield") from None

[/usr/local/lib/python3.7/dist-packages/amaranth/hdl/dsl.py](https://localhost:8080/#) in Elif(self, cond)
    251         if_data = self._get_ctrl("If")
    252         if if_data is None or if_data["depth"] != self.domain._depth:
--> 253             raise SyntaxError("Elif without preceding If")
    254         try:
    255             _outer_case, self._statements = self._statements, []

SyntaxError: Elif without preceding If

However, when the condition is calculated outside the Elif, it works

from amaranth import *
from amaranth.back import verilog

class Stepper(Elaboratable):
  def __init__(self):
    self.output = Signal(3)
    self.up = Signal()
    self.down = Signal()
    self.ports = [self.output, self.up, self.output]

  def edge_detect(self, m, input):
    last = Signal()
    m.d.sync += last.eq(input)
    detected = input & ~last
    return detected

  def elaborate(self, platform):
    m = Module()
    is_down = self.edge_detect(m, self.down)
    with m.If(self.edge_detect(m, self.up)):
      m.d.sync += self.output.eq(self.output+1)
    with m.Elif(is_down):
      m.d.sync += self.output.eq(self.output-1)
    return m

s = Stepper()
verilog.convert(s, name='Top', ports=s.ports)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions