aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.envrc1
-rw-r--r--.gitignore14
-rw-r--r--Makefile19
-rwxr-xr-xclean.sh13
-rw-r--r--flake.lock58
-rw-r--r--flake.nix19
-rw-r--r--src/Top.bs53
7 files changed, 177 insertions, 0 deletions
diff --git a/.envrc b/.envrc
new file mode 100644
index 0000000..3550a30
--- /dev/null
+++ b/.envrc
@@ -0,0 +1 @@
+use flake
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..732ff23
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,14 @@
+# Blanket ignores and exceptions to them
+.*
+*~
+!.builds
+!.envrc
+!.gitignore
+
+# Nix outputs
+result
+result-*
+
+# Non-Nix outputs
+tmp/
+dump.vcd
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..80b04e5
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,19 @@
+BSC_COMP_FLAGS = -aggressive-conditions -check-assert -keep-fires
+BSC_LINK_FLAGS = -keep-fires
+TOPFILE = Top
+TOPMODULE = mkTop
+
+all: tmp/$(TOPMODULE).exe tmp/$(TOPMODULE).v
+clean: clean.sh
+ @./clean.sh
+.PHONY: all clean
+
+tmp/$(TOPMODULE).exe: tmp/$(TOPMODULE).ba
+ @mkdir -p $(dir $@)
+ bsc -e $(TOPMODULE) -o $@ -p $(dir $<) -sim -simdir tmp -u $(BSC_LINK_FLAGS)
+tmp/$(TOPMODULE).ba: src/$(TOPFILE).bs
+ @mkdir -p $(dir $@)
+ bsc -bdir $(dir $@) -g $(TOPMODULE) -sim -u $(BSC_COMP_FLAGS) $<
+tmp/$(TOPMODULE).v: src/$(TOPFILE).bs
+ @mkdir -p $(dir $@)
+ bsc -bdir tmp -g $(TOPMODULE) -u -verilog -vdir tmp $(BSC_COMP_FLAGS) $<
diff --git a/clean.sh b/clean.sh
new file mode 100755
index 0000000..68769e6
--- /dev/null
+++ b/clean.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+set -eu
+
+cd "$(git rev-parse --show-toplevel)"
+
+if [ "$(git status --porcelain=v1 --ignored -z | grep -z '^!!' | wc -c)" = 0 ]; then
+ exit
+fi
+
+git status --porcelain=v1 --ignored -z \
+| grep -z '^!!' \
+| xargs -0 awk 'BEGIN { for(i = 1; i < ARGC; i++) printf "%s%c", substr(ARGV[i], 4), 0; }' \
+| xargs -0 rm -r
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..df65460
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,58 @@
+{
+ "nodes": {
+ "flake-utils": {
+ "inputs": {
+ "systems": "systems"
+ },
+ "locked": {
+ "lastModified": 1710146030,
+ "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
+ "type": "github"
+ },
+ "original": {
+ "id": "flake-utils",
+ "type": "indirect"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1708702655,
+ "narHash": "sha256-qxT5jSLhelfLhQ07+AUxSTm1VnVH+hQxDkQSZ/m/Smo=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "c5101e457206dd437330d283d6626944e28794b3",
+ "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
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..e49859b
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,19 @@
+{
+ outputs = { self, flake-utils, nixpkgs }:
+ flake-utils.lib.eachDefaultSystem (system:
+ let pkgs = nixpkgs.legacyPackages.${system};
+ in rec {
+ devShells.default = pkgs.mkShell {
+ inputsFrom = builtins.attrValues packages;
+ nativeBuildInputs = [
+ pkgs.bluespec
+ pkgs.gtkwave
+ pkgs.icestorm
+ pkgs.verilator
+ pkgs.yosys
+ ];
+ };
+
+ packages = { };
+ });
+}
diff --git a/src/Top.bs b/src/Top.bs
new file mode 100644
index 0000000..6dee830
--- /dev/null
+++ b/src/Top.bs
@@ -0,0 +1,53 @@
+package Top where
+
+mkTop :: Module Empty
+mkTop =
+ module
+ deepThought :: DeepThought_IFC <- mkDeepThought
+
+ rules
+ "rl_ask": when True ==> do
+ $display "Asking the Ultimate Question of Life, The Universe and Everything"
+ deepThought.whatIsTheAnswer
+
+ "rl_print_answer": when True ==> do
+ x <- deepThought.getAnswer
+ $display "Deep Thought says: Hello, World! The answer is %0d." x
+ $finish
+
+interface DeepThought_IFC =
+ whatIsTheAnswer :: Action
+ getAnswer :: ActionValue (Int 32)
+
+data State_DT = IDLE | THINKING | ANSWER_READY
+ deriving (Eq, Bits, FShow)
+
+mkDeepThought :: Module DeepThought_IFC
+mkDeepThought =
+ module
+ rg_state_dt :: Reg State_DT <- mkReg IDLE
+ rg_half_millenia :: Reg (Bit 4) <- mkReg 0
+
+ let millenia = rg_half_millenia [3:1]
+ let half_millenium = rg_half_millenia [0:0]
+
+ rules
+ "rl_think": when (rg_state_dt == THINKING) ==> do
+ $write " DeepThought: ... thinking ... (%0d" millenia
+ if (half_millenium == 1) then $write ".5" else noAction
+ $display " million years)"
+
+ if (rg_half_millenia == 15) then
+ rg_state_dt := ANSWER_READY
+ else
+ rg_half_millenia := rg_half_millenia + 1
+
+ interface
+ whatIsTheAnswer = rg_state_dt := THINKING
+ when (rg_state_dt == IDLE)
+
+ getAnswer = do
+ rg_state_dt := IDLE
+ rg_half_millenia := 0
+ return 42
+ when (rg_state_dt == ANSWER_READY)