No description
  • Emacs Lisp 49.5%
  • VHDL 41.6%
  • Scheme 6.7%
  • Shell 2.2%
Find a file
2025-12-19 11:20:17 +01:00
sim first version 2025-03-11 16:39:29 +01:00
src readme: update. 2025-12-19 10:48:14 +01:00
hdl-prj.json include lsp files 2025-12-19 10:57:41 +01:00
hdl-profile.sh Rename scripts 2025-12-19 11:20:17 +01:00
init.el Add emacs vunit mode. 2025-07-18 10:42:12 +02:00
install.sh Rename scripts 2025-12-19 11:20:17 +01:00
launch-emacs.sh Rename scripts 2025-12-19 11:20:17 +01:00
LICENSE first version 2025-03-11 16:39:29 +01:00
manifest.scm readme: update. 2025-12-19 10:48:14 +01:00
README.md Rename scripts 2025-12-19 11:20:17 +01:00
readme.org Rename scripts 2025-12-19 11:20:17 +01:00
vhdl_ls.toml include lsp files 2025-12-19 10:57:41 +01:00

GNU/Emacs full IDE for HDL development - with tools.

Using Guix as a package manager. Tested under GNU/Emacs 30.2.

This repository lives here, with a mirror.

Install

The init.el configuration file in this repository must be used as Emacs init file

git clone --depth=1 https://git.sr.ht/~csantosb/emacs.vhdl-ide $TMPDIR/vhdl-ide

Then, just simply

cd $TMPDIR/vhdl-ide
./install.sh # create guix profile and install emacs ide here
./launch-emacs.sh

Use

keys:

Other than default emacs or package keys, the following are defined here.

  • C-M-SPC: launch a terminal
  • M-.: find definition
  • M-,: back from definition

Tools

Frequently used digital electronics tools.

Languages

  • amaranth:

  • migen:

  • myhdl:

Style

  • vsg:

Compilers

  • ghdl-llvm: analyzer, compiler, simulator and (experimental) synthesizer (requires guix-science channel)

  • nvc: compiler and simulator

  • verilator:

  • iverilog:

Scripting

  • tlc:

  • tcllib:

Development

  • make:

  • fd:

  • git:

Project management

  • hdlmake: multi-purpose makefiles for projects
  • edalize:

Synthesis

Implementation

  • nextpnr-cli:

Wave viewer

Programming

LSP

Libraries

  • p1076:

  • open-logic:

Modeling

  • uhdm:

  • systemc:

Verification

  • sby:

  • eqy:

  • mcy:

  • cocotb: coroutine based cosimulation testbench environment using python

  • cocotb-bus: cocotb reusable tools

  • vunit: unit testing framework

  • osvvm: verification libraries and scripts

Testing

You may test this configuration with help of the provided example code

./src/alu.vhd
./sim/alu_tb.vhd
.hdl-prj.json

Init.el

variables

Setup necessary variables.

(setq use-package-always-defer t
	  use-package-always-ensure nil)

(setenv "GHDL"
		(format "%s/bin/ghdl" (getenv "GUIX_PROFILE")))

(add-to-list 'treesit-extra-load-path
			 (format "%s/lib/tree-sitter" (getenv "GUIX_PROFILE")))

vhdl mode

(use-package vhdl-mode
  :hook
  (vhdl-mode . (lambda()
				 (vhdl-stutter-mode t)
				 (vhdl-electric-mode t)
				 (when (and (executable-find "ghdl-ls")
							(locate-dominating-file
							 default-directory "hdl-prj.json"))
				   (eglot-ensure)))))

vhdl-ts mode

(require 'treesit)
(use-package vhdl-ts-mode
  :mode (("\\.\\(vhd\\(?:l?\\)?\\)" . vhdl-ts-mode))
  :when (and (treesit-available-p)
			 (treesit-language-available-p 'vhdl) ; vhdl-ts-install-grammar
			 (treesit-ready-p 'vhdl t))
  :bind
  (:map vhdl-ts-mode-map
		("C-c C-b" . nil) ; vhdl-ts-beautify-buffer
		("C-M-u" . #'vhdl-ts-find-entity-instance-bwd))
  :custom
  (vhdl-ts-indent-level 2)
  (vhdl-ts-imenu-style 'tree-group)
  (vhdl-ts-beautify-align-ports-and-params t)
  :hook
  (vhdl-ts-mode . (lambda ()
					(vhdl-ext-mode)
					(require 'fpga)
					(superword-mode -1)
					(subword-mode t)
					(when outline-minor-mode
					  (setq-local
					   outline-regexp
					   "^\\s-*--\\s-\\([*]\\{1,8\\}\\)\\s-\\(.*\\)$"))
					;; otherwise, I’m unable to make imenu work properly
					(setq-local eglot-stay-out-of (list 'imenu)))))

vhdl-ext mode

(use-package vhdl-ext
  :after vhdl-ts-mode
  :init
  (setq vhdl-ext-eglot-default-server 've-ghdl-ls
		vhdl-ext-feature-list '(font-lock
								xref
								hierarchy
								eglot ; sets vhdl-ext-eglot-default-server
								beautify
								navigation
								imenu
								which-func))
  :bind
  (:map vhdl-ext-mode-map
		("C-M-i" . nil) ; vhdl-ext-beautify-block-at-point
		("C-c C-c" . vhdlide/vhdl-ext-beautify-region-or-buffer)
		("C-c C-b" . vhdlide/vhdl-ext-beautify-region-or-buffer))
  :config

  (defun vhdlide/vhdl-ext-beautify-region-or-buffer (&optional arg)
	"Beautify with vhdl-ts, using ‘beautify-block-at-point’.
With a prefix ARG, call ‘vhdl-ts-beautify-buffer’ instead.
With a double prefix ARG, beautify current dir instead."
	(interactive "P")
	(cond
	 ((equal arg '(16))
	  (call-interactively 'vhdl-ext-beautify-dir-files))
	 ((equal arg '(4))
	  (vhdl-ts-beautify-buffer))
	 (t
	  (vhdl-ext-beautify-block-at-point)))
	(save-buffer))
  (vhdl-ext-mode-setup))

fpga mode

(use-package fpga

;;; Mode

  :mode (("\\.vds?\\'" . fpga-xilinx-vivado-compilation-mode)
		 ("\\runme.log?\\'" . fpga-xilinx-vivado-compilation-mode))

;;; Init

  :init

  (setq fpga-feature-list '(xilinx yosys))

;;; Config

  :config

  (require 'tcl)

  (defvar csb/fpga-xilinx-vivado-shell-outline-regexp
	(regexp-opt
	 (append
	  (mapcar (lambda (arg) (format "%s:" arg)) fpga-xilinx-vivado-shell-commands)
	  (list "*** Running"
			"ERROR: "
			"WARNING:"
			"Command: "
			"wait_on_runs: "
			"___ ")))
	"docstring")

  (defvar csb/fpga-xilinx-vivado-compilation-outline-regexp
	(regexp-opt
	 (append
	  (mapcar (lambda (arg) (format "%s:" arg)) fpga-xilinx-vivado-shell-commands)
	  (list "*** Running"
			"Command: "
			"wait_on_runs: "
			"___ ")))
	"docstring")

  (defvar csb/fpga-xilinx-vivado-make-targets
	(list "project"
		  "synthesize"
		  "par"
		  "bitstream"
		  "all")
	"toto")

;;; Custom

  :custom

  ;; yosys
  (fpga-yosys-cmd-opts (list "-m $HOME/.guix-profile/lib/yosys/ghdl.so"))
  (fpga-yosys-buf nil)
  (fpga-yosys-bin "~/.guix-profile/bin/yosys")
  ;; check fpga-yosys--base-cmd

  ;; xilinx-vivado
  (fpga-xilinx-vivado-buf nil)
  ;; (fpga-xilinx-vivado-cmd-opts '("-mode" "tcl" "-nojournal" "-nolog"))
  (fpga-xilinx-vivado-cmd-opts '("-mode" "tcl"))
  (fpga-xilinx-vivado-bin
   "export TERM=xterm; /opt/Xilinx/Vivado/2024.1/bin/vivado")
  (fpga-xilinx-vivado--base-cmd
   (concat fpga-xilinx-vivado-bin
		   " " (mapconcat #'identity fpga-xilinx-vivado-cmd-opts " ")))

;;; Bind

  :bind

  (:map tcl-mode-map
		("C-c C-c" . fpga-xilinx-vivado-shell-send-line-or-region-and-step)
		("C-c C-j" . fpga-xilinx-vivado-shell-send-line-or-region-and-step))

;;; Hook

  :hook

  ;; (setq compilation-start-hook nil)
  (compilation-start .(lambda (arg)
						;; auto set mode in compilation buffer
						(when compilation-arguments
						  (let ((_tmp (car (last
											(split-string
											 (car compilation-arguments))))))
							(when (member _tmp
										  csb/fpga-xilinx-vivado-make-targets)
							  (fpga-xilinx-vivado-compilation-mode))))))

  ;; (setq tcl-mode-hook nil)
  (tcl-mode . (lambda ()
				(setq-local csb/toggle-inferior-shell
							#'fpga-xilinx-vivado-shell)))

  ;; (setq fpga-xilinx-vivado-compilation-mode-hook nil)
  (fpga-xilinx-vivado-compilation-mode .
									   (lambda ()
										 (setq-local
										  outline-regexp
										  csb/fpga-xilinx-vivado-compilation-outline-regexp)
										 (outline-minor-mode)
										 (setq fill-column 150)
										 (visual-fill-column-mode)
										 (when (buffer-file-name)
										   (turn-on-auto-revert-tail-mode))))

  ;; (setq fpga-xilinx-vivado-compilation-mode-hook nil)
  (fpga-xilinx-vivado-shell-mode .(lambda ()
									(setq-local
									 outline-regexp
									 csb/fpga-xilinx-vivado-shell-outline-regexp)
									(setq fill-column 150)
									(visual-fill-column-mode))))

eglot

(use-package eglot
  :custom
  ;; activate Eglot in non-project files
  (eglot-extend-to-xref t))

flymake

Flymake is a modern on-the-fly syntax checking extension for GNU Emacs.

(use-package flymake
  :hook
  (prog-mode . flymake-mode)
  :config
  (vhdlide/which-key-add "M-SPC")
  :bind
  (:map flymake-diagnostics-buffer-mode-map
		("C-j" . flymake-goto-diagnostic)
		("RET" . flymake-goto-diagnostic)
		("SPC" . flymake-show-diagnostic)
		:map flymake-mode-map
		("M-SPC n" . flymake-goto-next-error)
		("M-SPC p" . flymake-goto-prev-error)
		;; Diagnostics
		("M-SPC d" . flymake-show-buffer-diagnostics)
		("M-SPC b" . flymake-show-buffer-diagnostics)
		("M-SPC P" . flymake-show-project-diagnostics)
		;;
		("M-SPC l" . flymake-switch-to-log-buffer)
		("M-SPC r" . flymake-reporting-backends)
		("M-SPC R" . flymake-running-backends)))

eldoc

(use-package eldoc
  :custom
  (eldoc-echo-area-prefer-doc-buffer t)
  (eldoc-documentation-strategy 'eldoc-documentation-compose-eagerly))

eldoc-box

(use-package eldoc-box
  :after eldoc
  :bind
  (("C-M-?" . eldoc-box-help-at-point))
  :config
  ;; check with (describe-face 'eldoc-box-body)
  ;; (set-face-attribute
  ;;  'eldoc-box-body nil
  ;;  ;; :family "Symbola"
  ;;  :height (* 10 (+ 1 csb/font-size)))
  ;; (set-face-attribute
  ;;  'eldoc-box-border nil
  ;;  :background "#000000"
  ;;  )
  ;; :custom
  ;; (eldoc-box-offset '(30 30 30))
  ;; (eldoc-box-max-pixel-width 800)
  ;; (eldoc-box-max-pixel-height ) ; 700 def
  ;; (eldoc-box-clear-with-C-g t)
  ;; (eldoc-box-cleanup-interval 5)

  :hook

  (prog-mode . eldoc-box-hover-at-point-mode)
  ;; (eglot-managed-mode . eldoc-box-hover-mode)
  ;; eldoc-box-buffer-hook
  ;; (
  ;;  ;; (org-mode . (lambda ()
  ;;  ;;               (eldoc-box-hover-mode)))
  ;;  ;; (emacs-lisp-mode . (lambda ()
  ;;  ;;                      (eldoc-box-hover-mode -1)
  ;;  ;;                      (eldoc-box-hover-at-point-mode t)))
  ;;  )
  )

which-key

Emacs package that displays available keybindings in popup.

(use-package which-key
  :init
  (which-key-mode 1)
  (defun vhdlide/which-key-add (key)
	(when (require 'which-key nil t)
	  (add-to-list 'which-key-allow-regexps key)))
  :config
  (which-key-setup-minibuffer)
  :custom
  (which-key-idle-delay 0.2))

which-key posframe

(use-package which-key-posframe
  :init (which-key-posframe-mode)
  :after which-key
  :custom
  (which-key-posframe-border-width 2))

project

(use-package project
  :init
  (keymap-unset global-map "C-x p") ; remove default
  (keymap-set global-map "C-c p" project-prefix-map) ; andd replace it by
  (vhdlide/which-key-add "C-c p") ; a little help
  :custom
  (project-switch-commands 'project-dired)
  :bind
  (("M-l" . consult-project-buffer)
   :map project-prefix-map
   ("SPC" . consult-dir)
   ("p" . project-switch-project)
   ("k" . project-kill-buffers)
   ("q" . nil)))

corfu

gui corfu

(use-package corfu
  :init (global-corfu-mode)
  :custom
  ;; Quit ?
  (corfu-quit-at-boundary 'separator)
  (corfu-quit-no-match t)
  (corfu-cycle t)
  (corfu-auto t)
  (corfu-auto-prefix 2)
  (corfu-auto-delay 0.5)
  (corfu-preview-current 'insert)
  :bind
  (:map corfu-map
		("C-j" . corfu-complete)
		("SPC" . corfu-insert-separator)))
  1. plugins, part of corfu

    1. history

      Sort candidates by their history position.

      (use-package corfu-history
        :after corfu
        :init (corfu-history-mode)
        :config
        (when (require 'savehist nil t)
      	(add-to-list 'savehist-additional-variables 'corfu-history)))
      
    2. info

      (use-package corfu-info
        :after corfu)
      
    3. popupinfo

      (use-package corfu-popupinfo
        :after corfu
        :init (corfu-popupinfo-mode)
        :bind
        (:map corfu-popupinfo-map
      		("M-t" . corfu-popupinfo-toggle)
      		("M-p" . corfu-popupinfo-scroll-down)
      		("M-n" . corfu-popupinfo-scroll-up))
        :custom
        (corfu-popupinfo-max-height 30)
        (corfu-popupinfo-delay '(1.0 . 0.5)))
      
    4. quick

      (use-package corfu-quick
        :after corfu
        :bind
        (:map corfu-map
      		("M-j" . corfu-quick-jump) ; Jump to candidate using quick keys
      		("M-c" . corfu-quick-complete) ; Complete candidate using quick keys
      		("M-i" . corfu-quick-insert)))
      
  2. plugins, not part of corfu

    1. kind-icon

      (use-package kind-icon
        :after corfu
        :custom
        ;; ;; TODO: remove when problem fixed
        ;; (kind-icon-use-icons nil)
        (kind-icon-default-face 'corfu-default) ; compute blended backgrounds
        :config
        (add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter))
      (require 'kind-icon)
      

terminal corfu

(use-package corfu-terminal
  :init (corfu-terminal-mode))

(use-package corfu-doc-terminal
  :init (corfu-doc-terminal-mode)
  :after corfu-terminal)

all the icons completions

Add icons to completion candidates.

(use-package all-the-icons-completion
  :init (all-the-icons-completion-mode))

consult

(use-package consult
  :init
  (define-prefix-command 'vhdlide/consult-map)
  (define-key ctl-x-map "c" 'vhdlide/consult-map)
  (vhdlide/which-key-add "C-x c")
  :bind
  (("M-s M-g" . consult-grep) ; A recursive grep
   ("C-x C-b" . consult-buffer) ; Switch to another buffer, or bookmarked file, or recently
   ("M-SPC" . consult-buffer) ; Switch to another buffer, or bookmarked file, or recently
   ("M-s M-l" . consult-line)
   :map vhdlide/consult-map
   ("L" . consult-locate)
   ("i" . consult-imenu)
   ("o" . consult-outline)
   ("I" . consult-imenu-multi)
   ("M-y" . consult-yank-from-kill-ring)
   ("M-s" . consult-ripgrep)))

embark

(use-package embark
  :bind (("C-." . embark-act)         ; pick some comfortable binding
		 ("C-;" . embark-dwim)))      ; good alternative: M-.

vertico

VERTical Interactive COmpletion provides a performant and minimalistic vertical completion UI based on the default completion system.

(use-package vertico
  :custom
  (vertico-cycle t)
  (vertico-resize t)
  (vertico-count 30)
  :bind
  (:map vertico-map
		("TAB" . embark-act)
		("C-c C-c" . embark-collect)
		("C-c C-e" . embark-export))
  :init
  (vertico-mode t))

vertico posframe

(use-package vertico-posframe
  :init (vertico-posframe-mode)
  :after vertico
  :custom
  (vertico-posframe-min-width 20)
  (vertico-posframe-min-height 1)
  (vertico-posframe-border-width 2)
  (vertico-posframe-poshandler #'posframe-poshandler-frame-center))

marginalia

https://github.com/minad/marginalia

(use-package marginalia
  :init (marginalia-mode)
  :bind
  (:map minibuffer-local-map
		("M-A" . marginalia-cycle)))

orderless

(use-package orderless
  :custom
  (completion-styles '(orderless partial-completion basic))
  (completion-category-overrides '((file (styles partial-completion)))))

nano

(require 'nano-theme)
(setq nano-font-size 12
	  nano-fonts-use t)
(load-theme 'nano-light t)

(require 'nano-modeline)
(nano-modeline-org-mode)
(add-hook 'prog-mode-hook #'nano-modeline-prog-mode)

crux

(use-package crux
  :bind
  (([remap kill-whole-line] . crux-kill-whole-line)
   ([remap move-beginning-of-line] . crux-move-beginning-of-line)
   ("C-a"  . crux-move-beginning-of-line)
   :map ctl-x-map
   ("C-n"  . crux-create-scratch-buffer)))

vterm

(use-package vterm
  :commands vterm
  :init
  :custom
  (vterm-kill-buffer-on-exit t)
  (vterm-clear-scrollback-when-clearing nil)
  :config
  :hook
  ((vterm-mode . (lambda ()
				   (nano-modeline-vterm-mode)
				   (hl-line-mode -1)))
   (vterm-copy-mode . (lambda ()
						(hl-line-mode t))))
  :bind
  (("C-M-SPC" . (lambda (&optional arg)
				  "Launch vterm below current window"
				  (interactive)
				  (split-window-below)
				  (vterm-other-window)))
   :map vterm-mode-map
   ("C-c C-t" . nil) ; disable default copy mode
   ("C-c C-j" . vterm-copy-mode) ; I prefer this one
   ("C-q" . vterm-send-next-key)
   ("C-y" . vterm-yank)
   ("C-c C-n" . vterm-next-prompt)
   ("C-c C-p" . vterm-previous-prompt)
   :map vterm-copy-mode-map
   ("C-c C-k" . (lambda ()
				  (interactive)
				  (vterm-copy-mode -1)
				  (message "Disabling vterm copy mode")))))

which function

(use-package which-function
  :init (which-function-mode t))

helpful

(use-package helpful
  :config
  (advice-add 'helpful-update :after #'elisp-demos-advice-helpful-update)
  :bind
  (("C-h c" . helpful-command)
   ("C-h @" . helpful-macro)
   ("C-h k" . helpful-key)
   ("C-h f" . helpful-function)
   ("C-h F" . helpful-callable)
   ("C-h v" . helpful-variable)
   ("C-h ." . helpful-at-point)
   :map helpful-mode-map
   ("C-j" . push-button)))

doom mode line

(use-package doom-modeline
  :init (doom-modeline-mode t)
  :custom
  (doom-modeline-support-imenu t)
  (doom-modeline-time t)
  (doom-modeline-battery t)
  (doom-modeline-env-version t)
  (doom-modeline-major-mode-color-icon t)
  (doom-modeline-height 20))

isearch

(use-package isearch

  :custom

  (isearch-lazy-count t) ; Show match numbers in the search prompt.
  (lazy-count-prefix-format nil)
  (lazy-count-suffix-format "   (%s/%s)")
  (isearch-regexp t)

  :config

  (defun vhdlvhdlide/isearch-forward (&optional arg)
	"Defaults to ‘isearch-forward’.
With prefix ‘ARG’ use ‘isearch-forward-symbol-at-point’ instead."
	(interactive "P")
	(cond ((equal arg '(4))
		   (isearch-forward-symbol-at-point))
		  (t
		   ;; prefer regexp
		   (isearch-forward '(4)))))

  (defun vhdlvhdlide/isearch-backward (&optional arg)
	"Defaults to ‘isearch-backward’.
With prefix ‘ARG’ use ‘isearch-forward-symbol-at-point’ instead."
	(interactive "P")
	(cond ((equal arg '(4))
		   (progn
			 (isearch-forward-symbol-at-point)
			 (let ((superword-mode t))
			   (backward-word 1))))
		  (t
		   ;; prefer regexp
		   (isearch-backward '(4)))))

  :bind

  (("C-s" . vhdlvhdlide/isearch-forward)
   ("C-r" . vhdlvhdlide/isearch-backward)

   :map isearch-mode-map

   ("C-j" . isearch-exit)))

vunit-mode

(use-package vunit-mode
  :init
  (global-vunit-mode t)
  :after vhdl-mode
  :custom
  ;; (vunit-path "project dependent")
  (vunit-simulator "ghdl")              ;nvc
  ;; (vunit-run-outdir "vunitout")         ;keep original
  (vunit-num-threads (num-processors))
  (vunit-python-executable (executable-find "python3")))

Scripts

install.sh

Install script.

First, create a dedicated guix profile

. ./hdl-profile.sh

Download and install packages in the dedicated profile from manifest file.

printf 'GUIX profile:\t%s\n' "$GUIX_PROFILE"
guix package -p "$GUIX_PROFILE" -m manifest.scm

manifest.scm

List of required packages to install.

(specifications->manifest
 (list

  ;; languages
  "python-amaranth"
  "python-migen"
  "python-myhdl"

  ;; style
  "python-vsg"

  ;; compilers
  ;; "ghdl-llvm"          ;requires guix-science channel
  "nvc"
  "verilator"
  "iverilog"

  ;; scripting
  "tcl"
  "tcllib"

  ;; development
  "make"
  "fd"
  "git"

  ;; emacs packages
  "emacs"
  "tree-sitter"
  "emacs-elisp-demos"
  "emacs-vhdl-ext"
  "emacs-vhdl-ts-mode"
  "emacs-fpga"
  "emacs-which-key-posframe"
  "emacs-all-the-icons"
  "emacs-all-the-icons-completion"
  "emacs-consult"
  "emacs-consult-eglot"
  "emacs-consult-dir"
  "emacs-embark"
  "emacs-vertico"
  "emacs-vertico-posframe"
  "emacs-marginalia"
  "emacs-vterm"
  "emacs-orderless"
  "emacs-corfu"
  "emacs-corfu-terminal"
  "emacs-corfu-doc"
  "emacs-corfu-doc-terminal"
  "emacs-nano-theme"
  "emacs-nano-modeline"
  "emacs-kind-icon"
  "emacs-crux"
  "emacs-helpful"
  "emacs-eldoc-box"
  "emacs-visual-fill-column"
  "emacs-doom-modeline"
  "emacs-vunit-mode"

  ;; fonts
  "font-google-roboto"
  "font-fira-code"
  "font-fira-mono"
  "font-fira-sans"

  ;; project management
  "python-hdlmake"
  "python-edalize"

  ;; synthesis
  "yosys"
  ;; "ghdl-yosys-plugin"       ;requires guix-science channel

  ;; implementation
  "nextpnr-cli"

  ;; wave viewer
  "gtkwave"

  ;; programming
  "openfpgaloader"

  ;; lsp
  ;; "ghdl-lsp"                 ;requires guix-science channel
  "vhdl-ls"

  ;; libraries
  "open-logic"
  "ieee-p1076"

  ;; modeling
  "uhdm"
  "systemc"

  ;; verification
  "sby"
  ;; "sby-gui"
  "eqy"
  "mcy"
  "python-cocotb"
  "python-cocotb-bus"
  "python-vunit"
  ;; osvvm
  "osvvm"
  "osvvm:uart"
  "osvvm:scripts"
  "osvvm:common"))

launch-emacs.sh

Launch emacs hdl ide with this script

First, activate the dedicated guix profile

. ./hdl-profile.sh

Then, launch emacs with:

printf 'GUIX profile:\t%s\n' "$GUIX_PROFILE"
emacs --init-directory=. #"$TMPDIR/vhdl-ide"

It assumes /$TMPDIR/vhdl-vhdlide/ as user-emacs-directory to avoid overwritting the default user directory.

setup profile

Create and activate a custom, dedicated profile to include all necessary packages.

export _PROFILE=hdl-profile
[ ! -d "$HOME/.guix-profiles/$_PROFILE" ] && mkdir -p "$HOME/.guix-profiles/$_PROFILE"
export GUIX_PROFILE="$HOME/.guix-profiles/$_PROFILE/guix-profile"
[ -f "$GUIX_PROFILE/etc/profile" ] && . "$GUIX_PROFILE/etc/profile"
printf 'GUIX profile:\t%s\n' "$GUIX_PROFILE"