New behavior for front-end handling of whiteboxes
authorClifford Wolf <clifford@clifford.at>
Sat, 20 Apr 2019 20:24:50 +0000 (22:24 +0200)
committerClifford Wolf <clifford@clifford.at>
Sat, 20 Apr 2019 20:24:50 +0000 (22:24 +0200)
Signed-off-by: Clifford Wolf <clifford@clifford.at>
README.md
frontends/ast/ast.cc
frontends/ast/ast.h
frontends/verilog/verilog_frontend.cc
frontends/verilog/verilog_frontend.h
frontends/verilog/verilog_parser.y

index 5c94c34e5d66e5ec5f21c17752f20ca34ba2d2d5..7f90cb3c21d563a21306bd0bcb172d20f1d58ad3 100644 (file)
--- a/README.md
+++ b/README.md
@@ -316,6 +316,9 @@ Verilog Attributes and non-standard features
   ``blackbox``, but is for whitebox modules, i.e. library modules that
   contain a behavioral model of the cell type.
 
+- The ``lib_whitebox`` attribute overwrites ``whitebox`` when ``read_verilog``
+  is run in `-lib` mode. Otherwise it's automatically removed.
+
 - The ``dynports`` attribute is used by the Verilog front-end to mark modules
   that have ports with a width that depends on a parameter.
 
index 720b3f3d15b1df265728a174b196d4028c9af396..e4f18a2acbe23a8f9df50b3b032a70d4cdcb7a2a 100644 (file)
@@ -46,7 +46,7 @@ namespace AST {
 // instantiate global variables (private API)
 namespace AST_INTERNAL {
        bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
-       bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_wb, flag_noopt, flag_icells, flag_autowire;
+       bool flag_nomem2reg, flag_mem2reg, flag_noblackbox, flag_lib, flag_nowb, flag_noopt, flag_icells, flag_autowire;
        AstNode *current_ast, *current_ast_mod;
        std::map<std::string, AstNode*> current_scope;
        const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL;
@@ -956,18 +956,67 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
                        log("--- END OF AST DUMP ---\n");
                }
 
-               if (flag_wb) {
-                       if (!ast->attributes.count("\\whitebox"))
-                               goto blackbox_module;
+               if (flag_nowb && ast->attributes.count("\\whitebox")) {
+                       delete ast->attributes.at("\\whitebox");
+                       ast->attributes.erase("\\whitebox");
+               }
+
+               if (ast->attributes.count("\\lib_whitebox")) {
+                       if (!flag_lib || flag_nowb) {
+                               delete ast->attributes.at("\\lib_whitebox");
+                               ast->attributes.erase("\\lib_whitebox");
+                       } else {
+                               if (ast->attributes.count("\\whitebox")) {
+                                       delete ast->attributes.at("\\whitebox");
+                                       ast->attributes.erase("\\whitebox");
+                               }
+                               AstNode *n = ast->attributes.at("\\lib_whitebox");
+                               ast->attributes["\\whitebox"] = n;
+                               ast->attributes.erase("\\lib_whitebox");
+                       }
+               }
+
+               bool blackbox_module = flag_lib;
+
+               if (!blackbox_module && ast->attributes.count("\\blackbox")) {
+                       AstNode *n = ast->attributes.at("\\blackbox");
+                       if (n->type != AST_CONSTANT)
+                               log_file_error(ast->filename, ast->linenum, "Blackbox attribute with non-constant value!\n");
+                       blackbox_module = n->asBool();
+               }
+
+               if (!blackbox_module && !flag_noblackbox)
+               {
+                       for (auto child : ast->children) {
+                               if (child->type == AST_WIRE && (child->is_input || child->is_output))
+                                       continue;
+                               if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)
+                                       continue;
+                               goto noblackbox;
+                       }
+                       blackbox_module = 1;
+               }
+
+       noblackbox:
+               if (blackbox_module && ast->attributes.count("\\whitebox")) {
                        AstNode *n = ast->attributes.at("\\whitebox");
                        if (n->type != AST_CONSTANT)
                                log_file_error(ast->filename, ast->linenum, "Whitebox attribute with non-constant value!\n");
-                       if (!n->asBool())
-                               goto blackbox_module;
+                       blackbox_module = !n->asBool();
                }
 
-               if (flag_lib) {
-       blackbox_module:
+               if (blackbox_module)
+               {
+                       if (ast->attributes.count("\\whitebox")) {
+                               delete ast->attributes.at("\\whitebox");
+                               ast->attributes.erase("\\whitebox");
+                       }
+
+                       if (ast->attributes.count("\\lib_whitebox")) {
+                               delete ast->attributes.at("\\lib_whitebox");
+                               ast->attributes.erase("\\lib_whitebox");
+                       }
+
                        std::vector<AstNode*> new_children;
                        for (auto child : ast->children) {
                                if (child->type == AST_WIRE && (child->is_input || child->is_output)) {
@@ -980,12 +1029,12 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
                                        delete child;
                                }
                        }
+
                        ast->children.swap(new_children);
-                       if (ast->attributes.count("\\whitebox")) {
-                               delete ast->attributes.at("\\whitebox");
-                               ast->attributes.erase("\\whitebox");
+
+                       if (ast->attributes.count("\\blackbox") == 0) {
+                               ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false);
                        }
-                       ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false);
                }
 
                ignoreThisSignalsInInitial = RTLIL::SigSpec();
@@ -1024,8 +1073,9 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
        current_module->nomeminit = flag_nomeminit;
        current_module->nomem2reg = flag_nomem2reg;
        current_module->mem2reg = flag_mem2reg;
+       current_module->noblackbox = flag_noblackbox;
        current_module->lib = flag_lib;
-       current_module->wb = flag_wb;
+       current_module->nowb = flag_nowb;
        current_module->noopt = flag_noopt;
        current_module->icells = flag_icells;
        current_module->autowire = flag_autowire;
@@ -1042,7 +1092,7 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
 
 // create AstModule instances for all modules in the AST tree and add them to 'design'
 void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil,
-               bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool wb, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire)
+               bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire)
 {
        current_ast = ast;
        flag_dump_ast1 = dump_ast1;
@@ -1055,8 +1105,9 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
        flag_nomeminit = nomeminit;
        flag_nomem2reg = nomem2reg;
        flag_mem2reg = mem2reg;
+       flag_noblackbox = noblackbox;
        flag_lib = lib;
-       flag_wb = wb;
+       flag_nowb = nowb;
        flag_noopt = noopt;
        flag_icells = icells;
        flag_autowire = autowire;
@@ -1390,8 +1441,9 @@ std::string AstModule::derive_common(RTLIL::Design *design, dict<RTLIL::IdString
        flag_nomeminit = nomeminit;
        flag_nomem2reg = nomem2reg;
        flag_mem2reg = mem2reg;
+       flag_noblackbox = noblackbox;
        flag_lib = lib;
-       flag_wb = wb;
+       flag_nowb = nowb;
        flag_noopt = noopt;
        flag_icells = icells;
        flag_autowire = autowire;
index 610e00fbf290c45c3483a818694aed37751f748d..281cbe0865ba8987fed475e9c7d71944c3ab9d14 100644 (file)
@@ -283,13 +283,13 @@ namespace AST
 
        // process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code
        void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil, bool nolatches, bool nomeminit,
-                       bool nomem2reg, bool mem2reg, bool lib, bool wb, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire);
+                       bool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire);
 
        // parametric modules are supported directly by the AST library
        // therefore we need our own derivate of RTLIL::Module with overloaded virtual functions
        struct AstModule : RTLIL::Module {
                AstNode *ast;
-               bool nolatches, nomeminit, nomem2reg, mem2reg, lib, wb, noopt, icells, autowire;
+               bool nolatches, nomeminit, nomem2reg, mem2reg, noblackbox, lib, nowb, noopt, icells, autowire;
                ~AstModule() YS_OVERRIDE;
                RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail) YS_OVERRIDE;
                RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, dict<RTLIL::IdString, RTLIL::IdString> modports, bool mayfail) YS_OVERRIDE;
index 4e2c5abb5b8297d6f2fa5a83d5851a045bd8d699..ed6ce2ecb80075ed5c19eb1eeb8eb7fccd0f3939 100644 (file)
@@ -145,12 +145,18 @@ struct VerilogFrontend : public Frontend {
                log("    -nodpi\n");
                log("        disable DPI-C support\n");
                log("\n");
+               log("    -noblackbox\n");
+               log("        do not automatically add a (* blackbox *) attribute to an\n");
+               log("        empty module.\n");
+               log("\n");
                log("    -lib\n");
                log("        only create empty blackbox modules. This implies -DBLACKBOX.\n");
+               log("        modules with the (* whitebox *) attribute will be preserved.\n");
+               log("        (* lib_whitebox *) will be treated like (* whitebox *).\n");
                log("\n");
-               log("    -wb\n");
-               log("        like -lib, except do not touch modules with the whitebox\n");
-               log("        attribute set. This also implies -DBLACKBOX.\n");
+               log("    -nowb\n");
+               log("        delete (* whitebox *) and (* lib_whitebox *) attributes from\n");
+               log("        all modules.\n");
                log("\n");
                log("    -noopt\n");
                log("        don't perform basic optimizations (such as const folding) in the\n");
@@ -231,8 +237,9 @@ struct VerilogFrontend : public Frontend {
                formal_mode = false;
                norestrict_mode = false;
                assume_asserts_mode = false;
+               noblackbox_mode = false;
                lib_mode = false;
-               wb_mode = false;
+               nowb_mode = false;
                default_nettype_wire = true;
 
                log_header(design, "Executing Verilog-2005 frontend.\n");
@@ -334,14 +341,17 @@ struct VerilogFrontend : public Frontend {
                                flag_nodpi = true;
                                continue;
                        }
-                       if (arg == "-lib" && !wb_mode) {
+                       if (arg == "-noblackbox") {
+                               noblackbox_mode = true;
+                               continue;
+                       }
+                       if (arg == "-lib") {
                                lib_mode = true;
                                defines_map["BLACKBOX"] = string();
                                continue;
                        }
-                       if (arg == "-wb" && !lib_mode) {
-                               wb_mode = true;
-                               defines_map["BLACKBOX"] = string();
+                       if (arg == "-nowb") {
+                               nowb_mode = true;
                                continue;
                        }
                        if (arg == "-noopt") {
@@ -439,7 +449,8 @@ struct VerilogFrontend : public Frontend {
                if (flag_nodpi)
                        error_on_dpi_function(current_ast);
 
-               AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, lib_mode, wb_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
+               AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches,
+                               flag_nomeminit, flag_nomem2reg, flag_mem2reg, noblackbox_mode, lib_mode, nowb_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
 
                if (!flag_nopp)
                        delete lexin;
index b5cf70c5798943cb3e5680de4c2f69ce772d7b16..ca40946cbdaade7003dee91f8ff93494f1028642 100644 (file)
@@ -69,11 +69,14 @@ namespace VERILOG_FRONTEND
        // running in -assert-assumes mode
        extern bool assert_assumes_mode;
 
+       // running in -noblackbox mode
+       extern bool noblackbox_mode;
+
        // running in -lib mode
        extern bool lib_mode;
 
-       // running in -wb mode
-       extern bool wb_mode;
+       // running in -nowb mode
+       extern bool nowb_mode;
 
        // lexer input stream
        extern std::istream *lexin;
index 122eb123047fe3d13a741173b568722f26107cdd..40968d17a12bcaf7052b00b0ca53b62e1b1a3b89 100644 (file)
@@ -59,7 +59,7 @@ namespace VERILOG_FRONTEND {
        std::vector<char> case_type_stack;
        bool do_not_require_port_stubs;
        bool default_nettype_wire;
-       bool sv_mode, formal_mode, lib_mode, wb_mode;
+       bool sv_mode, formal_mode, noblackbox_mode, lib_mode, nowb_mode;
        bool noassert_mode, noassume_mode, norestrict_mode;
        bool assume_asserts_mode, assert_assumes_mode;
        bool current_wire_rand, current_wire_const;
@@ -1906,7 +1906,7 @@ basic_expr:
                if ($4->substr(0, 1) != "'")
                        frontend_verilog_yyerror("Cast operation must be applied on sized constants e.g. (<expr>)<constval> , while %s is not a sized constant.", $4->c_str());
                AstNode *bits = $2;
-               AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode && !wb_mode);
+               AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
                if (val == NULL)
                        log_error("Value conversion failed: `%s'\n", $4->c_str());
                $$ = new AstNode(AST_TO_BITS, bits, val);
@@ -1917,7 +1917,7 @@ basic_expr:
                        frontend_verilog_yyerror("Cast operation must be applied on sized constants, e.g. <ID>\'d0, while %s is not a sized constant.", $2->c_str());
                AstNode *bits = new AstNode(AST_IDENTIFIER);
                bits->str = *$1;
-               AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode && !wb_mode);
+               AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
                if (val == NULL)
                        log_error("Value conversion failed: `%s'\n", $2->c_str());
                $$ = new AstNode(AST_TO_BITS, bits, val);
@@ -1925,14 +1925,14 @@ basic_expr:
                delete $2;
        } |
        TOK_CONSTVAL TOK_CONSTVAL {
-               $$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode && !wb_mode);
+               $$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
                if ($$ == NULL || (*$2)[0] != '\'')
                        log_error("Value conversion failed: `%s%s'\n", $1->c_str(), $2->c_str());
                delete $1;
                delete $2;
        } |
        TOK_CONSTVAL {
-               $$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode && !wb_mode);
+               $$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
                if ($$ == NULL)
                        log_error("Value conversion failed: `%s'\n", $1->c_str());
                delete $1;