FPGA flake
This commit is contained in:
parent
d766c8434a
commit
4642bafae1
|
@ -27,5 +27,10 @@
|
||||||
description = "Minimal python flake";
|
description = "Minimal python flake";
|
||||||
welcomeText = "hisss 🐍🐍🐍";
|
welcomeText = "hisss 🐍🐍🐍";
|
||||||
};
|
};
|
||||||
|
templates.verilog= {
|
||||||
|
path = ./fpga;
|
||||||
|
description = "FPGA flake, running verilog on ice40";
|
||||||
|
welcomeText = "mjau 🧊";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
1
fpga/.envrc
Normal file
1
fpga/.envrc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
use flake
|
3
fpga/.gitignore
vendored
Normal file
3
fpga/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
abc.history
|
||||||
|
.direnv
|
||||||
|
result
|
59
fpga/flake.lock
Normal file
59
fpga/flake.lock
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1694529238,
|
||||||
|
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1697009197,
|
||||||
|
"narHash": "sha256-viVRhBTFT8fPJTb1N3brQIpFZnttmwo3JVKNuWRVc3s=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "01441e14af5e29c9d27ace398e6dd0b293e25a54",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"id": "nixpkgs",
|
||||||
|
"type": "indirect"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
80
fpga/flake.nix
Normal file
80
fpga/flake.nix
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
{
|
||||||
|
description = "FPGA flake, running verilog on ice40";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs, flake-utils }:
|
||||||
|
flake-utils.lib.eachDefaultSystem (sys:
|
||||||
|
let pkgs = nixpkgs.legacyPackages.${sys};
|
||||||
|
|
||||||
|
verilator = import ./verilator.nix pkgs ;
|
||||||
|
yosys = pkgs.yosys;
|
||||||
|
|
||||||
|
vflags = ''-DSIMULATE -Wno-fatal -Wpedantic -Wwarn-lint -Wwarn-style -Wno-PINCONNECTEMPTY -Wno-BLKSEQ -CFLAGS "-Wpedantic -std=c++20"'';
|
||||||
|
|
||||||
|
verilate-src = cmd: ''
|
||||||
|
cp -r ${./src} ./src
|
||||||
|
cp -r ${./simulation} ./simulation
|
||||||
|
find ./src/ -name '*.v' -exec ${verilator}/bin/verilator ${vflags} ${cmd} {} +
|
||||||
|
'';
|
||||||
|
|
||||||
|
lint = pkgs.runCommand "lint" {} ''
|
||||||
|
${verilate-src "--lint-only"}
|
||||||
|
echo "compiler didn't get angry :3"
|
||||||
|
: 3 > $out
|
||||||
|
'';
|
||||||
|
|
||||||
|
test-trace = pkgs.runCommandCC "test-trace" {} ''
|
||||||
|
set -e
|
||||||
|
${verilate-src "--cc --build --exe --trace -CFLAGS -DTRACE=1 ./simulation/test_led.cpp -top top"}
|
||||||
|
mv obj_dir "$out" && mkdir "$out/bin"
|
||||||
|
cp "$out/Vtop" "$out/bin/sim"
|
||||||
|
$out/bin/sim $out/trace.vcd
|
||||||
|
echo "${pkgs.gtkwave}/bin/gtkwave $out/trace.vcd" > $out/bin/test-trace
|
||||||
|
chmod u+x $out/bin/test-trace
|
||||||
|
'';
|
||||||
|
|
||||||
|
synth = pkgs.runCommandCC "synth" {} ''
|
||||||
|
mkdir -p "$out"
|
||||||
|
find ${./src} -name '*.v' -exec ${yosys}/bin/yosys -f ' -sv' -q -p "synth_ice40 -top top -json $out/synth.json" {} +
|
||||||
|
'';
|
||||||
|
|
||||||
|
pnr-interactive = pkgs.writeScriptBin "pnr-interactive" ''
|
||||||
|
${pkgs.nextpnrWithGui}/bin/nextpnr-ice40 --up5k --package sg48 --pcf ${./pins.pcf} --json ${synth}/synth.json --gui
|
||||||
|
'';
|
||||||
|
|
||||||
|
pnr = pkgs.runCommandCC "pnr" {} ''
|
||||||
|
mkdir -p "$out"
|
||||||
|
${pkgs.nextpnrWithGui}/bin/nextpnr-ice40 --up5k --package sg48 --pcf ${./pins.pcf} --json ${synth}/synth.json --asc "$out/pnr.asc" \
|
||||||
|
--freq 50
|
||||||
|
'';
|
||||||
|
|
||||||
|
flash = pkgs.writeScriptBin "flash" ''
|
||||||
|
set -e
|
||||||
|
bin="$(mktemp)"
|
||||||
|
${pkgs.icestorm}/bin/icepack ${pnr}/pnr.asc "$bin"
|
||||||
|
${pkgs.icestorm}/bin/iceprog "$bin"
|
||||||
|
'';
|
||||||
|
|
||||||
|
deps = [
|
||||||
|
yosys pkgs.nextpnrWithGui pkgs.icestorm verilator pkgs.gtkwave
|
||||||
|
pkgs.picocom
|
||||||
|
];
|
||||||
|
in rec {
|
||||||
|
packages.verilator = verilator;
|
||||||
|
|
||||||
|
packages.lint = lint;
|
||||||
|
|
||||||
|
packages.test-trace = test-trace;
|
||||||
|
|
||||||
|
packages.synth = synth;
|
||||||
|
packages.pnr-interactive = pnr-interactive;
|
||||||
|
packages.pnr = pnr;
|
||||||
|
packages.flash = flash;
|
||||||
|
|
||||||
|
devShells.default = pkgs.mkShell { packages = deps; };
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
2
fpga/pins.pcf
Normal file
2
fpga/pins.pcf
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
set_io clk_12m 35
|
||||||
|
set_io led_red 26
|
56
fpga/simulation/test_led.cpp
Normal file
56
fpga/simulation/test_led.cpp
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
#include "Vtop.h"
|
||||||
|
#include "verilated.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
#include "verilated_vcd_c.h"
|
||||||
|
|
||||||
|
struct state {
|
||||||
|
VerilatedContext *ctx;
|
||||||
|
Vtop *vtop;
|
||||||
|
VerilatedVcdC *trace;
|
||||||
|
};
|
||||||
|
|
||||||
|
void posedge(state &state) {
|
||||||
|
state.ctx->timeInc(1);
|
||||||
|
state.vtop->clk_12m = 1;
|
||||||
|
state.vtop->eval();
|
||||||
|
state.trace->dump(state.ctx->time());
|
||||||
|
|
||||||
|
state.ctx->timeInc(1);
|
||||||
|
state.vtop->clk_12m = 0;
|
||||||
|
state.vtop->eval();
|
||||||
|
state.trace->dump(state.ctx->time());
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
VerilatedContext *vctx = new VerilatedContext;
|
||||||
|
Verilated::traceEverOn(true);
|
||||||
|
Vtop *vtop = new Vtop(vctx);
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
std::cout << "Run with argument for destination!" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
VerilatedVcdC *trace = new VerilatedVcdC;
|
||||||
|
vtop->trace(trace, 99);
|
||||||
|
trace->open(argv[1]);
|
||||||
|
std::cout << "(writing trace to " << argv[1] << ")" << std::endl;
|
||||||
|
|
||||||
|
state state = {
|
||||||
|
.ctx = vctx,
|
||||||
|
.vtop = vtop,
|
||||||
|
.trace = trace,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
for (int i = 0; i < 2<<24; i++) {
|
||||||
|
posedge(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
state.trace->close();
|
||||||
|
}
|
||||||
|
|
43
fpga/src/top.v
Normal file
43
fpga/src/top.v
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
module top(
|
||||||
|
input clk_12m,
|
||||||
|
|
||||||
|
output led_red
|
||||||
|
);
|
||||||
|
|
||||||
|
// want clock to blink at a rate of 1Hz
|
||||||
|
// intermediate clock at 2^24 Hz = 16.77MHz
|
||||||
|
// 12MHz * 7/5 = 16.8MHz, within 0.2%
|
||||||
|
|
||||||
|
wire clk_16_8m;
|
||||||
|
wire clk_stable;
|
||||||
|
// set ethernet clock to 50 MHz
|
||||||
|
`ifndef SIMULATE
|
||||||
|
SB_PLL40_PAD #(
|
||||||
|
.FEEDBACK_PATH("SIMPLE"),
|
||||||
|
.DIVR(4'd4), // divide by 4+1=5
|
||||||
|
.DIVF(7'd6), // multiply by 6+1=7
|
||||||
|
.DIVQ(3'd0), // divide by 2^0
|
||||||
|
.FILTER_RANGE(3'b001)
|
||||||
|
) SB_PLL40_PAD_inst (
|
||||||
|
.PACKAGEPIN(clk_12m),
|
||||||
|
.PLLOUTGLOBAL(clk_16_8m),
|
||||||
|
.RESETB(1'b1),
|
||||||
|
.BYPASS(1'b0),
|
||||||
|
.LOCK(clk_stable)
|
||||||
|
);
|
||||||
|
`else
|
||||||
|
// in simulation, tie clocks together
|
||||||
|
assign clk_16_8m = clk_12m;
|
||||||
|
assign clk_stable = 1;
|
||||||
|
`endif
|
||||||
|
|
||||||
|
// divide 16.8MHz clock by 2^24
|
||||||
|
reg [24:0] clk_ctr;
|
||||||
|
|
||||||
|
always @(posedge clk_16_8m) begin
|
||||||
|
clk_ctr <= clk_ctr + 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
assign led_red = clk_stable & clk_ctr[24];
|
||||||
|
|
||||||
|
endmodule
|
47
fpga/verilator.nix
Normal file
47
fpga/verilator.nix
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
pkgs: with pkgs;
|
||||||
|
|
||||||
|
# From https://github.com/NixOS/nixpkgs/blob/nixos-23.11/pkgs/applications/science/electronics/verilator/default.nix
|
||||||
|
# Patches out SystemC-support, as the SystemC does not build on Darwin
|
||||||
|
stdenv.mkDerivation rec {
|
||||||
|
pname = "verilator";
|
||||||
|
version = "5.018";
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = pname;
|
||||||
|
repo = pname;
|
||||||
|
rev = "v${version}";
|
||||||
|
hash = "sha256-f06UzNw2MQ5me03EPrVFhkwxKum/GLDzQbDNTBsJMJs=";
|
||||||
|
};
|
||||||
|
|
||||||
|
enableParallelBuilding = true;
|
||||||
|
buildInputs = [ perl python3 ]; # ccache
|
||||||
|
nativeBuildInputs = [ makeWrapper flex bison autoconf help2man git ];
|
||||||
|
nativeCheckInputs = [ which numactl ]; # cmake
|
||||||
|
|
||||||
|
doCheck = stdenv.isLinux; # darwin tests are broken for now...
|
||||||
|
checkTarget = "test";
|
||||||
|
|
||||||
|
preConfigure = "autoconf";
|
||||||
|
|
||||||
|
postPatch = ''
|
||||||
|
patchShebangs bin/* src/* nodist/* docs/bin/* examples/xml_py/* \
|
||||||
|
test_regress/{driver.pl,t/*.{pl,pf}} \
|
||||||
|
ci/* ci/docker/run/* ci/docker/run/hooks/* ci/docker/buildenv/build.sh
|
||||||
|
'';
|
||||||
|
# grep '^#!/' -R . | grep -v /nix/store | less
|
||||||
|
# (in nix-shell after patchPhase)
|
||||||
|
|
||||||
|
postInstall = lib.optionalString stdenv.isLinux ''
|
||||||
|
for x in $(ls $out/bin/verilator*); do
|
||||||
|
wrapProgram "$x" --set LOCALE_ARCHIVE "${glibcLocales}/lib/locale/locale-archive"
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "Fast and robust (System)Verilog simulator/compiler and linter";
|
||||||
|
homepage = "https://www.veripool.org/verilator";
|
||||||
|
license = with licenses; [ lgpl3Only artistic2 ];
|
||||||
|
platforms = platforms.unix;
|
||||||
|
maintainers = with maintainers; [ thoughtpolice amiloradovsky ];
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user