diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index 23404f844..8d0ba4cf6 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -254,6 +254,65 @@ static void checkLabelsMatch(const char *element, const std::string *before, con
 			element, before->c_str() + 1, after->c_str() + 1);
 }
 
+// This transforms a loop like
+//   for (genvar i = 0; i < 10; i++) begin : blk
+// to
+//   genvar _i;
+//   for (_i = 0; _i < 10; _i++) begin : blk
+//     localparam i = _i;
+// where `_i` is actually some auto-generated name.
+static void rewriteGenForDeclInit(AstNode *loop)
+{
+	// check if this generate for loop contains an inline declaration
+	log_assert(loop->type == AST_GENFOR);
+	AstNode *decl = loop->children[0];
+	if (decl->type == AST_ASSIGN_EQ)
+		return;
+	log_assert(decl->type == AST_GENVAR);
+	log_assert(loop->children.size() == 5);
+
+	// identify each component of the loop
+	AstNode *init = loop->children[1];
+	AstNode *cond = loop->children[2];
+	AstNode *incr = loop->children[3];
+	AstNode *body = loop->children[4];
+	log_assert(init->type == AST_ASSIGN_EQ);
+	log_assert(incr->type == AST_ASSIGN_EQ);
+	log_assert(body->type == AST_GENBLOCK);
+
+	// create a unique name for the genvar
+	std::string old_str = decl->str;
+	std::string new_str = stringf("$genfordecl$%d$%s", autoidx++, old_str.c_str());
+
+	// rename and move the genvar declaration to the containing description
+	decl->str = new_str;
+	loop->children.erase(loop->children.begin());
+	log_assert(current_ast_mod != nullptr);
+	current_ast_mod->children.push_back(decl);
+
+	// create a new localparam with old name so that the items in the loop
+	// can simply use the old name and shadow it as necessary
+	AstNode *indirect = new AstNode(AST_LOCALPARAM);
+	indirect->str = old_str;
+	AstNode *ident = new AstNode(AST_IDENTIFIER);
+	ident->str = new_str;
+	indirect->children.push_back(ident);
+
+	body->children.insert(body->children.begin(), indirect);
+
+	// only perform the renaming for the initialization, guard, and
+	// incrementation to enable proper shadowing of the synthetic localparam
+	std::function<void(AstNode*)> substitute = [&](AstNode *node) {
+		if (node->type == AST_IDENTIFIER && node->str == old_str)
+			node->str = new_str;
+		for (AstNode *child : node->children)
+			substitute(child);
+	};
+	substitute(init);
+	substitute(cond);
+	substitute(incr);
+}
+
 %}
 
 %define api.prefix {frontend_verilog_yy}
@@ -321,6 +380,7 @@ static void checkLabelsMatch(const char *element, const std::string *before, con
 %type <al> attr case_attr
 %type <ast> struct_union
 %type <ast_node_type> asgn_binop
+%type <ast> genvar_identifier
 
 %type <specify_target_ptr> specify_target
 %type <specify_triple_ptr> specify_triple specify_opt_triple
@@ -2978,16 +3038,50 @@ gen_stmt_or_module_body_stmt:
 		free_attr($1);
 	};
 
+genvar_identifier:
+	TOK_ID {
+		$$ = new AstNode(AST_IDENTIFIER);
+		$$->str = *$1;
+		delete $1;
+	};
+
+genvar_initialization:
+	TOK_GENVAR genvar_identifier {
+		frontend_verilog_yyerror("Generate for loop variable declaration is missing initialization!");
+	} |
+	TOK_GENVAR genvar_identifier '=' expr {
+		if (!sv_mode)
+			frontend_verilog_yyerror("Generate for loop inline variable declaration is only supported in SystemVerilog mode!");
+		AstNode *node = new AstNode(AST_GENVAR);
+		node->is_reg = true;
+		node->is_signed = true;
+		node->range_left = 31;
+		node->range_right = 0;
+		node->str = $2->str;
+		node->children.push_back(checkRange(node, nullptr));
+		ast_stack.back()->children.push_back(node);
+		SET_AST_NODE_LOC(node, @1, @4);
+		node = new AstNode(AST_ASSIGN_EQ, $2, $4);
+		ast_stack.back()->children.push_back(node);
+		SET_AST_NODE_LOC(node, @1, @4);
+	} |
+	genvar_identifier '=' expr {
+		AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $3);
+		ast_stack.back()->children.push_back(node);
+		SET_AST_NODE_LOC(node, @1, @3);
+	};
+
 // this production creates the obligatory if-else shift/reduce conflict
 gen_stmt:
 	TOK_FOR '(' {
 		AstNode *node = new AstNode(AST_GENFOR);
 		ast_stack.back()->children.push_back(node);
 		ast_stack.push_back(node);
-	} simple_behavioral_stmt ';' expr {
+	} genvar_initialization ';' expr {
 		ast_stack.back()->children.push_back($6);
 	} ';' simple_behavioral_stmt ')' gen_stmt_block {
 		SET_AST_NODE_LOC(ast_stack.back(), @1, @11);
+		rewriteGenForDeclInit(ast_stack.back());
 		ast_stack.pop_back();
 	} |
 	TOK_IF '(' expr ')' {
diff --git a/tests/verilog/genfor_decl_no_init.ys b/tests/verilog/genfor_decl_no_init.ys
new file mode 100644
index 000000000..348899195
--- /dev/null
+++ b/tests/verilog/genfor_decl_no_init.ys
@@ -0,0 +1,7 @@
+logger -expect error "Generate for loop variable declaration is missing initialization!" 1
+read_verilog -sv <<EOT
+module top;
+    for (genvar i; i < 10; i = i + 1)
+        wire x;
+endmodule
+EOT
diff --git a/tests/verilog/genfor_decl_no_sv.ys b/tests/verilog/genfor_decl_no_sv.ys
new file mode 100644
index 000000000..124a27c28
--- /dev/null
+++ b/tests/verilog/genfor_decl_no_sv.ys
@@ -0,0 +1,7 @@
+logger -expect error "Generate for loop inline variable declaration is only supported in SystemVerilog mode!" 1
+read_verilog <<EOT
+module top;
+    for (genvar i = 1; i < 10; i = i + 1)
+        wire x;
+endmodule
+EOT
diff --git a/tests/verilog/genvar_loop_decl_1.sv b/tests/verilog/genvar_loop_decl_1.sv
new file mode 100644
index 000000000..b503f75da
--- /dev/null
+++ b/tests/verilog/genvar_loop_decl_1.sv
@@ -0,0 +1,18 @@
+`default_nettype none
+
+module gate(a);
+	for (genvar i = 0; i < 2; i++)
+		wire [i:0] x = '1;
+
+	output wire [32:0] a;
+	assign a = {1'b0, genblk1[0].x, 1'b0, genblk1[1].x, 1'b0};
+endmodule
+
+module gold(a);
+	genvar i;
+	for (i = 0; i < 2; i++)
+		wire [i:0] x = '1;
+
+	output wire [32:0] a;
+	assign a = {1'b0, genblk1[0].x, 1'b0, genblk1[1].x, 1'b0};
+endmodule
diff --git a/tests/verilog/genvar_loop_decl_1.ys b/tests/verilog/genvar_loop_decl_1.ys
new file mode 100644
index 000000000..ded486248
--- /dev/null
+++ b/tests/verilog/genvar_loop_decl_1.ys
@@ -0,0 +1,14 @@
+read_verilog -sv genvar_loop_decl_1.sv
+
+select -assert-count 1 gate/genblk1[0].x
+select -assert-count 1 gate/genblk1[1].x
+select -assert-count 0 gate/genblk1[2].x
+
+select -assert-count 1 gold/genblk1[0].x
+select -assert-count 1 gold/genblk1[1].x
+select -assert-count 0 gold/genblk1[2].x
+
+proc
+equiv_make gold gate equiv
+equiv_simple
+equiv_status -assert
diff --git a/tests/verilog/genvar_loop_decl_2.sv b/tests/verilog/genvar_loop_decl_2.sv
new file mode 100644
index 000000000..c5a85ef11
--- /dev/null
+++ b/tests/verilog/genvar_loop_decl_2.sv
@@ -0,0 +1,30 @@
+`default_nettype none
+
+module gate(out);
+    wire [3:0] x;
+    for (genvar x = 0; x < 2; x++) begin : blk
+        localparam w = x;
+        if (x == 0) begin : sub
+            wire [w:0] x;
+        end
+    end
+    assign x = 2;
+    assign blk[0].sub.x = '1;
+    output wire [9:0] out;
+    assign out = {1'bx, x, blk[0].sub.x};
+endmodule
+
+module gold(out);
+    wire [3:0] x;
+    genvar z;
+    for (z = 0; z < 2; z++) begin : blk
+        localparam w = z;
+        if (z == 0) begin : sub
+            wire [w:0] x;
+        end
+    end
+    assign x = 2;
+    assign blk[0].sub.x = '1;
+    output wire [9:0] out;
+    assign out = {1'bx, x, blk[0].sub.x};
+endmodule
diff --git a/tests/verilog/genvar_loop_decl_2.ys b/tests/verilog/genvar_loop_decl_2.ys
new file mode 100644
index 000000000..52fdeb49c
--- /dev/null
+++ b/tests/verilog/genvar_loop_decl_2.ys
@@ -0,0 +1,5 @@
+read_verilog -sv genvar_loop_decl_2.sv
+proc
+equiv_make gold gate equiv
+equiv_simple
+equiv_status -assert
diff --git a/tests/verilog/genvar_loop_decl_3.sv b/tests/verilog/genvar_loop_decl_3.sv
new file mode 100644
index 000000000..4d6d2366d
--- /dev/null
+++ b/tests/verilog/genvar_loop_decl_3.sv
@@ -0,0 +1,28 @@
+`default_nettype none
+
+module gate(x, y);
+    output reg [15:0] x, y;
+    if (1) begin : gen
+        integer x, y;
+        for (genvar x = 0; x < 2; x++)
+            if (x == 0)
+                initial gen.x = 10;
+        assign y = x + 1;
+    end
+    initial x = gen.x;
+    assign y = gen.y;
+endmodule
+
+module gold(x, y);
+    output reg [15:0] x, y;
+    if (1) begin : gen
+        integer x, y;
+        genvar z;
+        for (z = 0; z < 2; z++)
+            if (z == 0)
+                initial x = 10;
+        assign y = x + 1;
+    end
+    initial x = gen.x;
+    assign y = gen.y;
+endmodule
diff --git a/tests/verilog/genvar_loop_decl_3.ys b/tests/verilog/genvar_loop_decl_3.ys
new file mode 100644
index 000000000..19f754124
--- /dev/null
+++ b/tests/verilog/genvar_loop_decl_3.ys
@@ -0,0 +1,5 @@
+read_verilog -sv genvar_loop_decl_3.sv
+proc
+equiv_make gold gate equiv
+equiv_simple
+equiv_status -assert