aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--frontends/verilog/preproc.cc34
-rw-r--r--frontends/verilog/preproc.h1
-rw-r--r--tests/verilog/macro_arg_tromp.sv21
-rw-r--r--tests/verilog/macro_arg_tromp.ys2
4 files changed, 54 insertions, 4 deletions
diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc
index 4b9ebe0aa..17f567587 100644
--- a/frontends/verilog/preproc.cc
+++ b/frontends/verilog/preproc.cc
@@ -36,6 +36,7 @@
#include "verilog_frontend.h"
#include "kernel/log.h"
#include <assert.h>
+#include <stack>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
@@ -334,6 +335,11 @@ define_map_t::add(const std::string &name, const std::string &txt, const arg_map
defines[name] = std::unique_ptr<define_body_t>(new define_body_t(txt, args));
}
+void define_map_t::add(const std::string &name, const define_body_t &body)
+{
+ defines[name] = std::unique_ptr<define_body_t>(new define_body_t(body));
+}
+
void define_map_t::merge(const define_map_t &map)
{
for (const auto &pr : map.defines) {
@@ -440,7 +446,17 @@ static bool read_argument(std::string &dest)
}
}
-static bool try_expand_macro(define_map_t &defines, std::string &tok)
+using macro_arg_stack_t = std::stack<std::pair<std::string, define_body_t>>;
+
+static void restore_macro_arg(define_map_t &defines, macro_arg_stack_t &macro_arg_stack)
+{
+ log_assert(!macro_arg_stack.empty());
+ auto &overwritten_arg = macro_arg_stack.top();
+ defines.add(overwritten_arg.first, overwritten_arg.second);
+ macro_arg_stack.pop();
+}
+
+static bool try_expand_macro(define_map_t &defines, macro_arg_stack_t &macro_arg_stack, std::string &tok)
{
if (tok == "`\"") {
std::string literal("\"");
@@ -450,7 +466,7 @@ static bool try_expand_macro(define_map_t &defines, std::string &tok)
if (ntok == "`\"") {
insert_input(literal+"\"");
return true;
- } else if (!try_expand_macro(defines, ntok)) {
+ } else if (!try_expand_macro(defines, macro_arg_stack, ntok)) {
literal += ntok;
}
}
@@ -495,6 +511,10 @@ static bool try_expand_macro(define_map_t &defines, std::string &tok)
args.push_back(arg);
}
for (const auto &pr : body->args.get_vals(name, args)) {
+ if (const define_body_t *existing = defines.find(pr.first)) {
+ macro_arg_stack.push({pr.first, *existing});
+ insert_input("`__restore_macro_arg ");
+ }
defines.add(pr.first, pr.second);
}
} else {
@@ -725,6 +745,7 @@ frontend_verilog_preproc(std::istream &f,
defines.merge(pre_defines);
defines.merge(global_defines_cache);
+ macro_arg_stack_t macro_arg_stack;
std::vector<std::string> filename_stack;
// We are inside pass_level levels of satisfied ifdefs, and then within
// fail_level levels of unsatisfied ifdefs. The unsatisfied ones are
@@ -828,7 +849,7 @@ frontend_verilog_preproc(std::istream &f,
if (tok == "`include") {
skip_spaces();
std::string fn = next_token(true);
- while (try_expand_macro(defines, fn)) {
+ while (try_expand_macro(defines, macro_arg_stack, fn)) {
fn = next_token();
}
while (1) {
@@ -935,7 +956,12 @@ frontend_verilog_preproc(std::istream &f,
continue;
}
- if (try_expand_macro(defines, tok))
+ if (tok == "`__restore_macro_arg") {
+ restore_macro_arg(defines, macro_arg_stack);
+ continue;
+ }
+
+ if (try_expand_macro(defines, macro_arg_stack, tok))
continue;
output_code.push_back(tok);
diff --git a/frontends/verilog/preproc.h b/frontends/verilog/preproc.h
index e1048156c..330855a92 100644
--- a/frontends/verilog/preproc.h
+++ b/frontends/verilog/preproc.h
@@ -42,6 +42,7 @@ struct define_map_t
// Add a definition, overwriting any existing definition for name.
void add(const std::string &name, const std::string &txt, const arg_map_t *args = nullptr);
+ void add(const std::string &name, const define_body_t &body);
// Merge in another map of definitions (which take precedence
// over anything currently defined).
diff --git a/tests/verilog/macro_arg_tromp.sv b/tests/verilog/macro_arg_tromp.sv
new file mode 100644
index 000000000..a9c68a417
--- /dev/null
+++ b/tests/verilog/macro_arg_tromp.sv
@@ -0,0 +1,21 @@
+// Taken from: https://github.com/YosysHQ/yosys/issues/2867
+
+`define MIN(x, y) ((x) < (y) ? (x) : (y))
+`define CEIL_DIV(x, y) (((x) / (y)) + `MIN((x) % (y), 1))
+
+module pad_msg1 (input logic [`MIN(512*`CEIL_DIV(64, 512), 64)-1:0] x,
+ output logic [`MIN(512*`CEIL_DIV(64, 512), 64)-1:0] y);
+ assign y[63:0] = x;
+endmodule
+
+module pad_msg2 (input logic [((512*`CEIL_DIV(64, 512)) < (64) ? (512*`CEIL_DIV(64,512)) : (64))-1:0] x,
+ output logic [((512*`CEIL_DIV(64, 512)) < (64) ? (512*`CEIL_DIV(64,512)) : (64))-1:0] y);
+ assign y[63:0] = x;
+endmodule
+
+module top(...);
+`define add(x) x +
+input [3:0] A;
+output [3:0] B;
+assign B = `add(`add(3)A)A;
+endmodule
diff --git a/tests/verilog/macro_arg_tromp.ys b/tests/verilog/macro_arg_tromp.ys
new file mode 100644
index 000000000..e8bd58e9b
--- /dev/null
+++ b/tests/verilog/macro_arg_tromp.ys
@@ -0,0 +1,2 @@
+logger -expect-no-warnings
+read_verilog -sv macro_arg_tromp.sv