From af51f6fe8ff1e5d0ba2b003778ca118d9c216036 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 3 Jul 2019 18:51:45 +0800 Subject: [PATCH] use nmigen build system, upstream yosys, reorganize --- default.nix | 51 ++-- eda/symbiflow.nix | 15 -- eda/vivado.nix | 55 ++--- eda/yosys.nix | 78 ------- eda/yosys_726.patch | 399 -------------------------------- examples/helloworld_ecp5.nix | 30 +-- examples/helloworld_ecp5.py | 18 +- examples/helloworld_kintex7.nix | 50 +--- examples/helloworld_kintex7.py | 18 +- examples/simplesoc_ecp5.nix | 32 +-- examples/simplesoc_ecp5.py | 39 ++-- release.nix | 2 +- 12 files changed, 106 insertions(+), 681 deletions(-) delete mode 100644 eda/symbiflow.nix delete mode 100644 eda/yosys.nix delete mode 100644 eda/yosys_726.patch diff --git a/default.nix b/default.nix index 4711beb..4ec561a 100644 --- a/default.nix +++ b/default.nix @@ -1,34 +1,27 @@ { pkgs }: rec { - drvs = rec { - yosys = pkgs.callPackage ./eda/yosys.nix {}; - symbiyosys = pkgs.symbiyosys.override { inherit yosys; }; - nmigen = pkgs.callPackage ./eda/nmigen.nix { inherit yosys; }; - nmigen-boards = pkgs.callPackage ./eda/nmigen-boards.nix { inherit nmigen; }; - scala-spinalhdl = pkgs.callPackage ./eda/scala-spinalhdl.nix {}; + vivado = import ./eda/vivado.nix { inherit pkgs; }; + nmigen = pkgs.callPackage ./eda/nmigen.nix { }; + nmigen-boards = pkgs.callPackage ./eda/nmigen-boards.nix { inherit nmigen; }; + scala-spinalhdl = pkgs.callPackage ./eda/scala-spinalhdl.nix {}; - jtagtap = pkgs.callPackage ./cores/jtagtap.nix { inherit nmigen; }; - minerva = pkgs.callPackage ./cores/minerva.nix { inherit nmigen; inherit jtagtap; }; - vexriscv-small = pkgs.callPackage ./cores/vexriscv.nix { - inherit scala-spinalhdl; - name = "vexriscv-small"; - scalaToRun = "vexriscv.demo.GenSmallAndProductive"; - }; - litex = pkgs.callPackage ./cores/litex.nix { inherit nmigen; }; - litedram = pkgs.callPackage ./cores/litedram.nix { inherit litex; }; - - heavycomps = pkgs.callPackage ./heavycomps.nix { inherit nmigen; }; - - binutils-riscv32 = pkgs.callPackage ./compilers/binutils.nix { platform = "riscv32"; }; - gcc-riscv32 = pkgs.callPackage ./compilers/gcc.nix { platform = "riscv32"; platform-binutils = binutils-riscv32; }; - binutils-riscv64 = pkgs.callPackage ./compilers/binutils.nix { platform = "riscv64"; }; - gcc-riscv64 = pkgs.callPackage ./compilers/gcc.nix { platform = "riscv64"; platform-binutils = binutils-riscv64; }; - rust-riscv32i-crates = pkgs.callPackage ./compilers/rust-riscv32i-crates.nix { }; - - fw-helloworld = pkgs.callPackage ./firmware { inherit rust-riscv32i-crates binutils-riscv32; }; - }; - lib = { - symbiflow = import ./eda/symbiflow.nix { inherit pkgs; inherit (drvs) yosys; }; - vivado = import ./eda/vivado.nix { inherit pkgs; }; + jtagtap = pkgs.callPackage ./cores/jtagtap.nix { inherit nmigen; }; + minerva = pkgs.callPackage ./cores/minerva.nix { inherit nmigen; inherit jtagtap; }; + vexriscv-small = pkgs.callPackage ./cores/vexriscv.nix { + inherit scala-spinalhdl; + name = "vexriscv-small"; + scalaToRun = "vexriscv.demo.GenSmallAndProductive"; }; + litex = pkgs.callPackage ./cores/litex.nix { inherit nmigen; }; + litedram = pkgs.callPackage ./cores/litedram.nix { inherit litex; }; + + heavycomps = pkgs.callPackage ./heavycomps.nix { inherit nmigen; }; + + binutils-riscv32 = pkgs.callPackage ./compilers/binutils.nix { platform = "riscv32"; }; + gcc-riscv32 = pkgs.callPackage ./compilers/gcc.nix { platform = "riscv32"; platform-binutils = binutils-riscv32; }; + binutils-riscv64 = pkgs.callPackage ./compilers/binutils.nix { platform = "riscv64"; }; + gcc-riscv64 = pkgs.callPackage ./compilers/gcc.nix { platform = "riscv64"; platform-binutils = binutils-riscv64; }; + rust-riscv32i-crates = pkgs.callPackage ./compilers/rust-riscv32i-crates.nix { }; + + fw-helloworld = pkgs.callPackage ./firmware { inherit rust-riscv32i-crates binutils-riscv32; }; } diff --git a/eda/symbiflow.nix b/eda/symbiflow.nix deleted file mode 100644 index 3286242..0000000 --- a/eda/symbiflow.nix +++ /dev/null @@ -1,15 +0,0 @@ -{ pkgs, yosys }: -{ - buildBitstream = { name, src }: - pkgs.stdenv.mkDerivation { - inherit name src; - phases = [ "buildPhase" ]; - buildPhase = - '' - mkdir $out - ${yosys}/bin/yosys -p "read_ilang $src/top.il; synth_ecp5 -top top -nomux -json $out/top.json" - ${pkgs.nextpnr}/bin/nextpnr-ecp5 --json $out/top.json --textcfg $out/top.config `cat $src/device` --lpf $src/top.lpf --freq 100 - ${pkgs.trellis}/bin/ecppack --svf-rowsize 100000 --svf $out/top.svf $out/top.config $out/top.bit - ''; - }; -} diff --git a/eda/vivado.nix b/eda/vivado.nix index 3addc1d..77a21c5 100644 --- a/eda/vivado.nix +++ b/eda/vivado.nix @@ -1,37 +1,24 @@ # Install Vivado in /opt and add to /etc/nixos/configuration.nix: # nix.sandboxPaths = ["/opt"]; -{ pkgs }: -let - vivadoEnv = pkgs.buildFHSUserEnv { - name = "vivado-env"; - targetPkgs = pkgs: ( - with pkgs; [ - ncurses5 - zlib - libuuid - xorg.libSM - xorg.libICE - xorg.libXrender - xorg.libX11 - xorg.libXext - xorg.libXtst - xorg.libXi - ] - ); - }; -in - { - buildBitstream = { name, src, vivadoPath ? "/opt/Xilinx/Vivado/2018.3" }: - pkgs.stdenv.mkDerivation { - inherit name src; - phases = [ "buildPhase" ]; - buildPhase = - '' - cp --no-preserve=mode,ownership -R $src/* . - ${vivadoEnv}/bin/vivado-env -c "source ${vivadoPath}/settings64.sh && vivado -mode batch -source top.tcl" - mkdir $out - cp *.dcp *.rpt *.bit $out - ''; - }; - } +{ pkgs, vivadoPath ? "/opt/Xilinx/Vivado/2018.3" }: + +pkgs.buildFHSUserEnv { + name = "vivado"; + targetPkgs = pkgs: ( + with pkgs; [ + ncurses5 + zlib + libuuid + xorg.libSM + xorg.libICE + xorg.libXrender + xorg.libX11 + xorg.libXext + xorg.libXtst + xorg.libXi + ] + ); + profile = "source ${vivadoPath}/settings64.sh"; + runScript = "vivado"; +} diff --git a/eda/yosys.nix b/eda/yosys.nix deleted file mode 100644 index fe38d8f..0000000 --- a/eda/yosys.nix +++ /dev/null @@ -1,78 +0,0 @@ -{ stdenv, fetchFromGitHub -, pkgconfig, bison, flex -, tcl, readline, libffi, python3 -, protobuf -}: - -with builtins; - -stdenv.mkDerivation rec { - name = "yosys-${version}"; - version = "2019.04.27hx"; - - srcs = [ - (fetchFromGitHub { - owner = "yosyshq"; - repo = "yosys"; - rev = "ea0e0722bb42254ac8c63eb41664d9dfb7973aec"; - sha256 = "1sq9a1h651is9wq8sq4kb4n8v4d91fmdc7g01nrxj1vk1nji8308"; - name = "yosys"; - }) - - # NOTE: the version of abc used here is synchronized with - # the one in the yosys Makefile of the version above; - # keep them the same for quality purposes. - (fetchFromGitHub { - owner = "berkeley-abc"; - repo = "abc"; - rev = "3709744c60696c5e3f4cc123939921ce8107fe04"; - sha256 = "18a9cjng3qfalq8m9az5ck1y5h4l2pf9ycrvkzs9hn82b1j7vrax"; - name = "yosys-abc"; - }) - ]; - sourceRoot = "yosys"; - - enableParallelBuilding = true; - nativeBuildInputs = [ pkgconfig ]; - buildInputs = [ tcl readline libffi python3 bison flex protobuf ]; - - makeFlags = [ "ENABLE_PROTOBUF=1" ]; - - patchPhase = '' - patch -p1 < ${./yosys_726.patch} - substituteInPlace ../yosys-abc/Makefile \ - --replace 'CC := gcc' "" - substituteInPlace ./Makefile \ - --replace 'CXX = clang' "" \ - --replace 'ABCMKARGS = CC="$(CXX)"' 'ABCMKARGS =' \ - --replace 'echo UNKNOWN' 'echo ${substring 0 10 (elemAt srcs 0).rev}' - ''; - - preBuild = '' - chmod -R u+w ../yosys-abc - ln -s ../yosys-abc abc - make config-${if stdenv.cc.isClang or false then "clang" else "gcc"} - echo 'ABCREV := default' >> Makefile.conf - makeFlags="PREFIX=$out $makeFlags" - - # we have to do this ourselves for some reason... - (cd misc && ${protobuf}/bin/protoc --cpp_out ../backends/protobuf/ ./yosys.proto) - ''; - - meta = { - description = "Framework for RTL synthesis tools"; - longDescription = '' - Yosys is a framework for RTL synthesis tools. It currently has - extensive Verilog-2005 support and provides a basic set of - synthesis algorithms for various application domains. - Yosys can be adapted to perform any synthesis job by combining - the existing passes (algorithms) using synthesis scripts and - adding additional passes as needed by extending the yosys C++ - code base. - ''; - homepage = http://www.clifford.at/yosys/; - license = stdenv.lib.licenses.isc; - maintainers = with stdenv.lib.maintainers; [ shell thoughtpolice ]; - platforms = stdenv.lib.platforms.unix; - }; -} diff --git a/eda/yosys_726.patch b/eda/yosys_726.patch deleted file mode 100644 index acb79cd..0000000 --- a/eda/yosys_726.patch +++ /dev/null @@ -1,399 +0,0 @@ -diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc -index 83d83f48..ef6f102c 100644 ---- a/backends/verilog/verilog_backend.cc -+++ b/backends/verilog/verilog_backend.cc -@@ -25,6 +25,7 @@ - #include "kernel/celltypes.h" - #include "kernel/log.h" - #include "kernel/sigtools.h" -+#include "kernel/modtools.h" - #include - #include - #include -@@ -33,15 +34,17 @@ - USING_YOSYS_NAMESPACE - PRIVATE_NAMESPACE_BEGIN - --bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, defparam, decimal, siminit; -+bool verbose, norename, noattr, attr2comment, noexpr, nodec, noinline, nohex, nostr, defparam, decimal, siminit; - int auto_name_counter, auto_name_offset, auto_name_digits; - std::map auto_name_map; - std::set reg_wires, reg_ct; -+std::map proc_consumed_wires; - std::string auto_prefix; - - RTLIL::Module *active_module; - dict active_initdata; - SigMap active_sigmap; -+ModIndex active_modindex; - - void reset_auto_counter_id(RTLIL::IdString id, bool may_rename) - { -@@ -183,6 +186,72 @@ bool is_reg_wire(RTLIL::SigSpec sig, std::string ®_name) - return true; - } - -+bool can_inline_cell_expr(RTLIL::Cell *cell) -+{ -+ static pool inlinable_cells = { -+ "$not", "$pos", "$neg", -+ "$and", "$or", "$xor", "$xnor", -+ "$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool", -+ "$shl", "$shr", "$sshl", "$sshr", -+ "$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt", -+ "$add", "$sub", "$mul", "$div", "$mod", "$pow", -+ "$logic_not", "$logic_and", "$logic_or", -+ "$mux" -+ }; -+ -+ if (noinline) -+ return false; -+ -+ if (!inlinable_cells.count(cell->type)) -+ return false; -+ -+ const RTLIL::SigSpec &output = cell->getPort("\\Y"); -+ if (!output.is_wire()) -+ return false; -+ -+ RTLIL::Wire *output_wire = output.as_wire(); -+ if (output_wire->port_id || (!noattr && output_wire->attributes.size())) -+ return false; -+ -+ pool ports = active_modindex.query_ports(output[0]); -+ if (proc_consumed_wires[output_wire] == 1 && ports.size() == 1) -+ return true; -+ -+ if (proc_consumed_wires[output_wire] == 0 && ports.size() == 2) -+ { -+ auto port1 = ports.pop(); -+ auto port2 = ports.pop(); -+ return port1.cell->getPort(port1.port).size() == -+ port2.cell->getPort(port2.port).size(); -+ } -+ -+ return false; -+} -+ -+bool can_inline_wire(RTLIL::Wire *wire) -+{ -+ if (noinline) -+ return false; -+ -+ RTLIL::SigSpec wire_spec = RTLIL::SigSpec(wire); -+ if (wire_spec.empty()) -+ return false; -+ -+ pool ports = active_modindex.query_ports(wire_spec[0]); -+ if (ports.size() > 2) -+ return false; -+ -+ for (auto &port_info : ports) -+ { -+ if (port_info.cell->name[0] == '$' && port_info.port == "\\Y") -+ { -+ if (can_inline_cell_expr(port_info.cell)) -+ return true; -+ } -+ } -+ return false; -+} -+ - void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool set_signed = false, bool escape_comment = false) - { - if (width < 0) -@@ -313,13 +382,29 @@ void dump_reg_init(std::ostream &f, SigSpec sig) - } - } - -+bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell, bool do_inline); -+ - void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool no_decimal = false) - { - if (chunk.wire == NULL) { - dump_const(f, chunk.data, chunk.width, chunk.offset, no_decimal); - } else { - if (chunk.width == chunk.wire->width && chunk.offset == 0) { -- f << stringf("%s", id(chunk.wire->name).c_str()); -+ if (can_inline_wire(chunk.wire)) -+ { -+ f << "("; -+ pool ports = active_modindex.query_ports(SigSpec(chunk)[0]); -+ for (auto &port_info : ports) -+ { -+ if (port_info.port == "\\Y") -+ dump_cell_expr(f, "", port_info.cell, true); -+ } -+ f << ")"; -+ } -+ else -+ { -+ f << stringf("%s", id(chunk.wire->name).c_str()); -+ } - } else if (chunk.width == 1) { - if (chunk.wire->upto) - f << stringf("%s[%d]", id(chunk.wire->name).c_str(), (chunk.wire->width - chunk.offset - 1) + chunk.wire->start_offset); -@@ -372,6 +457,9 @@ void dump_attributes(std::ostream &f, std::string indent, dictattributes); - #if 0 - if (wire->port_input && !wire->port_output) -@@ -464,30 +552,54 @@ no_special_reg_name: - } - } - --void dump_cell_expr_uniop(std::ostream &f, std::string indent, RTLIL::Cell *cell, std::string op) -+void dump_cell_expr_uniop(std::ostream &f, std::string indent, RTLIL::Cell *cell, std::string op, bool do_inline) - { -- f << stringf("%s" "assign ", indent.c_str()); -- dump_sigspec(f, cell->getPort("\\Y")); -- f << stringf(" = %s ", op.c_str()); -+ if (!do_inline) -+ { -+ f << stringf("%s" "assign ", indent.c_str()); -+ dump_sigspec(f, cell->getPort("\\Y")); -+ f << stringf(" = "); -+ } -+ f << stringf("%s ", op.c_str()); - dump_attributes(f, "", cell->attributes, ' '); - dump_cell_expr_port(f, cell, "A", true); -- f << stringf(";\n"); -+ if (!do_inline) -+ { -+ f << stringf(";\n"); -+ } - } - --void dump_cell_expr_binop(std::ostream &f, std::string indent, RTLIL::Cell *cell, std::string op) -+void dump_cell_expr_binop(std::ostream &f, std::string indent, RTLIL::Cell *cell, std::string op, bool do_inline) - { -- f << stringf("%s" "assign ", indent.c_str()); -- dump_sigspec(f, cell->getPort("\\Y")); -- f << stringf(" = "); -+ if (!do_inline) -+ { -+ f << stringf("%s" "assign ", indent.c_str()); -+ dump_sigspec(f, cell->getPort("\\Y")); -+ f << stringf(" = "); -+ } -+ else -+ { -+ f << stringf("("); -+ } - dump_cell_expr_port(f, cell, "A", true); - f << stringf(" %s ", op.c_str()); - dump_attributes(f, "", cell->attributes, ' '); - dump_cell_expr_port(f, cell, "B", true); -- f << stringf(";\n"); -+ if (!do_inline) -+ { -+ f << stringf(";\n"); -+ } -+ else -+ { -+ f << stringf(")"); -+ } - } - --bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) -+bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell, bool do_inline) - { -+ if (can_inline_cell_expr(cell) && !do_inline) -+ return true; -+ - if (cell->type == "$_NOT_") { - f << stringf("%s" "assign ", indent.c_str()); - dump_sigspec(f, cell->getPort("\\Y")); -@@ -658,9 +770,9 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) - } - - #define HANDLE_UNIOP(_type, _operator) \ -- if (cell->type ==_type) { dump_cell_expr_uniop(f, indent, cell, _operator); return true; } -+ if (cell->type ==_type) { dump_cell_expr_uniop(f, indent, cell, _operator, do_inline); return true; } - #define HANDLE_BINOP(_type, _operator) \ -- if (cell->type ==_type) { dump_cell_expr_binop(f, indent, cell, _operator); return true; } -+ if (cell->type ==_type) { dump_cell_expr_binop(f, indent, cell, _operator, do_inline); return true; } - - HANDLE_UNIOP("$not", "~") - HANDLE_UNIOP("$pos", "+") -@@ -756,16 +868,30 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) - - if (cell->type == "$mux") - { -- f << stringf("%s" "assign ", indent.c_str()); -- dump_sigspec(f, cell->getPort("\\Y")); -- f << stringf(" = "); -+ if (!do_inline) -+ { -+ f << stringf("%s" "assign ", indent.c_str()); -+ dump_sigspec(f, cell->getPort("\\Y")); -+ f << stringf(" = "); -+ } -+ else -+ { -+ f << stringf("("); -+ } - dump_sigspec(f, cell->getPort("\\S")); - f << stringf(" ? "); - dump_attributes(f, "", cell->attributes, ' '); - dump_sigspec(f, cell->getPort("\\B")); - f << stringf(" : "); - dump_sigspec(f, cell->getPort("\\A")); -- f << stringf(";\n"); -+ if (!do_inline) -+ { -+ f << stringf(";\n"); -+ } -+ else -+ { -+ f << stringf(")"); -+ } - return true; - } - -@@ -1243,7 +1369,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) - void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) - { - if (cell->type[0] == '$' && !noexpr) { -- if (dump_cell_expr(f, indent, cell)) -+ if (dump_cell_expr(f, indent, cell, false)) - return; - } - -@@ -1400,25 +1526,42 @@ void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw - void case_body_find_regs(RTLIL::CaseRule *cs) - { - for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it) -- for (auto it2 = (*it)->cases.begin(); it2 != (*it)->cases.end(); it2++) -- case_body_find_regs(*it2); -+ { -+ for (auto &c : (*it)->signal.chunks()) -+ if (c.wire != NULL && c.offset == 0 && c.width == c.wire->width) -+ proc_consumed_wires[c.wire]++; -+ for (auto it2 = (*it)->cases.begin(); it2 != (*it)->cases.end(); it2++) -+ case_body_find_regs(*it2); -+ } - -- for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) { -+ for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) -+ { - for (auto &c : it->first.chunks()) -+ { - if (c.wire != NULL) - reg_wires.insert(c.wire->name); -+ for (auto &c : it->second.chunks()) -+ if (c.wire != NULL && c.offset == 0 && c.width == c.wire->width) -+ proc_consumed_wires[c.wire]++; -+ } - } - } - --void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, bool find_regs = false) -+void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, bool sweep = false) - { -- if (find_regs) { -+ if (sweep) { - case_body_find_regs(&proc->root_case); - for (auto it = proc->syncs.begin(); it != proc->syncs.end(); ++it) -- for (auto it2 = (*it)->actions.begin(); it2 != (*it)->actions.end(); it2++) { -- for (auto &c : it2->first.chunks()) -- if (c.wire != NULL) -- reg_wires.insert(c.wire->name); -+ { -+ for (auto it2 = (*it)->actions.begin(); it2 != (*it)->actions.end(); it2++) -+ { -+ for (auto &c : it2->first.chunks()) -+ if (c.wire != NULL) -+ reg_wires.insert(c.wire->name); -+ for (auto &c : it2->second.chunks()) -+ if (c.wire != NULL && c.offset == 0 && c.width == c.wire->width) -+ proc_consumed_wires[c.wire]++; -+ } - } - return; - } -@@ -1487,9 +1630,11 @@ void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, boo - void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module) - { - reg_wires.clear(); -+ proc_consumed_wires.clear(); - reset_auto_counter(module); - active_module = module; - active_sigmap.set(module); -+ active_modindex = ModIndex(module); - active_initdata.clear(); - - for (auto wire : module->wires()) -@@ -1575,6 +1720,7 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module) - - f << stringf("%s" "endmodule\n", indent.c_str()); - active_module = NULL; -+ active_modindex = ModIndex(); - active_sigmap.clear(); - active_initdata.clear(); - } -@@ -1605,7 +1751,12 @@ struct VerilogBackend : public Backend { - log("\n"); - log(" -noexpr\n"); - log(" without this option all internal cells are converted to Verilog\n"); -- log(" expressions.\n"); -+ log(" expressions. implies -noinline.\n"); -+ log("\n"); -+ log(" -noinline\n"); -+ log(" without this option all internal cells driving a wire connected to\n"); -+ log(" a single internal cell are inlined into that cell and the wire is\n"); -+ log(" omitted.\n"); - log("\n"); - log(" -siminit\n"); - log(" add initial statements with hierarchical refs to initialize FFs when\n"); -@@ -1662,6 +1813,7 @@ struct VerilogBackend : public Backend { - noattr = false; - attr2comment = false; - noexpr = false; -+ noinline = false; - nodec = false; - nohex = false; - nostr = false; -@@ -1723,7 +1875,11 @@ struct VerilogBackend : public Backend { - continue; - } - if (arg == "-noexpr") { -- noexpr = true; -+ noexpr = noinline = true; -+ continue; -+ } -+ if (arg == "-noinline") { -+ noinline = true; - continue; - } - if (arg == "-nodec") { -diff --git a/kernel/modtools.h b/kernel/modtools.h -index 409562eb..b198709d 100644 ---- a/kernel/modtools.h -+++ b/kernel/modtools.h -@@ -226,6 +226,10 @@ struct ModIndex : public RTLIL::Monitor - auto_reload_module = true; - } - -+ ModIndex() : module(NULL) -+ { -+ } -+ - ModIndex(RTLIL::Module *_m) : sigmap(_m), module(_m) - { - auto_reload_counter = 0; -@@ -235,7 +239,8 @@ struct ModIndex : public RTLIL::Monitor - - ~ModIndex() - { -- module->monitors.erase(this); -+ if (module) -+ module->monitors.erase(this); - } - - SigBitInfo *query(RTLIL::SigBit bit) diff --git a/examples/helloworld_ecp5.nix b/examples/helloworld_ecp5.nix index 7cca97b..7fe1a29 100644 --- a/examples/helloworld_ecp5.nix +++ b/examples/helloworld_ecp5.nix @@ -1,25 +1,11 @@ { pkgs, hx }: -let - symbiflowInput = pkgs.runCommand "helloworld-symbiflow-input" { - buildInputs = [ (pkgs.python3.withPackages(ps: [hx.drvs.nmigen hx.drvs.heavycomps])) hx.drvs.yosys ]; - } - '' - mkdir $out - - python ${./helloworld_ecp5.py} > $out/top.il - - cat > $out/top.lpf << EOF - LOCATE COMP "clk100" SITE "P3"; - IOBUF PORT "clk100" IO_TYPE=LVDS; - LOCATE COMP "serial_tx" SITE "A11"; - IOBUF PORT "serial_tx" IO_TYPE=LVCMOS33; - EOF - - echo -n "--um-45k --speed 8 --package CABGA381" > $out/device - ''; -in - hx.lib.symbiflow.buildBitstream { - name = "helloworld-bitstream"; - src = symbiflowInput; +pkgs.runCommand "helloworld-bitstream" { + buildInputs = [ (pkgs.python3.withPackages(ps: [hx.nmigen hx.nmigen-boards hx.heavycomps])) pkgs.yosys ]; } + '' + export YOSYS=${pkgs.yosys}/bin/yosys + export NEXTPNR_ECP5=${pkgs.nextpnr}/bin/nextpnr-ecp5 + export ECPPACK=${pkgs.trellis}/bin/ecppack + python ${./helloworld_ecp5.py} $out + '' diff --git a/examples/helloworld_ecp5.py b/examples/helloworld_ecp5.py index dd0f4a8..ba22ebd 100644 --- a/examples/helloworld_ecp5.py +++ b/examples/helloworld_ecp5.py @@ -1,5 +1,7 @@ +import argparse + from nmigen import * -from nmigen.back import rtlil +from nmigen_boards.versa_ecp5 import VersaECP5Platform from heavycomps import uart @@ -7,15 +9,13 @@ from heavycomps import uart class Top(Elaboratable): def __init__(self, baudrate=115200): self.baudrate = baudrate - self.clk100 = Signal() - self.serial_tx = Signal() def elaborate(self, platform): m = Module() cd_sync = ClockDomain(reset_less=True) m.domains += cd_sync - m.d.comb += cd_sync.clk.eq(self.clk100) + m.d.comb += cd_sync.clk.eq(platform.request("clk100").i) string = "Hello World!\r\n" mem = Memory(width=8, depth=len(string), @@ -29,7 +29,7 @@ class Top(Elaboratable): m.d.comb += [ tx.stb.eq(~wait), tx.data.eq(rdport.data), - self.serial_tx.eq(tx.tx) + platform.request("uart").tx.o.eq(tx.tx) ] release = Signal() @@ -49,10 +49,10 @@ class Top(Elaboratable): def main(): - top = Top() - output = rtlil.convert(Fragment.get(top, None), - ports=(top.clk100, top.serial_tx)) - print(output) + parser = argparse.ArgumentParser() + parser.add_argument("build_dir") + args = parser.parse_args() + VersaECP5Platform().build(Top(), build_dir=args.build_dir) if __name__ == "__main__": main() diff --git a/examples/helloworld_kintex7.nix b/examples/helloworld_kintex7.nix index c6add0a..e4c0d35 100644 --- a/examples/helloworld_kintex7.nix +++ b/examples/helloworld_kintex7.nix @@ -1,47 +1,9 @@ { pkgs, hx }: -let - vivadoInput = pkgs.runCommand "helloworld-vivado-input" { - buildInputs = [ (pkgs.python3.withPackages(ps: [hx.drvs.nmigen hx.drvs.heavycomps])) hx.drvs.yosys ]; - } - '' - mkdir $out - - python ${./helloworld_kintex7.py} > $out/top.v - - cat > $out/top.xdc << EOF - set_property LOC K24 [get_ports serial_tx] - set_property IOSTANDARD LVCMOS25 [get_ports serial_tx] - - set_property LOC K28 [get_ports clk156_p] - set_property IOSTANDARD LVDS_25 [get_ports clk156_p] - set_property DIFF_TERM TRUE [get_ports clk156_p] - - set_property LOC K29 [get_ports clk156_n] - set_property IOSTANDARD LVDS_25 [get_ports clk156_n] - set_property DIFF_TERM TRUE [get_ports clk156_n] - - create_clock -name clk156 -period 6.4 [get_nets clk156_p] - EOF - - cat > $out/top.tcl << EOF - create_project -force -name top -part xc7k325t-ffg900-2 - set_property XPM_LIBRARIES {XPM_CDC XPM_MEMORY} [current_project] - add_files {top.v} - set_property library work [get_files {top.v}] - read_xdc top.xdc - synth_design -top top -part xc7k325t-ffg900-2 - opt_design - place_design - route_design - set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design] - set_property BITSTREAM.GENERAL.COMPRESS True [current_design] - write_bitstream -force top.bit - quit - EOF - ''; -in - hx.lib.vivado.buildBitstream { - name = "helloworld-bitstream"; - src = vivadoInput; +pkgs.runCommand "helloworld-bitstream" { + buildInputs = [ (pkgs.python3.withPackages(ps: [hx.nmigen hx.nmigen-boards hx.heavycomps])) pkgs.yosys ]; } + '' + export VIVADO=${hx.vivado}/bin/vivado + python ${./helloworld_kintex7.py} $out + '' diff --git a/examples/helloworld_kintex7.py b/examples/helloworld_kintex7.py index 17432ac..582e44a 100644 --- a/examples/helloworld_kintex7.py +++ b/examples/helloworld_kintex7.py @@ -1,5 +1,7 @@ +import argparse + from nmigen import * -from nmigen.back import verilog +from nmigen_boards.kc705 import KC705Platform from heavycomps import uart @@ -16,8 +18,8 @@ class Top(Elaboratable): cd_sync = ClockDomain(reset_less=True) m.domains += cd_sync - m.submodules.clock = Instance("IBUFGDS", - i_I=self.clk156_p, i_IB=self.clk156_n, o_O=cd_sync.clk) + m.submodules.clock = Instance("BUFG", + i_I=platform.request("clk156").i, o_O=cd_sync.clk) string = "Hello World!\r\n" mem = Memory(width=8, depth=len(string), @@ -29,7 +31,7 @@ class Top(Elaboratable): m.d.comb += [ tx.stb.eq(1), tx.data.eq(rdport.data), - self.serial_tx.eq(tx.tx) + platform.request("uart").tx.o.eq(tx.tx) ] with m.If(tx.ack): @@ -42,10 +44,10 @@ class Top(Elaboratable): def main(): - top = Top() - output = verilog.convert(Fragment.get(top, None), - ports=(top.clk156_p, top.clk156_n, top.serial_tx)) - print(output) + parser = argparse.ArgumentParser() + parser.add_argument("build_dir") + args = parser.parse_args() + KC705Platform().build(Top(), build_dir=args.build_dir) if __name__ == "__main__": main() diff --git a/examples/simplesoc_ecp5.nix b/examples/simplesoc_ecp5.nix index 46e717e..dc8d3d9 100644 --- a/examples/simplesoc_ecp5.nix +++ b/examples/simplesoc_ecp5.nix @@ -1,27 +1,11 @@ { pkgs, hx }: -let - symbiflowInput = pkgs.runCommand "simplesoc-symbiflow-input" { - buildInputs = [ (pkgs.python3.withPackages(ps: [hx.drvs.nmigen hx.drvs.heavycomps hx.drvs.minerva])) hx.drvs.yosys ]; - } - '' - mkdir $out - - python ${./simplesoc_ecp5.py} ${hx.drvs.fw-helloworld}/helloworld.bin $out/top.il - - cat > $out/top.lpf << EOF - LOCATE COMP "clk100" SITE "P3"; - IOBUF PORT "clk100" IO_TYPE=LVDS; - LOCATE COMP "serial_tx" SITE "A11"; - IOBUF PORT "serial_tx" IO_TYPE=LVCMOS33; - LOCATE COMP "led" SITE "E16"; - IOBUF PORT "led" IO_TYPE=LVCMOS25; - EOF - - echo -n "--um-45k --speed 8 --package CABGA381" > $out/device - ''; -in - hx.lib.symbiflow.buildBitstream { - name = "simplesoc-bitstream"; - src = symbiflowInput; +pkgs.runCommand "simplesoc-bitstream" { + buildInputs = [ (pkgs.python3.withPackages(ps: [hx.nmigen hx.nmigen-boards hx.heavycomps hx.minerva])) pkgs.yosys ]; } + '' + export YOSYS=${pkgs.yosys}/bin/yosys + export NEXTPNR_ECP5=${pkgs.nextpnr}/bin/nextpnr-ecp5 + export ECPPACK=${pkgs.trellis}/bin/ecppack + python ${./simplesoc_ecp5.py} ${hx.fw-helloworld}/helloworld.bin $out + '' diff --git a/examples/simplesoc_ecp5.py b/examples/simplesoc_ecp5.py index 1a1e674..af8c4a1 100644 --- a/examples/simplesoc_ecp5.py +++ b/examples/simplesoc_ecp5.py @@ -1,8 +1,10 @@ +import os import argparse import struct from nmigen import * -from nmigen.back import rtlil, pysim +from nmigen.back import pysim +from nmigen_boards.versa_ecp5 import VersaECP5Platform from heavycomps import uart, wishbone from minerva.core import Minerva @@ -27,28 +29,30 @@ class SimpleWishboneSerial(Elaboratable): class Top(Elaboratable): - def __init__(self, firmware, create_clock): - if create_clock: - self.clk100 = Signal() - self.led = Signal() - self.serial_tx = Signal() + def __init__(self, firmware, simulate): self.firmware = firmware + self.simulate = simulate def elaborate(self, platform): m = Module() - if hasattr(self, "clk100"): + if self.simulate: + io_user_led = Signal() + io_uart_tx = Signal() + else: cd_sync = ClockDomain(reset_less=True) m.domains += cd_sync - m.d.comb += cd_sync.clk.eq(self.clk100) + m.d.comb += cd_sync.clk.eq(platform.request("clk100").i) + io_user_led = platform.request("user_led").o + io_uart_tx = platform.request("uart").tx.o counter = Signal(27) m.d.sync += counter.eq(counter + 1) - m.d.comb += self.led.eq(counter[-1]) + m.d.comb += io_user_led.eq(counter[-1]) m.submodules.cpu = cpu = Minerva(with_icache=False, with_dcache=False, with_muldiv=False) m.submodules.ram = ram = wishbone.SRAM(Memory(32, 1024, init=self.firmware)) - m.submodules.uart = uart = SimpleWishboneSerial(self.serial_tx, 100e6) + m.submodules.uart = uart = SimpleWishboneSerial(io_uart_tx, 100e6) m.submodules.con = con = wishbone.InterconnectShared( [cpu.ibus, cpu.dbus], [ @@ -74,23 +78,22 @@ def main(): parser = argparse.ArgumentParser() parser.add_argument("--simulate", action="store_true") parser.add_argument("firmware_bin") - parser.add_argument("output_file") + parser.add_argument("build_dir") args = parser.parse_args() firmware = read_firmware(args.firmware_bin) - top = Top(firmware, create_clock=not args.simulate) + top = Top(firmware, args.simulate) if args.simulate: + os.makedirs(args.build_dir, exist_ok=True) with pysim.Simulator(top, - vcd_file=open(args.output_file + ".vcd", "w"), - gtkw_file=open(args.output_file + ".gtkw", "w")) as sim: + vcd_file=open(os.path.join(args.build_dir, "simplesoc.vcd"), "w"), + gtkw_file=open(os.path.join(args.build_dir, "simplesoc.gtkw"), "w")) as sim: sim.add_clock(1e-6) sim.run_until(1000e-6, run_passive=True) else: - output = rtlil.convert(Fragment.get(top, None), - ports=(top.clk100, top.led, top.serial_tx)) - with open(args.output_file, "w") as f: - f.write(output) + VersaECP5Platform().build(top, build_dir=args.build_dir) + if __name__ == "__main__": main() diff --git a/release.nix b/release.nix index 6288962..c8823a5 100644 --- a/release.nix +++ b/release.nix @@ -2,7 +2,7 @@ let pkgs = import { overlays = [ (import ./overlay.nix) ]; }; hx = import ./default.nix { inherit pkgs; }; - jobs = hx.drvs // { + jobs = hx // { inherit (pkgs) llvm_7 rustc cargo cargo-vendor; helloworld_ecp5 = import ./examples/helloworld_ecp5.nix { inherit pkgs hx; };