Repository: veryl-lang/veryl (Rust)

Issue:
`reset_low_suffix` does not affect inst port list
The `reset_low_suffix` does not affect inst port lists if a module has a reset port with `reset_async_low` type.

Example

Veryl
```systemverilog
module sub (
    i_clk: input clock,
    i_rst: input reset,
) {}

module top (
    i_clk  : input clock          ,
    i_rst_n: input reset_async_low,
) {
    let rst: reset = i_rst_n as reset;

    inst u_sub: sub (
        i_clk: i_clk,
        i_rst: rst  ,
    );
}
```

Generated SV
```systemverilog
module veryl_testcase_sub (
    input var logic i_clk  ,
    input var logic i_rst_n
);
endmodule

module veryl_testcase_top (
    input var logic i_clk  ,
    input var logic i_rst_n
);
    logic rst_n; always_comb rst_n = i_rst_n;

    veryl_testcase_sub u_sub (
        .i_clk (i_clk),
        .i_rst (rst_n)
    );
endmodule
//# sourceMappingURL=a.sv.map
```

`i_rst` of inst `u_sub` should be emitted to `i_rst_n` because the `reset_low_suffix` is set to "_n" but the actual result is `i_rst`.


Discussion:

Patch:
diff --git a/crates/emitter/src/emitter.rs b/crates/emitter/src/emitter.rs
index 712ae29b8..4b6a35c2b 100644
--- a/crates/emitter/src/emitter.rs
+++ b/crates/emitter/src/emitter.rs
@@ -13,7 +13,7 @@ use veryl_analyzer::symbol::TypeModifierKind as SymTypeModifierKind;
 use veryl_analyzer::symbol::{
     GenericMap, GenericTables, Port, Symbol, SymbolId, SymbolKind, TypeKind, VariableAffiliation,
 };
-use veryl_analyzer::symbol_path::{GenericSymbolPath, SymbolPath};
+use veryl_analyzer::symbol_path::{GenericSymbolPath, SymbolPath, SymbolPathNamespace};
 use veryl_analyzer::symbol_table::{self, ResolveError, ResolveResult};
 use veryl_analyzer::{msb_table, namespace_table};
 use veryl_metadata::{Build, BuiltinType, ClockType, Format, Metadata, ResetType, SourceMapTarget};
@@ -86,6 +86,7 @@ pub struct Emitter {
     duplicated_index: usize,
     modport_connections_tables: Vec<ExpandModportConnectionsTable>,
     modport_ports_table: Option<ExpandedModportPortTable>,
+    inst_module_namespace: Option<Namespace>,
 }
 
 impl Default for Emitter {
@@ -134,6 +135,7 @@ impl Default for Emitter {
             duplicated_index: 0,
             modport_connections_tables: Vec::new(),
             modport_ports_table: None,
+            inst_module_namespace: None,
         }
     }
 }
@@ -541,6 +543,23 @@ impl Emitter {
         self.align_finish(align_kind::WIDTH);
     }
 
+    fn emit_identifier(&mut self, arg: &Identifier, namespace: Option<Namespace>) {
+        let align = !self.align_any()
+            && !self.in_attribute
+            && attribute_table::is_align(&arg.first(), AlignItem::Identifier);
+        if align {
+            self.align_start(align_kind::IDENTIFIER);
+        }
+
+        let text = emitting_identifier(arg, namespace).identifier_token;
+        self.veryl_token(&text);
+        self.push_resolved_identifier(&text.to_string());
+
+        if align {
+            self.align_finish(align_kind::IDENTIFIER);
+        }
+    }
+
     fn case_inside_statement(&mut self, arg: &CaseStatement) {
         let (prefix, force_last_item_default) = self.cond_type_prefix(&arg.case.case_token.token);
         self.token(&arg.case.case_token.append(&prefix, &None));
@@ -930,7 +949,7 @@ impl Emitter {
     }
 
     fn emit_generate_named_block(&mut self, arg: &GenerateNamedBlock, prefix: &str) {
-        self.default_block = Some(emitting_identifier(arg.identifier.as_ref()));
+        self.default_block = Some(emitting_identifier(arg.identifier.as_ref(), None));
         self.token_will_push(&arg.l_brace.l_brace_token.replace(&format!("{prefix}begin")));
         self.space(1);
         self.colon(&arg.colon);
@@ -1291,6 +1310,11 @@ impl Emitter {
         self.align_finish(align_kind::EXPRESSION);
     }
 
+    fn emit_port_identifier(&mut self, identifier: &Identifier) {
+        let namespace = self.inst_module_namespace.clone();
+        self.emit_identifier(identifier, namespace);
+    }
+
     fn emit_inst_unconnected_port(
         &mut self,
         defined_ports: &[Port],
@@ -2147,20 +2171,7 @@ impl VerylWalker for Emitter {
 
     /// Semantic action for non-terminal 'Identifier'
     fn identifier(&mut self, arg: &Identifier) {
-        let align = !self.align_any()
-            && !self.in_attribute
-            && attribute_table::is_align(&arg.first(), AlignItem::Identifier);
-        if align {
-            self.align_start(align_kind::IDENTIFIER);
-        }
-
-        let text = emitting_identifier(arg).identifier_token;
-        self.veryl_token(&text);
-        self.push_resolved_identifier(&text.to_string());
-
-        if align {
-            self.align_finish(align_kind::IDENTIFIER);
-        }
+        self.emit_identifier(arg, None);
     }
 
     /// Semantic action for non-terminal 'Number'
@@ -3148,7 +3159,7 @@ impl VerylWalker for Emitter {
         //self.str(";");
         //self.newline();
         self.align_start(align_kind::IDENTIFIER);
-        self.identifier(&emitting_identifier(arg.identifier.as_ref()));
+        self.identifier(&emitting_identifier(arg.identifier.as_ref(), None));
         self.align_finish(align_kind::IDENTIFIER);
         self.space(1);
         self.equ(&arg.equ);
@@ -3558,7 +3569,7 @@ impl VerylWalker for Emitter {
             self.str("always_comb");
         }
         self.space(1);
-        self.identifier(&emitting_identifier(arg.identifier.as_ref()));
+        self.identifier(&emitting_identifier(arg.identifier.as_ref(), None));
         self.space(1);
         self.equ(&arg.equ);
         self.space(1);
@@ -4281,22 +4292,22 @@ impl VerylWalker for Emitter {
             &arg.inst.inst_token.token,
             Attr::Allow(AllowItem::MissingPort),
         );
-        let (defined_ports, generic_map, namespace) =
+        let (defined_ports, generic_map, symbol) =
             if let (Ok(symbol), _) = self.resolve_scoped_idnetifier(&arg.scoped_identifier) {
                 match symbol.found.kind {
                     SymbolKind::Module(ref x) if !allow_missing_port => {
-                        (x.ports.clone(), vec![], symbol.found.namespace)
+                        (x.ports.clone(), vec![], symbol.found)
                     }
                     SymbolKind::GenericInstance(ref x) => {
                         let base = symbol_table::get(x.base).unwrap();
                         match base.kind {
                             SymbolKind::Module(ref x) if !allow_missing_port => {
-                                (x.ports.clone(), symbol.found.generic_maps(), base.namespace)
+                                (x.ports.clone(), symbol.found.generic_maps(), base)
                             }
-                            _ => (vec![], vec![], base.namespace),
+                            _ => (vec![], vec![], base),
                         }
                     }
-                    _ => (vec![], vec![], symbol.found.namespace),
+                    _ => (vec![], vec![], symbol.found),
                 }
             } else {
                 unreachable!()
@@ -4315,10 +4326,11 @@ impl VerylWalker for Emitter {
             &defined_ports,
             &connected_ports,
             &generic_map,
-            &namespace,
+            &symbol.namespace,
         );
         self.modport_connections_tables
             .push(modport_connections_table);
+        self.inst_module_namespace = Some(symbol.inner_namespace());
 
         let compact = attribute_table::is_format(&arg.identifier.first(), FormatItem::Compact);
         let single_line =
@@ -4373,6 +4385,7 @@ impl VerylWalker for Emitter {
         }
 
         self.modport_connections_tables.pop();
+        self.inst_module_namespace = None;
     }
 
     /// Semantic action for non-terminal 'InstParameter'
@@ -4510,7 +4523,7 @@ impl VerylWalker for Emitter {
         } else {
             self.str(".");
             self.align_start(align_kind::IDENTIFIER);
-            self.identifier(&arg.identifier);
+            self.emit_port_identifier(&arg.identifier);
             self.align_finish(align_kind::IDENTIFIER);
             self.space(1);
             self.str("(");
@@ -5733,8 +5746,14 @@ pub fn identifier_with_prefix_suffix(
     }
 }
 
-pub fn emitting_identifier(arg: &Identifier) -> Identifier {
-    let (prefix, suffix) = if let Ok(found) = symbol_table::resolve(arg) {
+pub fn emitting_identifier(arg: &Identifier, namespace: Option<Namespace>) -> Identifier {
+    let path_namespace = if let Some(x) = namespace {
+        SymbolPathNamespace(arg.into(), x)
+    } else {
+        arg.into()
+    };
+
+    let (prefix, suffix) = if let Ok(found) = symbol_table::resolve(path_namespace) {
         match &found.found.kind {
             SymbolKind::Port(x) => (x.prefix.clone(), x.suffix.clone()),
             SymbolKind::Variable(x) => (x.prefix.clone(), x.suffix.clone()),


Test patch:
diff --git a/crates/emitter/src/tests.rs b/crates/emitter/src/tests.rs
index 76a952078..225950279 100644
--- a/crates/emitter/src/tests.rs
+++ b/crates/emitter/src/tests.rs
@@ -184,6 +184,55 @@ endmodule
     assert_eq!(ret, expect);
 }
 
+#[test]
+fn clock_reset_port_name() {
+    let code = r#"module ModuleA (
+    i_clk: input clock,
+    i_rst: input reset,
+) {}
+module ModuleB (
+    i_clock: input clock,
+    i_reset: input reset,
+) {
+    inst u: ModuleA (
+        i_clk: i_clock,
+        i_rst: i_reset,
+    );
+}
+"#;
+
+    let expect = r#"module prj_ModuleA (
+    input var logic i_clk_p,
+    input var logic i_rst_x
+);
+endmodule
+module prj_ModuleB (
+    input var logic i_clock_p,
+    input var logic i_reset_x
+);
+    prj_ModuleA u (
+        .i_clk_p (i_clock_p),
+        .i_rst_x (i_reset_x)
+    );
+endmodule
+//# sourceMappingURL=test.sv.map
+"#;
+
+    let mut metadata: Metadata =
+        toml::from_str(&Metadata::create_default_toml("prj").unwrap()).unwrap();
+    metadata.build.clock_posedge_suffix = Some("_p".to_string());
+    metadata.build.reset_low_suffix = Some("_x".to_string());
+
+    let ret = if cfg!(windows) {
+        emit(&metadata, code).replace("\r\n", "\n")
+    } else {
+        emit(&metadata, code)
+    };
+
+    println!("ret\n{}exp\n{}", ret, expect);
+    assert_eq!(ret, expect);
+}
+
 #[test]
 fn omit_project_prefix() {
     let code = r#"module ModuleA {
diff --git a/testcases/map/25_dependency.sv.map b/testcases/map/25_dependency.sv.map
index 9526d5c8c..1c62b8550 100644
--- a/testcases/map/25_dependency.sv.map
+++ b/testcases/map/25_dependency.sv.map
@@ -1,1 +1,1 @@
-{"version":3,"file":"25_dependency.sv.map","sources":["../veryl/25_dependency.veryl"],"names":["","module","veryl_testcase_Module25","(","input","logic","i_clk",",","i_rst_n","veryl_sample3_data_if.mp_in","in_if","veryl_sample3_data_if.mp_out","out_if",")",";","veryl_sample3_data_if","data_if","veryl_sample_delay","u0","i_d",".","data","o_d","veryl_sample2_delay","u1","endmodule"],"mappings":"AAAAA,AAAAC,OAAOC,wBAASC;IACJC,UAAQC,yBAAhBC,OAA8CC;IACtCH,UAAQC,yBAAhBG,OAA8CD;IAC9BE,6BAAhBC,OAA8CH;IAC9BI,6BAAhBC,OAA8CZ;AAClDa,CAAEC;IACEd,AAAce,sBAATC,UAA+BF;;IAEpCd,AAASiB,mBAAJC,GAAwBf;SACzBG,SAAAA,aAAqBC;SACrBC,SAAOR,AAAEQ,aAAYD;SACrBY,SAAOnB,AAAEU,KAAKU,CAACC,OAAMd;SACrBe,SAAOtB,AAAEgB,OAAOI,CAACC,KAAIrB;IACzBa,CAACC;;IAEDd,AAASuB,oBAAJC,GAAyBrB;SAC1BG,SAAAA,aAAqBC;SACrBC,SAAOR,AAAEQ,aAAYD;SACrBY,SAAOnB,AAAEgB,OAAOI,CAACC,KAAId;SACrBe,SAAOtB,AAAEY,MAAMQ,CAACC,MAAKrB;IACzBa,CAACC;AACLW"}
\ No newline at end of file
+{"version":3,"file":"25_dependency.sv.map","sources":["../veryl/25_dependency.veryl"],"names":["","module","veryl_testcase_Module25","(","input","logic","i_clk",",","i_rst_n","veryl_sample3_data_if.mp_in","in_if","veryl_sample3_data_if.mp_out","out_if",")",";","veryl_sample3_data_if","data_if","veryl_sample_delay","u0","i_rst_n_n","i_d",".","data","o_d","veryl_sample2_delay","u1","endmodule"],"mappings":"AAAAA,AAAAC,OAAOC,wBAASC;IACJC,UAAQC,yBAAhBC,OAA8CC;IACtCH,UAAQC,yBAAhBG,OAA8CD;IAC9BE,6BAAhBC,OAA8CH;IAC9BI,6BAAhBC,OAA8CZ;AAClDa,CAAEC;IACEd,AAAce,sBAATC,UAA+BF;;IAEpCd,AAASiB,mBAAJC,GAAwBf;SACzBG,WAAAA,aAAqBC;SACrBY,WAAOnB,AAAEQ,aAAYD;SACrBa,WAAOpB,AAAEU,KAAKW,CAACC,OAAMf;SACrBgB,WAAOvB,AAAEgB,OAAOK,CAACC,KAAItB;IACzBa,CAACC;;IAEDd,AAASwB,oBAAJC,GAAyBtB;SAC1BG,WAAAA,aAAqBC;SACrBY,WAAOnB,AAAEQ,aAAYD;SACrBa,WAAOpB,AAAEgB,OAAOK,CAACC,KAAIf;SACrBgB,WAAOvB,AAAEY,MAAMS,CAACC,MAAKtB;IACzBa,CAACC;AACLY"}
\ No newline at end of file
diff --git a/testcases/sv/25_dependency.sv b/testcases/sv/25_dependency.sv
index b9bd4fc8b..4214a1526 100644
--- a/testcases/sv/25_dependency.sv
+++ b/testcases/sv/25_dependency.sv
@@ -7,17 +7,17 @@ module veryl_testcase_Module25 (
     veryl_sample3_data_if data_if ();
 
     veryl_sample_delay u0 (
-        .i_clk   (i_clk       ),
-        .i_rst_n (i_rst_n     ),
-        .i_d     (in_if.data  ),
-        .o_d     (data_if.data)
+        .i_clk     (i_clk       ),
+        .i_rst_n_n (i_rst_n     ),
+        .i_d       (in_if.data  ),
+        .o_d       (data_if.data)
     );
 
     veryl_sample2_delay u1 (
-        .i_clk   (i_clk       ),
-        .i_rst_n (i_rst_n     ),
-        .i_d     (data_if.data),
-        .o_d     (out_if.data )
+        .i_clk     (i_clk       ),
+        .i_rst_n_n (i_rst_n     ),
+        .i_d       (data_if.data),
+        .o_d       (out_if.data )
     );
 endmodule
 //# sourceMappingURL=../map/25_dependency.sv.map