Compare commits
4 Commits
68e1b1e778
...
af51f6fe8f
Author | SHA1 | Date |
---|---|---|
Sebastien Bourdeauducq | af51f6fe8f | |
Sebastien Bourdeauducq | ca293ee7cc | |
Sebastien Bourdeauducq | 5d5853d3f8 | |
Sebastien Bourdeauducq | 1c0c4cee1b |
51
default.nix
51
default.nix
|
@ -1,34 +1,27 @@
|
||||||
{ pkgs }:
|
{ pkgs }:
|
||||||
rec {
|
rec {
|
||||||
drvs = rec {
|
vivado = import ./eda/vivado.nix { inherit pkgs; };
|
||||||
yosys = pkgs.callPackage ./eda/yosys.nix {};
|
nmigen = pkgs.callPackage ./eda/nmigen.nix { };
|
||||||
symbiyosys = pkgs.symbiyosys.override { inherit yosys; };
|
nmigen-boards = pkgs.callPackage ./eda/nmigen-boards.nix { inherit nmigen; };
|
||||||
nmigen = pkgs.callPackage ./eda/nmigen.nix { inherit yosys; };
|
scala-spinalhdl = pkgs.callPackage ./eda/scala-spinalhdl.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; };
|
jtagtap = pkgs.callPackage ./cores/jtagtap.nix { inherit nmigen; };
|
||||||
minerva = pkgs.callPackage ./cores/minerva.nix { inherit nmigen; inherit jtagtap; };
|
minerva = pkgs.callPackage ./cores/minerva.nix { inherit nmigen; inherit jtagtap; };
|
||||||
vexriscv-small = pkgs.callPackage ./cores/vexriscv.nix {
|
vexriscv-small = pkgs.callPackage ./cores/vexriscv.nix {
|
||||||
inherit scala-spinalhdl;
|
inherit scala-spinalhdl;
|
||||||
name = "vexriscv-small";
|
name = "vexriscv-small";
|
||||||
scalaToRun = "vexriscv.demo.GenSmallAndProductive";
|
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; };
|
|
||||||
};
|
};
|
||||||
|
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; };
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,8 @@ python3Packages.buildPythonPackage {
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "m-labs";
|
owner = "m-labs";
|
||||||
repo = "nmigen-boards";
|
repo = "nmigen-boards";
|
||||||
rev = "bb3d6d742fb759ecf51d303942b5570f66407a6e";
|
rev = "6e0cc9d2c9c085912d5350f1f88aaa68af1e25d8";
|
||||||
sha256 = "18nsy95swr6116kaikrw5mnrzcdhlvy2i5ad2lkj11f0x8af5y7w";
|
sha256 = "1w3v0hn45hxdmfgl8px0hcc483mq3lzbhrbrgp1nar7f04b2kism";
|
||||||
};
|
};
|
||||||
|
|
||||||
propagatedBuildInputs = [ nmigen ];
|
propagatedBuildInputs = [ nmigen ];
|
||||||
|
|
|
@ -6,8 +6,8 @@ python3Packages.buildPythonPackage {
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "m-labs";
|
owner = "m-labs";
|
||||||
repo = "nmigen";
|
repo = "nmigen";
|
||||||
rev = "0ab215e5ed761a2bab07b9fe29eb8ad87eae0be9";
|
rev = "9a1048af50aa2f7b8b75260832e8849255190253";
|
||||||
sha256 = "0wwx23nldcc3gjrlz2d6d9117ghnm5c2m3jx999007s56w7vw7rz";
|
sha256 = "1f1i661wyn674hcsalmg5py2z178kqdhmfi1lwpfjz3vhgxsy0cv";
|
||||||
};
|
};
|
||||||
|
|
||||||
checkPhase = "PATH=${yosys}/bin:${symbiyosys}/bin:${yices}/bin:$PATH python -m unittest discover nmigen.test -v";
|
checkPhase = "PATH=${yosys}/bin:${symbiyosys}/bin:${yices}/bin:$PATH python -m unittest discover nmigen.test -v";
|
||||||
|
|
|
@ -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
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,37 +1,24 @@
|
||||||
# Install Vivado in /opt and add to /etc/nixos/configuration.nix:
|
# Install Vivado in /opt and add to /etc/nixos/configuration.nix:
|
||||||
# nix.sandboxPaths = ["/opt"];
|
# nix.sandboxPaths = ["/opt"];
|
||||||
|
|
||||||
{ pkgs }:
|
{ pkgs, vivadoPath ? "/opt/Xilinx/Vivado/2018.3" }:
|
||||||
let
|
|
||||||
vivadoEnv = pkgs.buildFHSUserEnv {
|
pkgs.buildFHSUserEnv {
|
||||||
name = "vivado-env";
|
name = "vivado";
|
||||||
targetPkgs = pkgs: (
|
targetPkgs = pkgs: (
|
||||||
with pkgs; [
|
with pkgs; [
|
||||||
ncurses5
|
ncurses5
|
||||||
zlib
|
zlib
|
||||||
libuuid
|
libuuid
|
||||||
xorg.libSM
|
xorg.libSM
|
||||||
xorg.libICE
|
xorg.libICE
|
||||||
xorg.libXrender
|
xorg.libXrender
|
||||||
xorg.libX11
|
xorg.libX11
|
||||||
xorg.libXext
|
xorg.libXext
|
||||||
xorg.libXtst
|
xorg.libXtst
|
||||||
xorg.libXi
|
xorg.libXi
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
};
|
profile = "source ${vivadoPath}/settings64.sh";
|
||||||
in
|
runScript = "vivado";
|
||||||
{
|
}
|
||||||
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
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
|
@ -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;
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -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 <string>
|
|
||||||
#include <sstream>
|
|
||||||
#include <set>
|
|
||||||
@@ -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<RTLIL::IdString, int> auto_name_map;
|
|
||||||
std::set<RTLIL::IdString> reg_wires, reg_ct;
|
|
||||||
+std::map<RTLIL::Wire*, int> proc_consumed_wires;
|
|
||||||
std::string auto_prefix;
|
|
||||||
|
|
||||||
RTLIL::Module *active_module;
|
|
||||||
dict<RTLIL::SigBit, RTLIL::State> 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<IdString> 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<ModIndex::PortInfo> 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<ModIndex::PortInfo> 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<ModIndex::PortInfo> 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, dict<RTLIL::IdString,
|
|
||||||
|
|
||||||
void dump_wire(std::ostream &f, std::string indent, RTLIL::Wire *wire)
|
|
||||||
{
|
|
||||||
+ if (can_inline_wire(wire))
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
dump_attributes(f, indent, wire->attributes);
|
|
||||||
#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)
|
|
|
@ -1,25 +1,11 @@
|
||||||
{ pkgs, hx }:
|
{ pkgs, hx }:
|
||||||
|
|
||||||
let
|
pkgs.runCommand "helloworld-bitstream" {
|
||||||
symbiflowInput = pkgs.runCommand "helloworld-symbiflow-input" {
|
buildInputs = [ (pkgs.python3.withPackages(ps: [hx.nmigen hx.nmigen-boards hx.heavycomps])) pkgs.yosys ];
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
''
|
||||||
|
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
|
||||||
|
''
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
import argparse
|
||||||
|
|
||||||
from nmigen import *
|
from nmigen import *
|
||||||
from nmigen.back import rtlil
|
from nmigen_boards.versa_ecp5 import VersaECP5Platform
|
||||||
|
|
||||||
from heavycomps import uart
|
from heavycomps import uart
|
||||||
|
|
||||||
|
@ -7,20 +9,18 @@ from heavycomps import uart
|
||||||
class Top(Elaboratable):
|
class Top(Elaboratable):
|
||||||
def __init__(self, baudrate=115200):
|
def __init__(self, baudrate=115200):
|
||||||
self.baudrate = baudrate
|
self.baudrate = baudrate
|
||||||
self.clk100 = Signal()
|
|
||||||
self.serial_tx = Signal()
|
|
||||||
|
|
||||||
def elaborate(self, platform):
|
def elaborate(self, platform):
|
||||||
m = Module()
|
m = Module()
|
||||||
|
|
||||||
cd_sync = ClockDomain(reset_less=True)
|
cd_sync = ClockDomain(reset_less=True)
|
||||||
m.domains += cd_sync
|
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"
|
string = "Hello World!\r\n"
|
||||||
mem = Memory(width=8, depth=len(string),
|
mem = Memory(width=8, depth=len(string),
|
||||||
init=[ord(c) for c in string])
|
init=[ord(c) for c in string])
|
||||||
m.submodules.rdport = rdport = mem.read_port(synchronous=False)
|
m.submodules.rdport = rdport = mem.read_port(domain="comb")
|
||||||
|
|
||||||
wait = Signal()
|
wait = Signal()
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ class Top(Elaboratable):
|
||||||
m.d.comb += [
|
m.d.comb += [
|
||||||
tx.stb.eq(~wait),
|
tx.stb.eq(~wait),
|
||||||
tx.data.eq(rdport.data),
|
tx.data.eq(rdport.data),
|
||||||
self.serial_tx.eq(tx.tx)
|
platform.request("uart").tx.o.eq(tx.tx)
|
||||||
]
|
]
|
||||||
|
|
||||||
release = Signal()
|
release = Signal()
|
||||||
|
@ -49,10 +49,10 @@ class Top(Elaboratable):
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
top = Top()
|
parser = argparse.ArgumentParser()
|
||||||
output = rtlil.convert(Fragment.get(top, None),
|
parser.add_argument("build_dir")
|
||||||
ports=(top.clk100, top.serial_tx))
|
args = parser.parse_args()
|
||||||
print(output)
|
VersaECP5Platform().build(Top(), build_dir=args.build_dir)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
|
@ -1,47 +1,9 @@
|
||||||
{ pkgs, hx }:
|
{ pkgs, hx }:
|
||||||
|
|
||||||
let
|
pkgs.runCommand "helloworld-bitstream" {
|
||||||
vivadoInput = pkgs.runCommand "helloworld-vivado-input" {
|
buildInputs = [ (pkgs.python3.withPackages(ps: [hx.nmigen hx.nmigen-boards hx.heavycomps])) pkgs.yosys ];
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
''
|
||||||
|
export VIVADO=${hx.vivado}/bin/vivado
|
||||||
|
python ${./helloworld_kintex7.py} $out
|
||||||
|
''
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
import argparse
|
||||||
|
|
||||||
from nmigen import *
|
from nmigen import *
|
||||||
from nmigen.back import verilog
|
from nmigen_boards.kc705 import KC705Platform
|
||||||
|
|
||||||
from heavycomps import uart
|
from heavycomps import uart
|
||||||
|
|
||||||
|
@ -16,20 +18,20 @@ class Top(Elaboratable):
|
||||||
|
|
||||||
cd_sync = ClockDomain(reset_less=True)
|
cd_sync = ClockDomain(reset_less=True)
|
||||||
m.domains += cd_sync
|
m.domains += cd_sync
|
||||||
m.submodules.clock = Instance("IBUFGDS",
|
m.submodules.clock = Instance("BUFG",
|
||||||
i_I=self.clk156_p, i_IB=self.clk156_n, o_O=cd_sync.clk)
|
i_I=platform.request("clk156").i, o_O=cd_sync.clk)
|
||||||
|
|
||||||
string = "Hello World!\r\n"
|
string = "Hello World!\r\n"
|
||||||
mem = Memory(width=8, depth=len(string),
|
mem = Memory(width=8, depth=len(string),
|
||||||
init=[ord(c) for c in string])
|
init=[ord(c) for c in string])
|
||||||
m.submodules.rdport = rdport = mem.read_port(synchronous=False)
|
m.submodules.rdport = rdport = mem.read_port(domain="comb")
|
||||||
|
|
||||||
tx = uart.RS232TX(round(2**32*self.baudrate/156e6))
|
tx = uart.RS232TX(round(2**32*self.baudrate/156e6))
|
||||||
m.submodules.tx = tx
|
m.submodules.tx = tx
|
||||||
m.d.comb += [
|
m.d.comb += [
|
||||||
tx.stb.eq(1),
|
tx.stb.eq(1),
|
||||||
tx.data.eq(rdport.data),
|
tx.data.eq(rdport.data),
|
||||||
self.serial_tx.eq(tx.tx)
|
platform.request("uart").tx.o.eq(tx.tx)
|
||||||
]
|
]
|
||||||
|
|
||||||
with m.If(tx.ack):
|
with m.If(tx.ack):
|
||||||
|
@ -42,10 +44,10 @@ class Top(Elaboratable):
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
top = Top()
|
parser = argparse.ArgumentParser()
|
||||||
output = verilog.convert(Fragment.get(top, None),
|
parser.add_argument("build_dir")
|
||||||
ports=(top.clk156_p, top.clk156_n, top.serial_tx))
|
args = parser.parse_args()
|
||||||
print(output)
|
KC705Platform().build(Top(), build_dir=args.build_dir)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
|
@ -1,27 +1,11 @@
|
||||||
{ pkgs, hx }:
|
{ pkgs, hx }:
|
||||||
|
|
||||||
let
|
pkgs.runCommand "simplesoc-bitstream" {
|
||||||
symbiflowInput = pkgs.runCommand "simplesoc-symbiflow-input" {
|
buildInputs = [ (pkgs.python3.withPackages(ps: [hx.nmigen hx.nmigen-boards hx.heavycomps hx.minerva])) pkgs.yosys ];
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
''
|
||||||
|
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
|
||||||
|
''
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
|
import os
|
||||||
import argparse
|
import argparse
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
from nmigen import *
|
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 heavycomps import uart, wishbone
|
||||||
from minerva.core import Minerva
|
from minerva.core import Minerva
|
||||||
|
@ -27,28 +29,30 @@ class SimpleWishboneSerial(Elaboratable):
|
||||||
|
|
||||||
|
|
||||||
class Top(Elaboratable):
|
class Top(Elaboratable):
|
||||||
def __init__(self, firmware, create_clock):
|
def __init__(self, firmware, simulate):
|
||||||
if create_clock:
|
|
||||||
self.clk100 = Signal()
|
|
||||||
self.led = Signal()
|
|
||||||
self.serial_tx = Signal()
|
|
||||||
self.firmware = firmware
|
self.firmware = firmware
|
||||||
|
self.simulate = simulate
|
||||||
|
|
||||||
def elaborate(self, platform):
|
def elaborate(self, platform):
|
||||||
m = Module()
|
m = Module()
|
||||||
|
|
||||||
if hasattr(self, "clk100"):
|
if self.simulate:
|
||||||
|
io_user_led = Signal()
|
||||||
|
io_uart_tx = Signal()
|
||||||
|
else:
|
||||||
cd_sync = ClockDomain(reset_less=True)
|
cd_sync = ClockDomain(reset_less=True)
|
||||||
m.domains += cd_sync
|
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)
|
counter = Signal(27)
|
||||||
m.d.sync += counter.eq(counter + 1)
|
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.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.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(
|
m.submodules.con = con = wishbone.InterconnectShared(
|
||||||
[cpu.ibus, cpu.dbus],
|
[cpu.ibus, cpu.dbus],
|
||||||
[
|
[
|
||||||
|
@ -74,23 +78,22 @@ def main():
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument("--simulate", action="store_true")
|
parser.add_argument("--simulate", action="store_true")
|
||||||
parser.add_argument("firmware_bin")
|
parser.add_argument("firmware_bin")
|
||||||
parser.add_argument("output_file")
|
parser.add_argument("build_dir")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
firmware = read_firmware(args.firmware_bin)
|
firmware = read_firmware(args.firmware_bin)
|
||||||
top = Top(firmware, create_clock=not args.simulate)
|
top = Top(firmware, args.simulate)
|
||||||
|
|
||||||
if args.simulate:
|
if args.simulate:
|
||||||
|
os.makedirs(args.build_dir, exist_ok=True)
|
||||||
with pysim.Simulator(top,
|
with pysim.Simulator(top,
|
||||||
vcd_file=open(args.output_file + ".vcd", "w"),
|
vcd_file=open(os.path.join(args.build_dir, "simplesoc.vcd"), "w"),
|
||||||
gtkw_file=open(args.output_file + ".gtkw", "w")) as sim:
|
gtkw_file=open(os.path.join(args.build_dir, "simplesoc.gtkw"), "w")) as sim:
|
||||||
sim.add_clock(1e-6)
|
sim.add_clock(1e-6)
|
||||||
sim.run_until(1000e-6, run_passive=True)
|
sim.run_until(1000e-6, run_passive=True)
|
||||||
else:
|
else:
|
||||||
output = rtlil.convert(Fragment.get(top, None),
|
VersaECP5Platform().build(top, build_dir=args.build_dir)
|
||||||
ports=(top.clk100, top.led, top.serial_tx))
|
|
||||||
with open(args.output_file, "w") as f:
|
|
||||||
f.write(output)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
let
|
let
|
||||||
pkgs = import <nixpkgs> { overlays = [ (import ./overlay.nix) ]; };
|
pkgs = import <nixpkgs> { overlays = [ (import ./overlay.nix) ]; };
|
||||||
hx = import ./default.nix { inherit pkgs; };
|
hx = import ./default.nix { inherit pkgs; };
|
||||||
jobs = hx.drvs // {
|
jobs = hx // {
|
||||||
inherit (pkgs) llvm_7 rustc cargo cargo-vendor;
|
inherit (pkgs) llvm_7 rustc cargo cargo-vendor;
|
||||||
|
|
||||||
helloworld_ecp5 = import ./examples/helloworld_ecp5.nix { inherit pkgs hx; };
|
helloworld_ecp5 = import ./examples/helloworld_ecp5.nix { inherit pkgs hx; };
|
||||||
|
|
Loading…
Reference in New Issue