From 1ff7e633fbbf26e5f5de7e01a603045e1d854291 Mon Sep 17 00:00:00 2001 From: Avimitin Date: Fri, 23 Aug 2024 18:52:49 +0800 Subject: [PATCH] [nix] add 'dev-mode' attribute to handle script It is incovenient for users to always input strings like ".#t1.blastoise.ip.cases.mlir.hello.emu-result". So here is an env to help improve the current situation. With the "dev-mode" shell, users will have many bash function to help them set the current development "mode". For example, if users want to test "intrinsic.linear_optimisation" with VCS emulator, and compare the result with verilator-emulator, they will have to write "nix build .#t1.blastoise.ip.vcs-emu.cases.intrinsic.linear_optimisation", then ".#t1.blastoise.ip.verilator-emu.cases.intrinsic.linear_optimisation" With the new script, the test flow is separate into different phrases: * Firstly, get into the dev-mode shell: `nix develop .#dev-mode` * Then, set the config: `set_config blastoise` * Users can inspect RTL with simple command too: `build vcs-emu-rtl` * To switch between verilator and VCS, they can use: `set_emulator vcs-emu` or `set_emulator verilator-emu` * Finally, run the case: `test intrinsic.linear_optimisation` Signed-off-by: Avimitin --- nix/overlay.nix | 1 + nix/pkgs/dev-mode/default.nix | 8 ++ nix/pkgs/dev-mode/dev-mode.sh | 238 ++++++++++++++++++++++++++++++++++ nix/t1/default.nix | 10 +- 4 files changed, 249 insertions(+), 8 deletions(-) create mode 100644 nix/pkgs/dev-mode/default.nix create mode 100644 nix/pkgs/dev-mode/dev-mode.sh diff --git a/nix/overlay.nix b/nix/overlay.nix index 20b69d081..a11d3d703 100644 --- a/nix/overlay.nix +++ b/nix/overlay.nix @@ -46,6 +46,7 @@ rec { t1-script = final.callPackage ../script { }; inherit (t1-script) t1-helper ci-helper; + dev-mode = final.callPackage ./pkgs/dev-mode { }; # stdenv for compiling rvv programs, with ilp32f newlib and clang rv32-stdenv = rv32_pkgs.stdenv.override { diff --git a/nix/pkgs/dev-mode/default.nix b/nix/pkgs/dev-mode/default.nix new file mode 100644 index 000000000..aa673cc11 --- /dev/null +++ b/nix/pkgs/dev-mode/default.nix @@ -0,0 +1,8 @@ +{ mkShellNoCC, jq, ncurses }: +mkShellNoCC { + name = "t1-dev-mode"; + nativeBuildInputs = [ jq ncurses ]; + shellHook = '' + source ${./dev-mode.sh} + ''; +} diff --git a/nix/pkgs/dev-mode/dev-mode.sh b/nix/pkgs/dev-mode/dev-mode.sh new file mode 100644 index 000000000..009e003b4 --- /dev/null +++ b/nix/pkgs/dev-mode/dev-mode.sh @@ -0,0 +1,238 @@ +# prefer terminal safe colored and bold text when tput is supported +if tput setaf 0 &>/dev/null; then + ALL_OFF="$(tput sgr0)" + BOLD="$(tput bold)" + BLUE="${BOLD}$(tput setaf 4)" + GREEN="${BOLD}$(tput setaf 2)" + RED="${BOLD}$(tput setaf 1)" + YELLOW="${BOLD}$(tput setaf 3)" +else + ALL_OFF="\e[0m" + BOLD="\e[1m" + BLUE="${BOLD}\e[34m" + GREEN="${BOLD}\e[32m" + RED="${BOLD}\e[31m" + YELLOW="${BOLD}\e[33m" +fi +readonly ALL_OFF BOLD BLUE GREEN RED YELLOW + +info() { + local mesg=$1; shift + printf "${GREEN}[T1]${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" +} + +info2() { + local mesg=$1; shift + printf "${BLUE} ->${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" +} + +error() { + local mesg=$1; shift + printf "${RED}[T1] $(gettext "ERROR:")${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2 +} + +_ROOT_PATTERN="flake.nix" +if [ ! -r "$_ROOT_PATTERN" ]; then + error "Not in T1 root directory" "Please run nix develop at the root of the T1 project directory" + exit 1 +fi + +mkdir -p .cache/dev-mode +_CTX=.cache/dev-mode/state.json +if [ ! -r "$_CTX" ]; then + printf "{}" > "$_CTX" +fi + +_CFG="" +get_config() { + local cfg=$(jq -r ".config" "$_CTX") + _CFG="$cfg" + echo "$_CFG" +} + +_config_is_set() { + _CFG=$(get_config) + if [[ -z "$_CFG" || "$_CFG" = "null" ]]; then + info "Config not set yet, use 'set_config ' to set config" + info2 "Available configs: ${BLUE}$(list_config | xargs)${ALL_OFF}" + return 1 + else + return 0 + fi +} + +list_config() { + nix --no-warn-dirty eval ".#t1.allConfigs" --json | jq -r 'keys[]' +} + +set_config() { + if [[ -z "$@" ]]; then + error "No argument was given, use 'set_config ' to set config" + return 1 + fi + + local config=$1; shift + local allConfigsArray=( $(list_config) ) + + local verifiedConfig="" + for c in ${allConfigsArray[@]}; do + if [[ "$c" == "$config" ]]; then + verifiedConfig="$c" + fi + done + if [[ -z "$verifiedConfig" ]]; then + error "Config '$config' is not supported, available configs: ${allConfigsArray[*]}" + return 1 + fi + + local newCtx=$(jq --arg config "$config" '.config = $config' $_CTX) + printf "$newCtx" > "$_CTX" + + _CFG=$(get_config) + + info "Config is set to ${BLUE}${_CFG}${ALL_OFF}" +} + +_get_ip_attrs() { + nix --no-warn-dirty eval --json ".#legacyPackages.x86_64-linux" \ + --apply "pkgs: pkgs.lib.filterAttrs (_: v: pkgs.lib.isDerivation v) pkgs.t1.$_CFG.ip" \ + | jq -r 'keys[]' +} + +list_emulator() { + _get_ip_attrs | grep -E '(-emu$|-emu-trace$)' +} + +_EMU="" +get_emulator() { + local emu=$(jq -r ".emulator" "$_CTX") + if [[ -z "$emu" || "$emu" = "null" ]]; then + error "Emulator not set yet, please use 'set_emulator '" + return 1 + fi + + _EMU="$emu" + echo "$_EMU" +} + +_emulator_is_set() { + _EMU=$(get_emulator) + if [[ -z "$_EMU" || "$_EMU" = "null" ]]; then + return 1 + else + return 0 + fi +} + +set_emulator() { + if [[ -z "$@" ]]; then + error "No argument was given, use 'set_emulator ' to set main testing emulator" + return 1 + fi + + local emulator=$1; shift + local allEmuArray=( $(list_emulator) ) + + local verifiedEmulator="" + for e in ${allEmuArray[@]}; do + if [[ "$e" == "$emulator" ]]; then + verifiedEmulator="$e" + fi + done + if [[ -z "$verifiedEmulator" ]]; then + error "Emulator '$emulator' is not supported, available emulators: ${allEmuArray[*]}" + return 1 + fi + + local newCtx=$(jq --arg emulator "$verifiedEmulator" '.emulator = $emulator' $_CTX) + printf "$newCtx" > "$_CTX" + + _EMU=$(get_emulator) + + info "Emulator is set to ${BLUE}${_EMU}${ALL_OFF}" +} + +build() { + if [[ -z "$@" || "$@" = "help" ]]; then + error "Use ${BLUE}'build '${ALL_OFF} to build" + info2 "Available attrs" + _get_ip_attrs + return 1 + fi + + local attr=$1; shift + local availableAttrsArray=( $(_get_ip_attrs) ) + local verifiedAttr="" + for a in ${availableAttrsArray[@]}; do + if [ "$a" = "$attr" ]; then + verifiedAttr="$a" + fi + done + if [ -z "$verifiedAttr" ]; then + error "Invalid attr '$attr', available attrs:" + info2 "${availableAttrsArray[*]}" + return 1 + fi + + if ! _config_is_set; then + return 1 + fi + + local fullAttr=".#t1.$_CFG.ip.$attr" + info "Building $fullAttr to result dir ./result-$attr with flag '$@'" + nix build --no-warn-dirty --print-build-logs --out-link result-$attr "$fullAttr" $@ +} + +test() { + if [[ -z "$@" || "$@" = "help" ]]; then + error "Use 'test [emulator]' to run a test" + return 1 + fi + + local case=$1; shift + + if [[ -z "$_EMU" ]]; then + error "Emulator is not set yet" + info2 "Use 'set_emulator ' to set the main testing emulator" + return 1 + fi + + if ! printf "$case" | grep -Eq '\S\.\S'; then + error "Invalid case form '$case', expect '.'" + return 1 + fi + + local hasAttr=$(nix eval --json --no-warn-dirty ".#t1.$_CFG.ip.cases" --apply "cases: cases ? $case") + if [[ "x$hasAttr" = "xfalse" ]]; then + error "Unknown cases $case" + return 1 + fi + + info "Running test case $case with emulator $_EMU, output result to ./result-$case" + nix build --no-warn-dirty --print-build-logs --out-link ./result-$case ".#t1.$_CFG.ip.cases.$case.emu-result" +} + +main() { + info "Welcome to T1 dev mode, here are some convenient commands" + info2 "* set_config: set current configs" + info2 "* list_config: get all available configs" + info2 "* get_config: print current config" + info2 "* set_emulator: set current emulators" + info2 "* list_emulator: get all available emulators" + info2 "* get_emulator: print the main testing emulator" + info2 "* build: build T1 artifacts with config $_CFG" + info2 "* test: run test case with specific emulator" + + echo + echo + + if _config_is_set; then + info "Config is set to ${BLUE}$_CFG${ALL_OFF}, use ${GREEN}'set_config '${ALL_OFF} to modify config" + fi + + if _emulator_is_set; then + info "Emulator is set to ${BLUE}${_EMU}${ALL_OFF}, use ${GREEN}'set_emulator '${ALL_OFF} to modify emulator" + fi +} + +main diff --git a/nix/t1/default.nix b/nix/t1/default.nix index 2d5829d42..a3d8603cf 100644 --- a/nix/t1/default.nix +++ b/nix/t1/default.nix @@ -74,10 +74,10 @@ lib.makeScope newScope ]; }; - om = innerSelf.callPackage ./om.nix { inherit mlirbc; }; + om = innerSelf.callPackage ./om.nix { inherit mlirbc omreader; }; omreader = self.omreader-unwrapped.mkWrapper { inherit mlirbc; }; - emu-om = innerSelf.callPackage ./om.nix { mlirbc = emu-mlirbc; }; + emu-om = innerSelf.callPackage ./om.nix { omreader = emu-omreader; mlirbc = emu-mlirbc; }; emu-omreader = self.omreader-unwrapped.mkWrapper { mlirbc = emu-mlirbc; }; omGet = args: lib.fileContents (runCommand "get-${args}" { } '' ${emu-omreader}/bin/omreader ${args} > $out @@ -93,12 +93,6 @@ lib.makeScope newScope inherit (ip) verilator-emu verilator-emu-trace vcs-emu vcs-emu-trace rtlDesignMetadata; }; - # for the convenience to use x86 cases on non-x86 machines, avoiding the extra build time - cases-x86 = - if system == "x86-64-linux" - then self.cases - else pkgsX86.t1."${configName}".cases; - emu-elaborate = innerSelf.callPackage ./elaborate.nix { target = "ipemu"; }; emu-mlirbc = innerSelf.callPackage ./mlirbc.nix { elaborate = emu-elaborate; };