Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added gatemate vendor and Updated init file #1460

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions amaranth/vendor/__init__.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
__all__ = [
"AlteraPlatform",
"AMDPlatform",
"GateMatePlatform"
"GowinPlatform",
"IntelPlatform",
"LatticeECP5Platform",
Expand All @@ -27,6 +28,9 @@ def __getattr__(name):
if name in ("AlteraPlatform", "IntelPlatform"):
from ._altera import AlteraPlatform
return AlteraPlatform
if name == "GateMatePlatform":
from ._gatemate import GateMatePlatform
return GateMatePlatform
whitequark marked this conversation as resolved.
Show resolved Hide resolved
if name == "GowinPlatform":
from ._gowin import GowinPlatform
return GowinPlatform
Expand Down
95 changes: 95 additions & 0 deletions amaranth/vendor/_gatemate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
from abc import abstractmethod
from amaranth import *
from amaranth.build import *
from amaranth.lib.cdc import ResetSynchronizer



__all__ = ["GateMatePlatform"]

whitequark marked this conversation as resolved.
Show resolved Hide resolved


class GateMatePlatform(TemplatedPlatform):
"""

Required tools:
* ``yosys``
* ``p_r``

The environment is populated by running the script specified in the environment variable
``AMARANTH_ENV_GATEMATE``, if present.
"""

device = property(abstractmethod(lambda: None))
package = property(abstractmethod(lambda: None))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized that nothing in the platform file is using these variables. In that case they should be removed.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deleted those lines


toolchain = "GateMate"

required_tools = [
"yosys",
"p_r",
]

file_templates = {
**TemplatedPlatform.build_script_templates,
"{{name}}.v": r"""
/* {{autogenerated}} */
{{emit_verilog()}}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For a Yosys-based platform, you should output a .il file, not a .v one.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

        "{{name}}.il": r"""
            # {{autogenerated}}
            {{emit_rtlil()}}
        """,

Instead of

        "{{name}}.v": r"""
            /* {{autogenerated}} */
            {{emit_verilog()}}
        """,

""",
"{{name}}.debug.v": r"""
/* {{autogenerated}} */
{{emit_debug_verilog()}}
""",
"{{name}}.ys": r"""
# {{autogenerated}}
{% for file in platform.iter_files(".v") -%}
read -sv {{get_override("read_verilog_opts")|options}} {{file}}
{% endfor %}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't right: you should not be reading .v files in SystemVerilog mode. You should copy this part from e.g. SiliconBlue platform.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After reading all user-provided files, you should read the top-level .il file you should write above. This can again be copied from SiliconBlue essentially as-is.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The .ys script is now:

"{{name}}.ys": r"""
            # {{autogenerated}}
            {% for file in platform.iter_files(".v") -%}
                read_verilog {{get_override("read_verilog_opts")|options}} {{file}}
            {% endfor %}
            {% for file in platform.iter_files(".sv") -%}
                read_verilog -sv {{get_override("read_verilog_opts")|options}} {{file}}
            {% endfor %}
            {% for file in platform.iter_files(".il") -%}
                read_ilang {{file}}
            {% endfor %}
            read_ilang {{name}}.il
            {{get_override("script_after_read")|default("# (script_after_read placeholder)")}}
            synth_gatemate {{get_override("synth_opts")|options}} -top {{name}} -vlog {{name}}_synth.v
            {{get_override("script_after_synth")|default("# (script_after_synth placeholder)")}}
        """,

In the documentation provided here:
image
There is an option to write json, but is supported for a future release of the p_r tool with nextpnr that is planned next year.

Copy link
Author

@TarikHamedovic TarikHamedovic Jul 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The command_template for yosys is the same for the one in SilliconBlue:

        r"""
        {{invoke_tool("yosys")}}
            {{quiet("-q")}}
            {{get_override("yosys_opts")|options}}
            -l {{name}}.rpt
            {{name}}.ys
        """,

But running the code for my Blinky example I get this:

python3 Blinky.py -b -p amaranth_boards.gatemate_a1_evb.GateMate_A1_EVB
ERROR: Module `top' not found!
Traceback (most recent call last):
  File "/home/user/FPGA/tools/amaranth/examples/gatemate/Blinky.py", line 125, in <module>
    plat.build(Blinky(num_leds, clock_divider), do_program=do_program)
  File "/home/user/FPGA/tools/amaranth/amaranth/build/plat.py", line 103, in build
    products = plan.execute_local(build_dir)
  File "/home/user/FPGA/tools/amaranth/amaranth/build/run.py", line 118, in execute_local
    subprocess.check_call(["sh", f"{self.script}.sh"],
  File "/usr/lib/python3.10/subprocess.py", line 369, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['sh', 'build_top.sh']' returned non-zero exit status 1.

The top.ys script is given below:

# Automatically generated by Amaranth 0.6.0.dev13. Do not edit.
# (script_after_read placeholder)
synth_gatemate  -top top -vlog top_synth.v
# (script_after_synth placeholder)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, at the moment -vlog is the correct one.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But running the code for my Blinky example I get this:

That is odd. If you push your changes I can look into it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed the changes.

Copy link
Author

@TarikHamedovic TarikHamedovic Jul 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added my Blinky.py example aswell in examples for now so you can see.
Will delete later.
The command is

 python3 Blinky.py -b -p amaranth_boards.gatemate_a1_evb.GateMate_A1_EVB 

{{get_override("script_after_read")|default("# (script_after_read placeholder)")}}
synth_gatemate {{get_override("synth_opts")|options}} -top {{name}} -vlog {{name}}_synth.v
{{get_override("script_after_synth")|default("# (script_after_synth placeholder)")}}
""",
"{{name}}.ccf": r"""
# {{autogenerated}}
{% for port_name, pin_name, attrs in platform.iter_port_constraints_bits() -%}
Net "{{port_name}}" Loc = "{{pin_name}}"
{%- for constraint, value in attrs.items() -%}
| {{constraint}}={{value}}
{%- endfor -%};
{% endfor %}
""",
"{{name}}.sdc": r"""
# {{autogenerated}}
{% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no iter_clock_constraints function in the main branch (you can grep it with zero hits), how did you test sdc generation functionality?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't test the .sdc function, to be honest. I based this part of the on the _quicklogic.py vendor.

What do I need to do here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to make sure that a clock constraint, as specified in your board file at least, is actually applied. Whether a clock constraint is applied or not can be seen in the report of the PNR tool, in a format described in the vendor's documentation.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I searched through the documentation and couldn't find a clock constraint file anywhere.
This is the workflow.
image

I will ask a question on our github about the clock constraints

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That has a clock constraint file in the top right, as I would expect.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that is their pin constraint file, the .ccf file?

{% if port_signal is not none -%}
create_clock -period {{1000000000/frequency}} [get_ports {{port_signal.name|tcl_quote}}]
{% endif %}
{% endfor %}
""",
}

command_templates = [
r"""
{{invoke_tool("yosys")}}
{{quiet("-q")}}
{{get_override("yosys_opts")|options}}
-l {{name}}.rpt
{{name}}.ys
""",
r"""

{{invoke_tool("p_r")}}
{{verbose("-v")}}
-i {{name}}_synth.v
-o {{name}}
-ccf {{name}}.ccf
-cCP > log/impl.log
whitequark marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no log directory any more. The redirection should probably be something like this:

Suggested change
-cCP > log/impl.log
-cCP
> {{name}}.tim

The .rpt/.tim extension is something we've been using for Yosys based platforms and isn't set in stone, but it's nice to have consistency.

Copy link
Author

@TarikHamedovic TarikHamedovic Jul 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to

        r"""
        {{invoke_tool("p_r")}}
            {{verbose("-v")}}
            -i {{name}}_synth.v
            -o {{name}}
            -ccf {{name}}.ccf
            -cCP 
            > {{name}}.tim
        """,

""",
]

# Common logic

def add_clock_constraint(self, clock, frequency):
super().add_clock_constraint(clock, frequency)
clock.attrs["keep"] = "TRUE"
whitequark marked this conversation as resolved.
Show resolved Hide resolved
whitequark marked this conversation as resolved.
Show resolved Hide resolved