use indexmap::IndexMap;
use topstitch::*;
#[test]
fn test_interfaces() {
let module_a_verilog = "
module ModuleA (
output [31:0] a_data,
output a_valid,
input a_ready
);
endmodule
";
let module_b_verilog = "
module ModuleB (
input [31:0] b_data,
input b_valid,
output b_ready
);
endmodule
";
let module_a = ModDef::from_verilog("ModuleA", module_a_verilog, true, false);
module_a.def_intf_from_prefix("a_intf", "a_");
let module_b = ModDef::from_verilog("ModuleB", module_b_verilog, true, false);
module_b.def_intf_from_prefix("b_intf", "b_");
let top_module = ModDef::new("TopModule");
let a_inst = top_module.instantiate(&module_a, Some("inst_a"), None);
let b_inst = top_module.instantiate(&module_b, Some("inst_b"), None);
let a_intf = a_inst.get_intf("a_intf");
let b_intf = b_inst.get_intf("b_intf");
assert_eq!(a_intf.width(), 34);
assert_eq!(b_intf.width(), 34);
a_intf.connect(&b_intf, false);
assert_eq!(
top_module.emit(true),
"\
module TopModule;
wire [31:0] inst_a_a_data;
wire inst_a_a_valid;
wire inst_b_b_ready;
ModuleA inst_a (
.a_data(inst_a_a_data),
.a_valid(inst_a_a_valid),
.a_ready(inst_b_b_ready)
);
ModuleB inst_b (
.b_data(inst_a_a_data),
.b_valid(inst_a_a_valid),
.b_ready(inst_b_b_ready)
);
endmodule
"
);
}
#[test]
fn test_intf_iterators() {
let module = ModDef::new("ModuleA");
module.add_port("a_data", IO::Output(4));
module.add_port("a_valid", IO::Output(1));
module.add_port("a_ready", IO::Input(1));
let intf = module.def_intf_from_name_underscore("a");
let expected_iter_pairs = [
("data".to_string(), module.get_port("a_data").slice(3, 0)),
("valid".to_string(), module.get_port("a_valid").bit(0)),
("ready".to_string(), module.get_port("a_ready").bit(0)),
];
for (actual, expected) in intf.iter().zip(expected_iter_pairs) {
assert_eq!(actual, expected);
}
let expected_keys = ["data".to_string(), "valid".to_string(), "ready".to_string()];
for (actual, expected) in intf.keys().zip(expected_keys) {
assert_eq!(actual, expected);
}
let expected_values = [
module.get_port("a_data").slice(3, 0),
module.get_port("a_valid").bit(0),
module.get_port("a_ready").bit(0),
];
for (actual, expected) in intf.values().zip(expected_values) {
assert_eq!(actual, expected);
}
let top = ModDef::new("Top");
let inst = top.instantiate(&module, Some("u_a"), None);
let inst_intf = inst.get_intf("a");
let expected_inst_values = [
inst.get_port("a_data").slice(3, 0),
inst.get_port("a_valid").bit(0),
inst.get_port("a_ready").bit(0),
];
for (actual, expected) in inst_intf.values().zip(expected_inst_values) {
assert_eq!(actual, expected);
}
}
#[test]
fn test_intf_get_moddef_and_modinst() {
let module = ModDef::new("ModuleA");
module.add_port("a_data", IO::Output(4));
module.add_port("a_valid", IO::Output(1));
module.add_port("a_ready", IO::Input(1));
module.def_intf_from_name_underscore("a");
let intf = module.get_intf("a");
assert_eq!(
intf.get("data"),
Some(module.get_port("a_data").slice(3, 0))
);
assert_eq!(intf.get("missing"), None);
let top = ModDef::new("Top");
let inst = top.instantiate(&module, Some("u_a"), None);
let inst_intf = inst.get_intf("a");
assert_eq!(
inst_intf.get("data"),
Some(inst.get_port("a_data").slice(3, 0))
);
assert_eq!(inst_intf.get("missing"), None);
}
#[test]
fn test_intf_remove_moddef() {
let module = ModDef::new("ModuleA");
module.add_port("a_data", IO::Output(4));
module.add_port("a_valid", IO::Output(1));
module.add_port("a_ready", IO::Input(1));
module.def_intf_from_name_underscore("a");
let intf = module.get_intf("a");
assert_eq!(
intf.remove("data"),
Some(module.get_port("a_data").slice(3, 0))
);
assert_eq!(intf.get("data"), None);
assert_eq!(intf.remove("data"), None);
}
#[test]
fn test_intf_remove_modinst() {
let module = ModDef::new("ModuleA");
module.add_port("a_data", IO::Output(4));
module.add_port("a_valid", IO::Output(1));
module.add_port("a_ready", IO::Input(1));
module.def_intf_from_name_underscore("a");
let top = ModDef::new("Top");
let inst = top.instantiate(&module, Some("u_a"), None);
let inst_intf = inst.get_intf("a");
assert_eq!(
inst_intf.remove("data"),
Some(inst.get_port("a_data").slice(3, 0))
);
assert_eq!(inst_intf.get("data"), None);
assert_eq!(inst_intf.remove("data"), None);
}
#[test]
fn test_intf_iterators_modinst_hierarchy() {
let leaf = ModDef::new("Leaf");
leaf.add_port("bus_data", IO::Output(4)).tieoff(0);
leaf.add_port("bus_valid", IO::Output(1)).tieoff(0);
leaf.add_port("bus_ready", IO::Input(1)).unused();
leaf.def_intf_from_name_underscore("bus");
let mid = leaf.wrap(Some("Mid"), Some("leaf_inst"));
let top = ModDef::new("Top");
let mid_inst = top.instantiate(&mid, Some("mid_inst"), None);
let leaf_from_top = mid_inst.get_instance("leaf_inst");
let intf = leaf_from_top.get_intf("bus");
let expected_values = [
leaf_from_top.get_port("bus_data").slice(3, 0),
leaf_from_top.get_port("bus_valid").bit(0),
leaf_from_top.get_port("bus_ready").bit(0),
];
for (actual, expected) in intf.values().zip(expected_values) {
assert_eq!(actual, expected);
}
}
#[test]
fn test_modinst_get_intfs_preserves_hierarchy() {
let leaf = ModDef::new("Leaf");
leaf.add_port("bus_data", IO::Output(4)).tieoff(0);
leaf.add_port("bus_valid", IO::Output(1)).tieoff(0);
leaf.add_port("bus_ready", IO::Input(1)).unused();
leaf.add_port("ctrl_data", IO::Output(2)).tieoff(0);
leaf.add_port("ctrl_valid", IO::Output(1)).tieoff(0);
leaf.add_port("ctrl_ready", IO::Input(1)).unused();
leaf.def_intf_from_name_underscore("bus");
leaf.def_intf_from_name_underscore("ctrl");
let mid = leaf.wrap(Some("Mid"), Some("leaf_inst"));
let top = mid.wrap(Some("Top"), Some("mid_inst"));
let leaf_from_top = top.get_instance("mid_inst").get_instance("leaf_inst");
let intfs = leaf_from_top.get_intfs(Some("bus"));
assert_eq!(intfs.len(), 1);
let expected_values = [
leaf_from_top.get_port("bus_data").slice(3, 0),
leaf_from_top.get_port("bus_valid").bit(0),
leaf_from_top.get_port("bus_ready").bit(0),
];
for (actual, expected) in intfs[0].values().zip(expected_values) {
assert_eq!(actual, expected);
}
let all_intfs = leaf_from_top.get_intfs(None);
assert_eq!(all_intfs.len(), 2);
}
#[test]
fn test_intf_place_across_from() {
let module = ModDef::new("Top");
module.add_port("a_data", IO::Input(1));
module.add_port("b_data", IO::Input(1));
module.def_intf_from_name_underscore("a");
module.def_intf_from_name_underscore("b");
module.set_width_height(10, 10);
let pin_shape = Polygon::from_width_height(1, 1);
let mut tracks = TrackDefinitions::default();
tracks.add_track(TrackDefinition::new(
"M1",
0,
1,
TrackOrientation::Vertical,
Some(pin_shape.clone()),
None,
));
module.set_track_definitions(tracks);
let src_pin = PhysicalPin::from_translation("M1", pin_shape.clone(), Coordinate { x: 3, y: 0 });
module.place_pin("a_data", 0, src_pin);
let a_intf = module.get_intf("a");
let b_intf = module.get_intf("b");
b_intf.place_across_from(&a_intf, false);
let placed = module.get_port("b_data").bit(0).get_physical_pin();
assert_eq!(placed.translation(), Coordinate { x: 3, y: 10 });
}
#[test]
fn test_intf_place_crossover_from() {
let module = ModDef::new("Top");
module.add_port("a_data_tx", IO::Input(1));
module.add_port("a_data_rx", IO::Input(1));
module.add_port("b_data_tx", IO::Input(1));
module.add_port("b_data_rx", IO::Input(1));
module.def_intf_from_name_underscore("a");
module.def_intf_from_name_underscore("b");
module.set_width_height(10, 10);
let pin_shape = Polygon::from_width_height(1, 1);
let mut tracks = TrackDefinitions::default();
tracks.add_track(TrackDefinition::new(
"M1",
0,
1,
TrackOrientation::Vertical,
Some(pin_shape.clone()),
None,
));
module.set_track_definitions(tracks);
module.place_pin(
"a_data_tx",
0,
PhysicalPin::from_translation("M1", pin_shape.clone(), Coordinate { x: 3, y: 0 }),
);
module.place_pin(
"a_data_rx",
0,
PhysicalPin::from_translation("M1", pin_shape.clone(), Coordinate { x: 7, y: 0 }),
);
let a_intf = module.get_intf("a");
let b_intf = module.get_intf("b");
b_intf.place_crossover_from(&a_intf, "^(.*)_tx$", "^(.*)_rx$");
let b_tx_pin = module.get_port("b_data_tx").bit(0).get_physical_pin();
let b_rx_pin = module.get_port("b_data_rx").bit(0).get_physical_pin();
assert_eq!(b_tx_pin.translation(), Coordinate { x: 7, y: 10 });
assert_eq!(b_rx_pin.translation(), Coordinate { x: 3, y: 10 });
}
#[test]
fn test_interface_connection_moddef_to_modinst() {
let module_b_verilog = "
module ModuleB (
output [31:0] b_data,
output b_valid,
input b_ready
);
endmodule
";
let module_b = ModDef::from_verilog("ModuleB", module_b_verilog, true, false);
module_b.def_intf_from_prefix("b", "b_");
let module_a = ModDef::new("ModuleA");
module_a.add_port("a_data", IO::Output(32));
module_a.add_port("a_valid", IO::Output(1));
module_a.add_port("a_ready", IO::Input(1));
module_a.def_intf_from_prefix("a", "a_");
let b_inst = module_a.instantiate(&module_b, Some("inst_b"), None);
let mod_a_intf = module_a.get_intf("a");
let b_intf = b_inst.get_intf("b");
mod_a_intf.connect(&b_intf, false);
assert_eq!(
module_a.emit(true),
"\
module ModuleA(
output wire [31:0] a_data,
output wire a_valid,
input wire a_ready
);
ModuleB inst_b (
.b_data(a_data),
.b_valid(a_valid),
.b_ready(a_ready)
);
endmodule
"
);
}
#[test]
fn test_interface_connection_within_moddef() {
let module = ModDef::new("MyModule");
module.add_port("a_data", IO::Input(32));
module.add_port("a_valid", IO::Input(1));
module.add_port("a_ready", IO::Output(1));
module.add_port("b_data", IO::Output(32));
module.add_port("b_valid", IO::Output(1));
module.add_port("b_ready", IO::Input(1));
module.def_intf_from_prefix("a_intf", "a_");
module.def_intf_from_prefix("b_intf", "b_");
let a_intf = module.get_intf("a_intf");
let b_intf = module.get_intf("b_intf");
a_intf.connect(&b_intf, false);
assert_eq!(
module.emit(true),
"\
module MyModule(
input wire [31:0] a_data,
input wire a_valid,
output wire a_ready,
output wire [31:0] b_data,
output wire b_valid,
input wire b_ready
);
assign a_ready = b_ready;
assign b_data = a_data;
assign b_valid = a_valid;
endmodule
"
);
}
#[test]
fn test_export_interface_with_prefix() {
let module_a_verilog = "
module ModuleA (
output [31:0] a_data,
output a_valid,
input a_ready
);
endmodule
";
let module_a = ModDef::from_verilog("ModuleA", module_a_verilog, true, false);
module_a.def_intf_from_prefix("a", "a_");
let module_b = ModDef::new("ModuleB");
module_b
.instantiate(&module_a, None, None)
.get_intf("a")
.export_with_prefix("b", "b_");
let module_c = ModDef::new("ModuleC");
module_c
.instantiate(&module_b, None, None)
.get_intf("b")
.export_with_name_underscore("c");
assert_eq!(
module_c.emit(true),
"\
module ModuleB(
output wire [31:0] b_data,
output wire b_valid,
input wire b_ready
);
ModuleA ModuleA_i (
.a_data(b_data),
.a_valid(b_valid),
.a_ready(b_ready)
);
endmodule
module ModuleC(
output wire [31:0] c_data,
output wire c_valid,
input wire c_ready
);
ModuleB ModuleB_i (
.b_data(c_data),
.b_valid(c_valid),
.b_ready(c_ready)
);
endmodule
"
);
}
#[test]
fn test_intf_slice() {
let module_a_verilog = "
module ModuleA (
output [31:0] a_data,
output [3:0] a_valid,
input [1:0] a_ready
);
endmodule
";
let module_a = ModDef::from_verilog("ModuleA", module_a_verilog, true, false);
let mut mapping_lower: IndexMap<String, (String, usize, usize)> = IndexMap::new();
mapping_lower.insert("data".to_string(), ("a_data".to_string(), 15, 0));
mapping_lower.insert("valid".to_string(), ("a_valid".to_string(), 1, 0));
mapping_lower.insert("ready".to_string(), ("a_ready".to_string(), 0, 0));
module_a.def_intf("lower", mapping_lower);
let mut mapping_upper: IndexMap<String, (String, usize, usize)> = IndexMap::new();
mapping_upper.insert("data".to_string(), ("a_data".to_string(), 31, 16));
mapping_upper.insert("valid".to_string(), ("a_valid".to_string(), 3, 2));
mapping_upper.insert("ready".to_string(), ("a_ready".to_string(), 1, 1));
module_a.def_intf("upper", mapping_upper);
let top_module = ModDef::new("TopModule");
let a = top_module.instantiate(&module_a, None, None);
a.get_intf("upper").export_with_prefix("upper", "upper_");
a.get_intf("lower").export_with_prefix("lower", "lower_");
assert_eq!(
top_module.emit(true),
"\
module TopModule(
output wire [15:0] upper_data,
output wire [1:0] upper_valid,
input wire upper_ready,
output wire [15:0] lower_data,
output wire [1:0] lower_valid,
input wire lower_ready
);
ModuleA ModuleA_i (
.a_data({upper_data, lower_data}),
.a_valid({upper_valid, lower_valid}),
.a_ready({upper_ready, lower_ready})
);
endmodule
"
);
}
#[test]
fn test_intf_subdivide() {
let module_a_verilog = "
module ModuleA (
output [31:0] a_data,
output [3:0] a_valid,
input [1:0] a_ready
);
endmodule
";
let module_a = ModDef::from_verilog("ModuleA", module_a_verilog, true, false);
let a_intf = module_a.def_intf_from_prefix("a_intf", "a_");
a_intf.subdivide(2);
let top_module = ModDef::new("TopModule");
let a = top_module.instantiate(&module_a, None, None);
a.get_intf("a_intf_0").export_with_prefix("lower", "lower_");
a.get_intf("a_intf_1").export_with_prefix("upper", "upper_");
assert_eq!(
top_module.emit(true),
"\
module TopModule(
output wire [15:0] lower_data,
output wire [1:0] lower_valid,
input wire lower_ready,
output wire [15:0] upper_data,
output wire [1:0] upper_valid,
input wire upper_ready
);
ModuleA ModuleA_i (
.a_data({upper_data, lower_data}),
.a_valid({upper_valid, lower_valid}),
.a_ready({upper_ready, lower_ready})
);
endmodule
"
);
}
#[test]
fn test_complex_intf() {
let module_a_verilog = "
module ModuleA (
output [7:0] a_data_out,
output a_valid_out,
input [7:0] a_data_in,
input a_valid_in
);
endmodule
";
let module_b_verilog = "
module ModuleB (
output [15:0] b_data_out,
output [1:0] b_valid_out,
input [15:0] b_data_in,
input [1:0] b_valid_in
);
endmodule
";
let module_a = ModDef::from_verilog("ModuleA", module_a_verilog, true, false);
module_a.def_intf_from_prefix("a_intf", "a_");
let module_b = ModDef::from_verilog("ModuleB", module_b_verilog, true, false);
let b_intf = module_b.def_intf_from_prefix("b_intf", "b_");
b_intf.subdivide(2);
let top_module = ModDef::new("TopModule");
let a0 = top_module.instantiate(&module_a, Some("a0"), None);
let a1 = top_module.instantiate(&module_a, Some("a1"), None);
let b = top_module.instantiate(&module_b, None, None);
b.get_intf("b_intf_0")
.crossover(&a0.get_intf("a_intf"), "(.*)_in", "(.*)_out");
b.get_intf("b_intf_1")
.crossover(&a1.get_intf("a_intf"), "(.*)_in", "(.*)_out");
assert_eq!(
top_module.emit(true),
"\
module TopModule;
wire [7:0] a0_a_data_out;
wire a0_a_valid_out;
wire [15:0] ModuleB_i_b_data_out;
wire [1:0] ModuleB_i_b_valid_out;
ModuleA a0 (
.a_data_out(a0_a_data_out),
.a_valid_out(a0_a_valid_out),
.a_data_in(ModuleB_i_b_data_out[7:0]),
.a_valid_in(ModuleB_i_b_valid_out[0])
);
wire [7:0] a1_a_data_out;
wire a1_a_valid_out;
ModuleA a1 (
.a_data_out(a1_a_data_out),
.a_valid_out(a1_a_valid_out),
.a_data_in(ModuleB_i_b_data_out[15:8]),
.a_valid_in(ModuleB_i_b_valid_out[1])
);
ModuleB ModuleB_i (
.b_data_out(ModuleB_i_b_data_out),
.b_valid_out(ModuleB_i_b_valid_out),
.b_data_in({a1_a_data_out, a0_a_data_out}),
.b_valid_in({a1_a_valid_out, a0_a_valid_out})
);
endmodule
"
);
}
#[test]
fn test_intf_regex() {
let module_a_verilog = "
module ModuleA (
input [7:0] a_data_in,
input a_valid_in,
output [7:0] a_data_out,
output a_valid_out,
input [7:0] b_data_in,
input b_valid_in,
output [7:0] b_data_out,
output b_valid_out
);
endmodule
";
let module_a = ModDef::from_verilog("ModuleA", module_a_verilog, true, false);
module_a.def_intf_from_regexes("left", &[("a_(.*)_in", "a_$1"), ("b_(.*)_out", "b_$1")]);
module_a.def_intf_from_regexes("right", &[("a_(.*)_out", "a_$1"), ("b_(.*)_in", "b_$1")]);
let top_module = ModDef::new("TopModule");
let left = top_module.instantiate(&module_a, Some("left"), None);
let right = top_module.instantiate(&module_a, Some("right"), None);
left.get_intf("left").unused_and_tieoff(0);
left.get_intf("right")
.connect(&right.get_intf("left"), false);
right.get_intf("right").unused_and_tieoff(0);
assert_eq!(
top_module.emit(true),
"\
module TopModule;
wire [7:0] left_a_data_out;
wire left_a_valid_out;
wire [7:0] right_b_data_out;
wire right_b_valid_out;
ModuleA left (
.a_data_in(8'h00),
.a_valid_in(1'h0),
.a_data_out(left_a_data_out),
.a_valid_out(left_a_valid_out),
.b_data_in(right_b_data_out),
.b_valid_in(right_b_valid_out),
.b_data_out(),
.b_valid_out()
);
ModuleA right (
.a_data_in(left_a_data_out),
.a_valid_in(left_a_valid_out),
.a_data_out(),
.a_valid_out(),
.b_data_in(8'h00),
.b_valid_in(1'h0),
.b_data_out(right_b_data_out),
.b_valid_out(right_b_valid_out)
);
endmodule
"
);
}
#[test]
#[should_panic(expected = "Empty interface definition for A.b")]
fn test_empty_prefix_interface() {
let a_verilog = "\
module A(
output a_data,
output a_valid
);
endmodule";
let a_mod_def = ModDef::from_verilog("A", a_verilog, true, false);
a_mod_def.def_intf_from_name_underscore("b");
}
#[test]
#[should_panic(expected = "Empty interface definition for A.b")]
fn test_empty_regex_interface() {
let a_verilog = "\
module A(
output a_data,
output a_valid
);
endmodule";
let a_mod_def = ModDef::from_verilog("A", a_verilog, true, false);
a_mod_def.def_intf_from_regex("b", "^b_(.*)$", "${1}");
}
#[test]
#[should_panic(expected = "Interface function A.ab.data already exists")]
fn test_duplicate_intf_function_from_prefixes() {
let a_verilog = "\
module A(
output a_data,
output b_data
);
endmodule";
let a_mod_def = ModDef::from_verilog("A", a_verilog, true, false);
a_mod_def.def_intf_from_prefixes("ab", &["a_", "b_"], true);
}
#[test]
fn test_has_intf() {
let module_a_verilog = "
module ModuleA (
output [31:0] a_data,
output a_valid,
input a_ready
);
endmodule
";
let module_b_verilog = "
module ModuleB (
input [31:0] b_data,
input b_valid,
output b_ready
);
endmodule
";
let module_a = ModDef::from_verilog("ModuleA", module_a_verilog, true, false);
module_a.def_intf_from_prefix("a_intf", "a_");
assert!(module_a.has_intf("a_intf"));
assert!(!module_a.has_intf("b_intf"));
let module_b = ModDef::from_verilog("ModuleB", module_b_verilog, true, false);
module_b.def_intf_from_prefix("b_intf", "b_");
let top_module = ModDef::new("TopModule");
let b_inst = top_module.instantiate(&module_b, Some("inst_b"), None);
assert!(b_inst.has_intf("b_intf"));
assert!(!b_inst.has_intf("a_intf"));
}