/ scripts / synthesize.py
synthesize.py
  1  #!/usr/bin/env python3
  2  
  3  from collections.abc import Callable
  4  import os
  5  import sys
  6  import argparse
  7  
  8  from amaranth.build import Platform
  9  from amaranth.build.res import PortGroup
 10  from amaranth import *
 11  from amaranth.lib import memory
 12  from amaranth.lib.wiring import Component, Flow, Out, connect, flipped
 13  from amaranth_types import AbstractInterface
 14  
 15  if __name__ == "__main__":
 16      parent = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 17      sys.path.insert(0, parent)
 18  
 19  
 20  from transactron.utils.dependencies import DependencyContext, DependencyManager
 21  from transactron.utils import ModuleConnector
 22  from coreblocks.params.genparams import GenParams
 23  from coreblocks.params.fu_params import FunctionalComponentParams
 24  from coreblocks.core import Core
 25  from coreblocks.func_blocks.fu.alu import ALUComponent
 26  from coreblocks.func_blocks.fu.div_unit import DivComponent
 27  from coreblocks.func_blocks.fu.mul_unit import MulComponent, MulType
 28  from coreblocks.func_blocks.fu.shift_unit import ShiftUnitComponent
 29  from coreblocks.func_blocks.fu.zbc import ZbcComponent
 30  from coreblocks.func_blocks.fu.zbs import ZbsComponent
 31  from transactron import TransactronContextElaboratable
 32  from transactron.lib import Adapter, AdapterTrans
 33  from transactron.utils.amaranth_ext.memory import MultiportXORMemory, MultiportXORILVTMemory, MultiportOneHotILVTMemory
 34  from coreblocks.peripherals.wishbone import WishboneArbiter, WishboneInterface
 35  from constants.ecp5_platforms import (
 36      ResourceBuilder,
 37      append_resources,
 38      signature_resources,
 39      make_ecp5_platform,
 40  )
 41  
 42  from coreblocks.params.configurations import *
 43  
 44  str_to_coreconfig: dict[str, CoreConfiguration] = {
 45      "basic": basic_core_config,
 46      "tiny": tiny_core_config,
 47      "full": full_core_config,
 48  }
 49  
 50  
 51  class InterfaceConnector(Elaboratable):
 52      def __init__(self, interface: AbstractInterface, name: str, number: int):
 53          self.interface = interface
 54          self.name = name
 55          self.number = number
 56  
 57      @staticmethod
 58      def with_resources(interface: AbstractInterface, name: str, number: int):
 59          connector = InterfaceConnector(interface, name, number)
 60          resources = signature_resources(interface.signature, name, number)
 61          return connector, resources
 62  
 63      def elaborate(self, platform: Platform):
 64          m = Module()
 65  
 66          pins = platform.request(self.name, self.number)
 67          assert isinstance(pins, PortGroup)
 68  
 69          for hier_name, member, v in self.interface.signature.flatten(self.interface):
 70              name = "__".join(str(x) for x in hier_name)
 71              if member.flow == Flow.Out:
 72                  m.d.comb += getattr(pins, name).o.eq(v)
 73              else:
 74                  m.d.comb += v.eq(getattr(pins, name).i)
 75  
 76          return m
 77  
 78  
 79  UnitCore = Callable[[GenParams], tuple[ResourceBuilder, Elaboratable]]
 80  
 81  
 82  class SynthesisCore(Component):
 83      wb: WishboneInterface
 84  
 85      def __init__(self, gen_params: GenParams):
 86          super().__init__({"wb": Out(WishboneInterface(gen_params.wb_params).signature)})
 87          self.gen_params = gen_params
 88  
 89      def elaborate(self, platform):
 90          m = Module()
 91  
 92          m.submodules.core = core = Core(gen_params=self.gen_params)
 93          m.submodules.wb_arbiter = wb_arbiter = WishboneArbiter(self.gen_params.wb_params, 2)
 94  
 95          connect(m, wb_arbiter.masters[0], core.wb_instr)
 96          connect(m, wb_arbiter.masters[1], core.wb_data)
 97          connect(m, flipped(self.wb), wb_arbiter.slave_wb)
 98  
 99          return m
100  
101  
102  def unit_core(gen_params: GenParams):
103      core = SynthesisCore(gen_params)
104  
105      connector, resources = InterfaceConnector.with_resources(core, "wishbone", 0)
106  
107      module = ModuleConnector(core=core, connector=connector)
108  
109      return resources, TransactronContextElaboratable(module, dependency_manager=DependencyContext.get())
110  
111  
112  def unit_fu(unit_params: FunctionalComponentParams):
113      def unit(gen_params: GenParams):
114          fu = unit_params.get_module(gen_params)
115          issue_adapter = AdapterTrans.create(fu.issue)
116          push_result_adapter = Adapter.create(fu.push_result)
117  
118          issue_connector, issue_resources = InterfaceConnector.with_resources(issue_adapter, "adapter", 0)
119          push_connector, push_resources = InterfaceConnector.with_resources(push_result_adapter, "adapter", 1)
120  
121          resources = append_resources(issue_resources, push_resources)
122  
123          module = ModuleConnector(
124              fu=fu,
125              issue_connector=issue_connector,
126              accept_connector=push_connector,
127              issue_adapter=issue_adapter,
128              accept_adapter=push_result_adapter,
129          )
130  
131          return resources, TransactronContextElaboratable(module, dependency_manager=DependencyContext.get())
132  
133      return unit
134  
135  
136  core_units = {
137      "core": unit_core,
138      "alu_basic": unit_fu(ALUComponent(zba_enable=False, zbb_enable=False, zicond_enable=False)),
139      "alu_full": unit_fu(ALUComponent(zba_enable=True, zbb_enable=True, zicond_enable=True)),
140      "mul_shift": unit_fu(MulComponent(MulType.SHIFT_MUL)),
141      "mul_sequence": unit_fu(MulComponent(MulType.SEQUENCE_MUL)),
142      "mul_pipelined": unit_fu(MulComponent(MulType.PIPELINED_MUL)),
143      "mul_recursive": unit_fu(MulComponent(MulType.RECURSIVE_MUL)),
144      "div": unit_fu(DivComponent()),
145      "shift_basic": unit_fu(ShiftUnitComponent(zbb_enable=False)),
146      "shift_full": unit_fu(ShiftUnitComponent(zbb_enable=True)),
147      "zbs": unit_fu(ZbsComponent()),
148      "zbc": unit_fu(ZbcComponent()),
149  }
150  
151  
152  memory_types = {
153      "plain": memory.Memory,
154      "xor": MultiportXORMemory,
155      "xor-ilvt": MultiportXORILVTMemory,
156      "onehot-ilvt": MultiportOneHotILVTMemory,
157  }
158  
159  
160  def synthesize(core_config: CoreConfiguration, platform: str, core: UnitCore):
161      with DependencyContext(DependencyManager()):
162          gen_params = GenParams(core_config)
163          resource_builder, module = core(gen_params)
164  
165          if platform == "ecp5":
166              make_ecp5_platform(resource_builder)().build(module)
167  
168  
169  def main():
170      parser = argparse.ArgumentParser()
171      parser.add_argument(
172          "-p",
173          "--platform",
174          default="ecp5",
175          choices=["ecp5"],
176          help="Selects platform to synthesize circuit on. Default: %(default)s",
177      )
178  
179      parser.add_argument(
180          "-c",
181          "--config",
182          default="basic",
183          help="Select core configuration. "
184          + f"Available configurations: {', '.join(str_to_coreconfig.keys())}. Default: %(default)s",
185      )
186  
187      parser.add_argument(
188          "-u",
189          "--unit",
190          default="core",
191          help="Select core unit. " + f"Available units: {', '.join(core_units.keys())}. Default: %(default)s",
192      )
193  
194      parser.add_argument(
195          "-m", "--memory", default="xor-ilvt", choices=memory_types.keys(), help="Select superscalar memory type."
196      )
197  
198      parser.add_argument(
199          "--strip-debug",
200          action="store_true",
201          help="Remove debugging signals. Default: %(default)s",
202      )
203  
204      parser.add_argument(
205          "-v",
206          "--verbose",
207          action="store_true",
208          help="Enables verbose output. Default: %(default)s",
209      )
210  
211      args = parser.parse_args()
212  
213      os.environ["AMARANTH_verbose"] = "true" if args.verbose else "false"
214  
215      if args.config not in str_to_coreconfig:
216          raise KeyError(f"Unknown config '{args.config}'")
217  
218      if args.unit not in core_units:
219          raise KeyError(f"Unknown core unit '{args.unit}'")
220  
221      config = str_to_coreconfig[args.config]
222      if args.strip_debug:
223          config = config.replace(debug_signals=False)
224  
225      config = config.replace(multiport_memory_type=memory_types[args.memory])
226  
227      synthesize(config, args.platform, core_units[args.unit])
228  
229  
230  if __name__ == "__main__":
231      main()