From 8656b1c08f34c3585ac8ec0e7285fbaaad6a7bc8 Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Mon, 19 Aug 2013 19:50:04 +0200
Subject: Added support for bufif0/bufif1 primitives

---
 frontends/ast/simplify.cc | 90 ++++++++++++++++++++++++++++++-----------------
 frontends/verilog/lexer.l |  2 +-
 2 files changed, 59 insertions(+), 33 deletions(-)

diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index 440d38618..1d381740b 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -498,39 +498,65 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage)
 		}
 		children.clear();
 
-		AstNodeType op_type = AST_NONE;
-		bool invert_results = false;
-
-		if (str == "and")
-			op_type = AST_BIT_AND;
-		if (str == "nand")
-			op_type = AST_BIT_AND, invert_results = true;
-		if (str == "or")
-			op_type = AST_BIT_OR;
-		if (str == "nor")
-			op_type = AST_BIT_OR, invert_results = true;
-		if (str == "xor")
-			op_type = AST_BIT_XOR;
-		if (str == "xnor")
-			op_type = AST_BIT_XOR, invert_results = true;
-		if (str == "buf")
-			op_type = AST_POS;
-		if (str == "not")
-			op_type = AST_POS, invert_results = true;
-		assert(op_type != AST_NONE);
-
-		AstNode *node = children_list[1];
-		if (op_type != AST_POS)
-			for (size_t i = 2; i < children_list.size(); i++)
-				node = new AstNode(op_type, node, children_list[i]);
-		if (invert_results)
-			node = new AstNode(AST_BIT_NOT, node);
+		if (str == "bufif0" || str == "bufif1")
+		{
+			if (children_list.size() != 3)
+				log_error("Invalid number of arguments for primitive `%s' at %s:%d!\n",
+						str.c_str(), filename.c_str(), linenum);
 
-		str.clear();
-		type = AST_ASSIGN;
-		children.push_back(children_list[0]);
-		children.push_back(node);
-		did_something = true;
+			std::vector<RTLIL::State> z_const(1, RTLIL::State::Sz);
+
+			AstNode *node = new AstNode(AST_TERNARY, children_list.at(2));
+			if (str == "bufif0") {
+				node->children.push_back(AstNode::mkconst_bits(z_const, false));
+				node->children.push_back(children_list.at(1));
+			} else {
+				node->children.push_back(children_list.at(1));
+				node->children.push_back(AstNode::mkconst_bits(z_const, false));
+			}
+
+			str.clear();
+			type = AST_ASSIGN;
+			children.push_back(children_list.at(0));
+			children.push_back(node);
+			did_something = true;
+		}
+		else
+		{
+			AstNodeType op_type = AST_NONE;
+			bool invert_results = false;
+
+			if (str == "and")
+				op_type = AST_BIT_AND;
+			if (str == "nand")
+				op_type = AST_BIT_AND, invert_results = true;
+			if (str == "or")
+				op_type = AST_BIT_OR;
+			if (str == "nor")
+				op_type = AST_BIT_OR, invert_results = true;
+			if (str == "xor")
+				op_type = AST_BIT_XOR;
+			if (str == "xnor")
+				op_type = AST_BIT_XOR, invert_results = true;
+			if (str == "buf")
+				op_type = AST_POS;
+			if (str == "not")
+				op_type = AST_POS, invert_results = true;
+			assert(op_type != AST_NONE);
+
+			AstNode *node = children_list[1];
+			if (op_type != AST_POS)
+				for (size_t i = 2; i < children_list.size(); i++)
+					node = new AstNode(op_type, node, children_list[i]);
+			if (invert_results)
+				node = new AstNode(AST_BIT_NOT, node);
+
+			str.clear();
+			type = AST_ASSIGN;
+			children.push_back(children_list[0]);
+			children.push_back(node);
+			did_something = true;
+		}
 	}
 
 	// replace dynamic ranges in left-hand side expressions (e.g. "foo[bar] <= 1'b1;") with
diff --git a/frontends/verilog/lexer.l b/frontends/verilog/lexer.l
index cc7590ca5..e873f9d91 100644
--- a/frontends/verilog/lexer.l
+++ b/frontends/verilog/lexer.l
@@ -169,7 +169,7 @@ namespace VERILOG_FRONTEND {
 }
 <STRING>.	{ yymore(); }
 
-and|nand|or|nor|xor|xnor|not|buf {
+and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1 {
 	frontend_verilog_yylval.string = new std::string(yytext);
 	return TOK_PRIMITIVE;
 }
-- 
cgit v1.2.3