Skip to content

Commit b248a11

Browse files
committed
test(analyzer): cover procedural and partial modport connects
1 parent a40d2ac commit b248a11

1 file changed

Lines changed: 157 additions & 0 deletions

File tree

crates/analyzer/src/tests/comb_loop_interface_tests.rs

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,3 +469,160 @@ fn comb_loop_generic_interface_enabled_specialization_retains_feedthrough() {
469469
fn comb_loop_generic_interface_disabled_specialization_has_no_feedthrough() {
470470
assert_interface_comb_loop(&specialized_interface_code(2), false);
471471
}
472+
473+
fn formal_modport_connect_code(source_assignments: &str) -> String {
474+
format!(
475+
r#"
476+
interface Bus {{
477+
var request : logic;
478+
var response: logic;
479+
modport initiator {{
480+
request : output,
481+
response: input,
482+
}}
483+
modport target {{
484+
..converse(initiator)
485+
}}
486+
}}
487+
module Bridge (
488+
producer: modport Bus::initiator,
489+
consumer: modport Bus::target,
490+
) {{
491+
connect producer <> consumer;
492+
}}
493+
module Top {{
494+
inst producer: Bus;
495+
inst consumer: Bus;
496+
inst bridge: Bridge (
497+
producer: producer,
498+
consumer: consumer,
499+
);
500+
{source_assignments}
501+
}}
502+
"#
503+
)
504+
}
505+
506+
#[test]
507+
fn comb_loop_formal_modport_connect_detects_feedback() {
508+
assert_interface_comb_loop(
509+
&formal_modport_connect_code(
510+
r#"assign consumer.request = consumer.response;
511+
assign producer.response = producer.request;"#,
512+
),
513+
true,
514+
);
515+
}
516+
517+
#[test]
518+
fn comb_loop_formal_modport_connect_with_constant_sources_has_no_feedback() {
519+
assert_interface_comb_loop(
520+
&formal_modport_connect_code(
521+
r#"assign consumer.request = 0;
522+
assign producer.response = 0;"#,
523+
),
524+
false,
525+
);
526+
}
527+
528+
fn procedural_modport_connect_code(overrides: &str) -> String {
529+
format!(
530+
r#"
531+
interface Bus {{
532+
var request : logic;
533+
var response: logic;
534+
modport initiator {{
535+
request : output,
536+
response: input,
537+
}}
538+
modport target {{
539+
..converse(initiator)
540+
}}
541+
}}
542+
module Top {{
543+
inst producer: Bus;
544+
inst consumer: Bus;
545+
always_comb {{
546+
producer.initiator <> consumer.target;
547+
{overrides}
548+
}}
549+
assign consumer.request = consumer.response;
550+
assign producer.response = producer.request;
551+
}}
552+
"#
553+
)
554+
}
555+
556+
#[test]
557+
fn comb_loop_procedural_modport_connect_detects_feedback() {
558+
assert_interface_comb_loop(&procedural_modport_connect_code(""), true);
559+
}
560+
561+
#[test]
562+
#[ignore = "comb-loop migration: false positive; procedural modport connect killed by later overrides"]
563+
fn comb_loop_procedural_modport_connect_overrides_kill_feedback() {
564+
assert_interface_comb_loop(
565+
&procedural_modport_connect_code(
566+
r#"producer.request = 0;
567+
consumer.response = 0;"#,
568+
),
569+
false,
570+
);
571+
}
572+
573+
fn partial_modport_connect_code(source_assignments: &str) -> String {
574+
format!(
575+
r#"
576+
interface Bus {{
577+
var request : logic;
578+
var response: logic;
579+
modport initiator {{
580+
request : output,
581+
response: input,
582+
}}
583+
modport target_request {{
584+
request: input,
585+
}}
586+
}}
587+
module RequestBridge (
588+
producer: modport Bus::initiator,
589+
consumer: modport Bus::target_request,
590+
) {{
591+
connect producer <> consumer;
592+
}}
593+
module Top {{
594+
inst producer: Bus;
595+
inst consumer: Bus;
596+
inst bridge: RequestBridge (
597+
producer: producer,
598+
consumer: consumer,
599+
);
600+
{source_assignments}
601+
}}
602+
"#
603+
)
604+
}
605+
606+
#[test]
607+
fn comb_loop_partial_modport_connect_detects_shared_member_feedback() {
608+
assert_interface_comb_loop(
609+
&partial_modport_connect_code(
610+
r#"assign consumer.request = producer.response;
611+
assign producer.response = producer.request;
612+
assign consumer.response = 0;"#,
613+
),
614+
true,
615+
);
616+
}
617+
618+
#[test]
619+
fn comb_loop_partial_modport_connect_does_not_connect_absent_member() {
620+
assert_interface_comb_loop(
621+
&partial_modport_connect_code(
622+
r#"assign consumer.request = 0;
623+
assign consumer.response = producer.request;
624+
assign producer.response = consumer.response;"#,
625+
),
626+
false,
627+
);
628+
}

0 commit comments

Comments
 (0)