olofk / fusesoc

Package manager and build abstraction tool for FPGA/ASIC development
BSD 2-Clause "Simplified" License
1.21k stars 246 forks source link

Integrate with migen & nmigen packages #424

Open FFY00 opened 4 years ago

FFY00 commented 4 years ago

I am opening this issue to investigate allowing fusesoc to integrate migen or nmigen packages. I think this is a desirable functionality by several people.

Preliminarily, are there any high-level ideas on how it should work/be implemented?

imphil commented 3 years ago

Thanks for your interest in FuseSoC. I don't know enough about migen to help out here, what's the use case you're trying to support, or the problem you're trying to solve? What would be the "user story" of such an integration?

mithro commented 3 years ago

I think there are two modes;

While both can already be done, at the moment both require a lot of manual work. They also don't take advantage of many of FuseSoC's advanced functionality and the typical very flexible configuration options that Migen cores provide.

olofk commented 3 years ago

My ideas so far: For the first case, create a generator that converts (n)migen cores to verilog and allows them to be used in a verilog flow. This would a) require a standard API in (n)migen to do the conversion and discover what options that can be configured or b) a separate generator for each (n)migen core. For b), I currently have been focusing on liteDRAM since I'm using that one already. LiteDRAM exposes today a mechanism to do configuration through a yaml file and generate. This can be easily wrapped by a FuseSoC generator

For FuseSoC cores inside of (n)migen designs my suggestion would be to have (n)migen parse core description files so that it can pick out the relevant things it needs to know about (e.g. source files, any defines that needs to be set, parameters etc)

mithro commented 3 years ago

@cr1901 was working on this recently and even had a demo somewhere?

mithro commented 3 years ago

https://github.com/cr1901/migen_uart

mithro commented 3 years ago

https://twitter.com/cr1901/status/1360809455827492865?s=20

cr1901 commented 3 years ago

Using a FuseSoC core inside a Migen design.

I essentially still do this manually, as I can't really think of a nice way to call out to fusesoc programmatically to grab the core, skip the YAML phase and use Python data structures directly for generator options, and generate the core in a reasonable build dir. Perhaps the build dir could be user supplied?

olofk commented 3 years ago

Hi @cr1901 I remember your migen_uart but I hadn't had en opportunity to look at it before. That's an excellent example! Really like that you open up for all three levels of integration. I think this will be a good reference for other migen cores.

For using a FuseSoC core inside a Migen design I hadn't thought of cores that uses generators, just regular ones where migen could pick up e.g. the file list instead of defining that manually. Point in case would be https://github.com/litex-hub/pythondata-cpu-serv where SERV is currently a submodule and the Litex wrapper somehow needs to keep the correct file list updated

cr1901 commented 3 years ago

For cores w/o generators written in (n)migen, either including it as a submodule or in-line is reasonable. I wish there were hooks in fusesoc to do the following:

  1. Running fusesoc library add, then providing a hook inside the (n)migen builder script to add the libraries to sys.path when building. This would be for cores w/o generators if one wished to not go the submodule route.
  2. The same, but can programmatically add generator args, which will emit the generated core in a suitable directory (perhaps requiring the user to specify the build dir root- I'm aware that generators use a temp dir and then are copied to the final build directory before the toolchain runs).
cr1901 commented 3 years ago

The same, but can programmatically add generator args, which will emit the generated core in a suitable directory (perhaps requiring the user to specify the build dir root- I'm aware that generators use a temp dir and then are copied to the final build directory before the toolchain runs).

To elaborate on this... consider that I want to use the migen-uart core in an nmigen design (I know the compat wrapper exists). The easiest way I've found to generate the Verilog by modifying the actual uart.py file where the UART is defined ahead of time and include the Verilog output directly. This is a bit tedious (and also wasn't my intent: the below code will eventually be removed completely):

diff --git a/uart.py b/uart.py
index 9579cde..5f3395a 100644
--- a/uart.py
+++ b/uart.py
@@ -321,6 +321,7 @@ if __name__ == "__main__":
     # run_simulation(dut, timing_tb(dut), vcd_name="timing_tb.vcd")
     # dut = CoreTB(1843200, 115200)
     # run_simulation(dut, core_tb(dut), vcd_name="core_tb.vcd")
-    m = Core(12000000, 19200)
+    m = Core(16630000, 19200)
     with open("uart.v", "w") as fp:
-        fp.write(str(verilog.convert(m, ios={m.tx, m.rx})))
+        fp.write(str(verilog.convert(m, ios={m.tx, m.rx, m.out_data, m.in_data,
+            m.wr, m.rd, m.tx_empty, m.rx_empty, m.tx_ov, m.rx_ov})))

However, it also seems tedious to create a YAML file just to have fusesoc run the generator to emit output Verilog, when I intend to use a fusesoc core within the nmigen build system. Having a hook to skip writing out the YAML file to send to the generator (or do it in-line) would be nice.