From 64ccbf8510d33f08af7743974d061db166da1832 Mon Sep 17 00:00:00 2001
From: Florian Zeitz <florob@babelmonkeys.de>
Date: Mon, 17 Aug 2015 15:27:35 +0200
Subject: [PATCH] Warn on literals exceeding the specified bit width

---
 frontends/verilog/const2ast.cc | 73 ++++++++++++++++++----------------
 1 file changed, 39 insertions(+), 34 deletions(-)

diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc
index ebecb92f2..6a9326898 100644
--- a/frontends/verilog/const2ast.cc
+++ b/frontends/verilog/const2ast.cc
@@ -96,44 +96,51 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
 	if (base == 10 && GetSize(digits) == 1 && digits.front() >= 0xf0)
 		base = 2;
 
+	data.clear();
+
 	if (base == 10) {
-		data.clear();
-		if (len_in_bits < 0) {
-			while (!digits.empty())
-				data.push_back(my_decimal_div_by_two(digits) ? RTLIL::S1 : RTLIL::S0);
-			while (data.size() < 32)
-				data.push_back(RTLIL::S0);
-		} else {
-			for (int i = 0; i < len_in_bits; i++)
-				data.push_back(my_decimal_div_by_two(digits) ? RTLIL::S1 : RTLIL::S0);
+		while (!digits.empty())
+			data.push_back(my_decimal_div_by_two(digits) ? RTLIL::S1 : RTLIL::S0);
+	} else {
+		int bits_per_digit = my_ilog2(base-1);
+		for (auto it = digits.rbegin(), e = digits.rend(); it != e; it++) {
+			for (int i = 0; i < bits_per_digit; i++) {
+				int bitmask = 1 << i;
+				if (*it == 0xf0)
+					data.push_back(case_type == 'x' ? RTLIL::Sa : RTLIL::Sx);
+				else if (*it == 0xf1)
+					data.push_back(case_type == 'x' || case_type == 'z' ? RTLIL::Sa : RTLIL::Sz);
+				else if (*it == 0xf2)
+					data.push_back(RTLIL::Sa);
+				else
+					data.push_back((*it & bitmask) ? RTLIL::S1 : RTLIL::S0);
+			}
 		}
-		return;
 	}
 
-	int bits_per_digit = my_ilog2(base-1);
-	if (len_in_bits < 0)
-		len_in_bits = std::max<int>(digits.size() * bits_per_digit, 32);
+	int len = GetSize(data);
+	RTLIL::State msb = data.back();
 
-	data.clear();
-	data.resize(len_in_bits);
-
-	for (int i = 0; i < len_in_bits; i++) {
-		int bitmask = 1 << (i % bits_per_digit);
-		int digitidx = digits.size() - (i / bits_per_digit) - 1;
-		if (digitidx < 0) {
-			if (i > 0 && (data[i-1] == RTLIL::Sz || data[i-1] == RTLIL::Sx || data[i-1] == RTLIL::Sa))
-				data[i] = data[i-1];
-			else
-				data[i] = RTLIL::S0;
-		} else if (digits[digitidx] == 0xf0)
-			data[i] = case_type == 'x' ? RTLIL::Sa : RTLIL::Sx;
-		else if (digits[digitidx] == 0xf1)
-			data[i] = case_type == 'x' || case_type == 'z' ? RTLIL::Sa : RTLIL::Sz;
-		else if (digits[digitidx] == 0xf2)
-			data[i] = RTLIL::Sa;
-		else
-			data[i] = (digits[digitidx] & bitmask) ? RTLIL::S1 : RTLIL::S0;
+	if (len_in_bits < 0) {
+		if (len < 32)
+			data.resize(32, msb == RTLIL::S0 || msb == RTLIL::S1 ? RTLIL::S0 : msb);
+		return;
+	}
+
+	for (len = len - 1; len >= 0; len--)
+		if (data[len] == RTLIL::S1)
+			break;
+	if (msb == RTLIL::S0 || msb == RTLIL::S1) {
+		len += 1;
+		data.resize(len_in_bits, RTLIL::S0);
+	} else {
+		len += 2;
+		data.resize(len_in_bits, msb);
 	}
+
+	if (len > len_in_bits)
+		log_warning("(Literal has a width of %d bit, but value requires %d bit. (%s:%d)\n",
+			len_in_bits, len, current_filename.c_str(), get_line_num());
 }
 
 // convert the Verilog code for a constant to an AST node
@@ -220,8 +227,6 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
 		if (len_in_bits < 0) {
 			if (is_signed && data.back() == RTLIL::S1)
 				data.push_back(RTLIL::S0);
-			while (data.size() < 32)
-				data.push_back(RTLIL::S0);
 		}
 		return AstNode::mkconst_bits(data, is_signed);
 	}
-- 
2.30.2