Skip to content

Commit dce5b08

Browse files
arnavm30matth2k
andauthored
Support Verilog instances with constant inputs (#103)
Co-authored-by: matth2k <mrh259@cornell.edu>
1 parent 7659ddf commit dce5b08

File tree

2 files changed

+133
-49
lines changed

2 files changed

+133
-49
lines changed

src/lib.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,46 @@ endmodule"
423423
);
424424
}
425425

426+
#[test]
427+
fn test_constant_parse() {
428+
let module = "module my_gates (
429+
y
430+
);
431+
output y;
432+
wire y;
433+
wire tmp1;
434+
wire tmp2;
435+
436+
AND2 _0_ (
437+
.A(1'd1),
438+
.B(1'h01),
439+
.Y(tmp1)
440+
);
441+
442+
AND2 _1_ (
443+
.A(1'b00),
444+
.B(1'd0),
445+
.Y(tmp2)
446+
);
447+
448+
AND2 _2_ (
449+
.A(tmp1),
450+
.B(tmp2),
451+
.Y(y)
452+
);
453+
454+
endmodule"
455+
.to_string();
456+
let ast = sv_parse_wrapper(&module, None).unwrap();
457+
let module = SVModule::from_ast(&ast);
458+
assert!(module.is_ok());
459+
let module = module.unwrap();
460+
assert_eq!(
461+
module.to_single_expr().unwrap().to_string(),
462+
"(AND (AND true true) (AND false false))".to_string()
463+
);
464+
}
465+
426466
#[test]
427467
fn test_verilog_emitter() {
428468
let mux: RecExpr<LutLang> = "(LUT 202 s1 (LUT 202 s0 a b) (LUT 202 s0 c d))"

src/verilog.rs

Lines changed: 93 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,52 @@ pub fn get_identifier(node: RefNode, ast: &sv_parser::SyntaxTree) -> Result<Stri
6565
}
6666
}
6767

68+
/// Parse a literal `node` in the `ast` into a boolean value
69+
fn parse_literal_as_bool(node: RefNode, ast: &sv_parser::SyntaxTree) -> Result<bool, String> {
70+
let value = unwrap_node!(node, BinaryValue, HexValue, UnsignedNumber);
71+
72+
if value.is_none() {
73+
return Err(
74+
"Expected a BinaryValue, HexValue, or UnsignedNumber Node under the Literal"
75+
.to_string(),
76+
);
77+
}
78+
79+
match value.unwrap() {
80+
RefNode::BinaryValue(b) => {
81+
let loc = b.nodes.0;
82+
let val = ast.get_str(&loc).unwrap();
83+
let num = u64::from_str_radix(val, 2).unwrap();
84+
match num {
85+
1 => Ok(true),
86+
0 => Ok(false),
87+
_ => Err(format!("Expected a 1 bit constant. Found {}", num)),
88+
}
89+
}
90+
RefNode::HexValue(b) => {
91+
let loc = b.nodes.0;
92+
let val = ast.get_str(&loc).unwrap();
93+
let num = u64::from_str_radix(val, 16).unwrap();
94+
match num {
95+
1 => Ok(true),
96+
0 => Ok(false),
97+
_ => Err(format!("Expected a 1 bit constant. Found {}", num)),
98+
}
99+
}
100+
RefNode::UnsignedNumber(b) => {
101+
let loc = b.nodes.0;
102+
let val = ast.get_str(&loc).unwrap();
103+
let num = val.parse::<u64>().unwrap();
104+
match num {
105+
1 => Ok(true),
106+
0 => Ok(false),
107+
_ => Err(format!("Expected a 1 bit constant. Found {}", num)),
108+
}
109+
}
110+
_ => unreachable!(),
111+
}
112+
}
113+
68114
fn init_format(program: u64, k: usize) -> Result<String, ()> {
69115
let w = 1 << k;
70116
match k {
@@ -633,20 +679,45 @@ impl SVModule {
633679
.add_signal(port_name, arg_name.unwrap())?;
634680
}
635681
None => {
636-
// Ignore clock enable and resets
682+
// Ignore clock enable and reset signals,
683+
// because they are not along the data path
684+
// The verilog emitter just re-inserts them at the end
685+
// This means we can only use D Flip-flops that are constantly *ON*.
637686
if port_name == "CE" || port_name == "R" {
638687
if unwrap_node!(arg, PrimaryLiteral).is_none() {
639688
return Err(format!(
640-
"Port {} should be driven constant",
689+
"Non-data port {} should be driven constant",
641690
port_name
642691
));
643692
}
644-
continue;
645693
} else {
646-
return Err(format!(
647-
"Expected a HierarchicalIdentifier for port {}",
648-
port_name
649-
));
694+
// If we don't have a identifier, it must be a constant connection
695+
let arg_name = cur_insts.last().unwrap().name.clone()
696+
+ port_name.as_str()
697+
+ "_const";
698+
cur_signals.push(SVSignal::new(1, arg_name.clone()));
699+
cur_insts
700+
.last_mut()
701+
.unwrap()
702+
.add_signal(port_name.clone(), arg_name.clone())?;
703+
704+
// Create the constant
705+
let literal = unwrap_node!(arg, PrimaryLiteral);
706+
if literal.is_none() {
707+
return Err(format!(
708+
"Expected a literal for connection on port {}",
709+
port_name
710+
));
711+
}
712+
let value = parse_literal_as_bool(literal.unwrap(), ast)?;
713+
let const_inst = SVPrimitive::new_const(
714+
value,
715+
arg_name.clone(),
716+
arg_name.clone() + "_inst",
717+
);
718+
719+
// Insert the constant before the current instance
720+
cur_insts.insert(cur_insts.len() - 1, const_inst);
650721
}
651722
}
652723
}
@@ -671,7 +742,7 @@ impl SVModule {
671742
let lhs_id = unwrap_node!(lhs, Identifier).unwrap();
672743
let lhs_name = get_identifier(lhs_id, ast).unwrap();
673744
let rhs = unwrap_node!(net_assign, Expression).unwrap();
674-
let rhs_id = unwrap_node!(rhs, Identifier, BinaryNumber, HexNumber).unwrap();
745+
let rhs_id = unwrap_node!(rhs, Identifier, PrimaryLiteral).unwrap();
675746
let assignment = unwrap_node!(net_assign, Symbol).unwrap();
676747
match assignment {
677748
RefNode::Symbol(sym) => {
@@ -685,47 +756,20 @@ impl SVModule {
685756
return Err("Expected an assignment operator".to_string());
686757
}
687758
}
688-
match rhs_id {
689-
RefNode::Identifier(_) => {
690-
let rhs_name = get_identifier(rhs_id, ast).unwrap();
691-
cur_insts.push(SVPrimitive::new_wire(
692-
rhs_name.clone(),
693-
lhs_name.clone(),
694-
lhs_name + "_wire_" + &rhs_name,
695-
));
696-
}
697-
RefNode::BinaryNumber(b) => {
698-
let loc = b.nodes.2.nodes.0;
699-
let val = ast.get_str(&loc).unwrap();
700-
let val = match val {
701-
"0" => false,
702-
"1" => true,
703-
_ => {
704-
return Err(format!(
705-
"Expected a 1 bit constant. Found {}",
706-
val
707-
));
708-
}
709-
};
710-
cur_insts.push(SVPrimitive::new_const(
711-
val,
712-
lhs_name.clone(),
713-
lhs_name + "_const_binary",
714-
));
715-
}
716-
RefNode::HexNumber(b) => {
717-
let loc = b.nodes.2.nodes.0;
718-
let val = ast.get_str(&loc).unwrap();
719-
let val = !matches!(val, "0");
720-
cur_insts.push(SVPrimitive::new_const(
721-
val,
722-
lhs_name.clone(),
723-
lhs_name + "_const_hex",
724-
));
725-
}
726-
_ => {
727-
return Err("Expected a Identifier or PrimaryLiteral".to_string());
728-
}
759+
if matches!(rhs_id, RefNode::Identifier(_)) {
760+
let rhs_name = get_identifier(rhs_id, ast).unwrap();
761+
cur_insts.push(SVPrimitive::new_wire(
762+
rhs_name.clone(),
763+
lhs_name.clone(),
764+
lhs_name + "_wire_" + &rhs_name,
765+
));
766+
} else {
767+
let val = parse_literal_as_bool(rhs_id, ast)?;
768+
cur_insts.push(SVPrimitive::new_const(
769+
val,
770+
lhs_name.clone(),
771+
lhs_name + "_const_binary",
772+
));
729773
}
730774
}
731775
NodeEvent::Leave(RefNode::NetAssignment(_net_assign)) => (),

0 commit comments

Comments
 (0)