pub enum Port {
ModDef {
mod_def_core: Weak<RefCell<ModDefCore>>,
name: String,
},
ModInst {
mod_def_core: Weak<RefCell<ModDefCore>>,
inst_name: String,
port_name: String,
},
}Expand description
Represents a port on a module definition or a module instance.
Variants§
Implementations§
Source§impl Port
impl Port
Sourcepub fn io(&self) -> IO
pub fn io(&self) -> IO
Returns the IO enum associated with this Port.
Examples found in repository?
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
fn main() {
// Path to the "examples" folder
let examples = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples");
// Import the adder module definition from a Verilog file
let adder_8_bit = ModDef::from_verilog_file(
"adder",
&examples.join("input").join("adder.sv"),
true,
false,
);
let adder_9_bit = adder_8_bit.parameterize(&[("W", 9)], None, None);
// Create a top-level module definition
let top = ModDef::new("top");
// Instantiate adders in a tree
let i00 = top.instantiate(&adder_8_bit, Some("i00"), None);
let i01 = top.instantiate(&adder_8_bit, Some("i01"), None);
let i11 = top.instantiate(&adder_9_bit, Some("i11"), None);
let a = top.add_port("in0", i00.get_port("a").io());
let b = top.add_port("in1", i00.get_port("b").io());
let c = top.add_port("in2", i01.get_port("a").io());
let sum = top.add_port("sum", i11.get_port("sum").io());
// Wire together adders in a tree
a.connect(&i00.get_port("a"));
i00.get_port("b").connect(&b); // order doesn't matter
c.connect(&i01.get_port("a"));
i01.get_port("b").tieoff(42); // required because unconnected inputs are not allowed
i00.get_port("sum").connect(&i11.get_port("a"));
i01.get_port("sum").connect(&i11.get_port("b"));
// Connect the final adder output the top-level output
sum.connect(&i11.get_port("sum"));
// Emit the final Verilog code
let output_dir = examples.join("output");
std::fs::create_dir_all(&output_dir).expect("should be possible to create output dir");
let output_file = output_dir.join("top.sv");
top.emit_to_file(&output_file, true);
eprintln!("Emitted to output file: {}", output_file.display());
}Source§impl Port
impl Port
Sourcepub fn connect<T: ConvertibleToPortSlice>(&self, other: &T)
pub fn connect<T: ConvertibleToPortSlice>(&self, other: &T)
Connects this port to another port or port slice.
Examples found in repository?
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
fn main() {
// Path to the "examples" folder
let examples = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples");
let input = examples.join("input");
// Parse the Verilog sources. Note that multiple sources can be specified.
let block = ModDef::from_verilog_files(
"block",
&[&input.join("pack.sv"), &input.join("block.sv")],
false,
false,
);
// Parameterization is optional; it's shown here to illustrate the feature. The
// parameterize() function returns a new ModDef with the given parameter values.
// Unspecified parameters will use their default values.
let block_parameterized = block.parameterize(&[("N", 32)], None, None);
// Create a stub for the parameterized block. Try replacing
// "block_parameterized" with "block" - it will still work, using default
// parameter values.
let stub = block_parameterized.stub("stub");
let a = stub.get_port("a");
let b_array = stub.get_port("b").subdivide(2);
a.connect(&b_array[0]);
b_array[1].tieoff(0);
stub.get_port("c").connect(&stub.get_port("d"));
// Emit the final Verilog code
let output_dir = examples.join("output");
std::fs::create_dir_all(&output_dir).expect("should be possible to create output dir");
let output_file = output_dir.join("stub.sv");
stub.emit_to_file(&output_file, true);
eprintln!("Emitted to output file: {}", output_file.display());
}More examples
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
fn main() {
// Path to the "examples" folder
let examples = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples");
// Import the adder module definition from a Verilog file
let adder_8_bit = ModDef::from_verilog_file(
"adder",
&examples.join("input").join("adder.sv"),
true,
false,
);
let adder_9_bit = adder_8_bit.parameterize(&[("W", 9)], None, None);
// Create a top-level module definition
let top = ModDef::new("top");
// Instantiate adders in a tree
let i00 = top.instantiate(&adder_8_bit, Some("i00"), None);
let i01 = top.instantiate(&adder_8_bit, Some("i01"), None);
let i11 = top.instantiate(&adder_9_bit, Some("i11"), None);
let a = top.add_port("in0", i00.get_port("a").io());
let b = top.add_port("in1", i00.get_port("b").io());
let c = top.add_port("in2", i01.get_port("a").io());
let sum = top.add_port("sum", i11.get_port("sum").io());
// Wire together adders in a tree
a.connect(&i00.get_port("a"));
i00.get_port("b").connect(&b); // order doesn't matter
c.connect(&i01.get_port("a"));
i01.get_port("b").tieoff(42); // required because unconnected inputs are not allowed
i00.get_port("sum").connect(&i11.get_port("a"));
i01.get_port("sum").connect(&i11.get_port("b"));
// Connect the final adder output the top-level output
sum.connect(&i11.get_port("sum"));
// Emit the final Verilog code
let output_dir = examples.join("output");
std::fs::create_dir_all(&output_dir).expect("should be possible to create output dir");
let output_file = output_dir.join("top.sv");
top.emit_to_file(&output_file, true);
eprintln!("Emitted to output file: {}", output_file.display());
}9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
fn main() {
// Path to the "examples" folder
let examples = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples");
let block = ModDef::new("Block");
///////////////////////
// Basic connections //
///////////////////////
let a = block.add_port("a", Input(8));
let b = block.add_port("b", Input(64));
let c = block.add_port("c", Output(16));
block.add_port("d", Output(32)); // will show how this can be retrieved by name
let e = block.add_port("e", Input(1));
let f = block.add_port("f", Input(16));
let g = block.add_port("g", Output(8));
let h = block.add_port("h", Output(8));
// this would be an error due to width mismatch
// a.connect(&stub.get_port("c"));
a.connect(&c.slice(7, 0));
c.slice(15, 8).tieoff(0); // without this, will get an error, "Stub.c is not fully driven."
let d = block.get_port("d");
b.slice(31, 0).connect(&d);
b.slice(63, 32).unused(); // without this, will get an error, "Stub.b is not fully used."
e.unused(); // without this, will get an error, "Stub.e is not fully used."
let f_array = f.subdivide(2);
f_array[0].connect(&g);
f_array[1].connect(&h);
//////////////////
// Feedthroughs //
//////////////////
block.feedthrough("ft_in", "ft_out", 128);
////////////////
// Interfaces //
////////////////
// connect by matching function name
block.add_port("a_intf_data", Input(8));
block.add_port("a_intf_valid", Output(1));
let a_intf = block.def_intf_from_prefix("a_intf", "a_intf_");
block.add_port("b_intf_data", Output(8));
block.add_port("b_intf_valid", Input(1));
block.def_intf_from_prefix("b_intf", "b_intf_"); // will show how to retrieve this
a_intf.connect(&block.get_intf("b_intf"), false);
// connect by "crossover" (using regex connection)
block.add_port("c_intf_data_tx", Output(8));
block.add_port("c_intf_data_rx", Input(8));
block.add_port("c_intf_valid_tx", Output(1));
block.add_port("c_intf_valid_rx", Input(1));
let c_intf = block.def_intf_from_prefix("c_intf", "c_intf_");
block.add_port("d_intf_data_tx", Output(8));
block.add_port("d_intf_data_rx", Input(8));
block.add_port("d_intf_valid_tx", Output(1));
block.add_port("d_intf_valid_rx", Input(1));
let d_intf = block.def_intf_from_prefix("d_intf", "d_intf_");
c_intf.crossover(&d_intf, "^(.*)_tx$", "^(.*)_rx$");
// interface subdivision
block.add_port("e_intf_data_tx", Output(16));
block.add_port("e_intf_data_rx", Input(16));
block.add_port("e_intf_valid_tx", Output(2));
block.add_port("e_intf_valid_rx", Input(2));
let e_intf = block.def_intf_from_prefix("e_intf", "e_intf_");
block.add_port("f_intf_data_tx", Output(8));
block.add_port("f_intf_data_rx", Input(8));
block.add_port("f_intf_valid_tx", Output(1));
block.add_port("f_intf_valid_rx", Input(1));
let f_intf = block.def_intf_from_prefix("f_intf", "f_intf_");
block.add_port("g_intf_data_tx", Output(8));
block.add_port("g_intf_data_rx", Input(8));
block.add_port("g_intf_valid_tx", Output(1));
block.add_port("g_intf_valid_rx", Input(1));
let g_intf = block.def_intf_from_prefix("g_intf", "g_intf_");
let e_intf_array = e_intf.subdivide(2);
e_intf_array[0].crossover(&f_intf, "^(.*)_tx$", "^(.*)_rx$");
e_intf_array[1].crossover(&g_intf, "^(.*)_tx$", "^(.*)_rx$");
// marking interfaces as unused
block.add_port("h_intf_data_tx", Output(8));
block.add_port("h_intf_data_rx", Input(8));
block.add_port("h_intf_valid_tx", Output(1));
block.add_port("h_intf_valid_rx", Input(1));
let h_intf = block.def_intf_from_prefix("h_intf", "h_intf_");
h_intf.unused(); // marks all inputs as unused
h_intf.tieoff(0); // ties off all outputs to 0
// Emit the final Verilog code
let output_dir = examples.join("output");
std::fs::create_dir_all(&output_dir).expect("should be possible to create output dir");
let output_file = output_dir.join("block.sv");
block.emit_to_file(&output_file, true);
eprintln!("Emitted to output file: {}", output_file.display());
}pub fn connect_pipeline<T: ConvertibleToPortSlice>( &self, other: &T, pipeline: PipelineConfig, )
Sourcepub fn tieoff<T: Into<BigInt>>(&self, value: T)
pub fn tieoff<T: Into<BigInt>>(&self, value: T)
Ties off this port to the given constant value, specified as a BigInt
or type that can be converted to a BigInt.
Examples found in repository?
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
fn main() {
// Path to the "examples" folder
let examples = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples");
// Import the adder module definition from a Verilog file
let adder_8_bit = ModDef::from_verilog_file(
"adder",
&examples.join("input").join("adder.sv"),
true,
false,
);
let adder_9_bit = adder_8_bit.parameterize(&[("W", 9)], None, None);
// Create a top-level module definition
let top = ModDef::new("top");
// Instantiate adders in a tree
let i00 = top.instantiate(&adder_8_bit, Some("i00"), None);
let i01 = top.instantiate(&adder_8_bit, Some("i01"), None);
let i11 = top.instantiate(&adder_9_bit, Some("i11"), None);
let a = top.add_port("in0", i00.get_port("a").io());
let b = top.add_port("in1", i00.get_port("b").io());
let c = top.add_port("in2", i01.get_port("a").io());
let sum = top.add_port("sum", i11.get_port("sum").io());
// Wire together adders in a tree
a.connect(&i00.get_port("a"));
i00.get_port("b").connect(&b); // order doesn't matter
c.connect(&i01.get_port("a"));
i01.get_port("b").tieoff(42); // required because unconnected inputs are not allowed
i00.get_port("sum").connect(&i11.get_port("a"));
i01.get_port("sum").connect(&i11.get_port("b"));
// Connect the final adder output the top-level output
sum.connect(&i11.get_port("sum"));
// Emit the final Verilog code
let output_dir = examples.join("output");
std::fs::create_dir_all(&output_dir).expect("should be possible to create output dir");
let output_file = output_dir.join("top.sv");
top.emit_to_file(&output_file, true);
eprintln!("Emitted to output file: {}", output_file.display());
}Sourcepub fn unused(&self)
pub fn unused(&self)
Marks this port as unused, meaning that if it is a module instance output or module definition input, validation will not fail if the port drives nothing. In fact, validation will fail if the port drives anything.
Examples found in repository?
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
fn main() {
// Path to the "examples" folder
let examples = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples");
let block = ModDef::new("Block");
///////////////////////
// Basic connections //
///////////////////////
let a = block.add_port("a", Input(8));
let b = block.add_port("b", Input(64));
let c = block.add_port("c", Output(16));
block.add_port("d", Output(32)); // will show how this can be retrieved by name
let e = block.add_port("e", Input(1));
let f = block.add_port("f", Input(16));
let g = block.add_port("g", Output(8));
let h = block.add_port("h", Output(8));
// this would be an error due to width mismatch
// a.connect(&stub.get_port("c"));
a.connect(&c.slice(7, 0));
c.slice(15, 8).tieoff(0); // without this, will get an error, "Stub.c is not fully driven."
let d = block.get_port("d");
b.slice(31, 0).connect(&d);
b.slice(63, 32).unused(); // without this, will get an error, "Stub.b is not fully used."
e.unused(); // without this, will get an error, "Stub.e is not fully used."
let f_array = f.subdivide(2);
f_array[0].connect(&g);
f_array[1].connect(&h);
//////////////////
// Feedthroughs //
//////////////////
block.feedthrough("ft_in", "ft_out", 128);
////////////////
// Interfaces //
////////////////
// connect by matching function name
block.add_port("a_intf_data", Input(8));
block.add_port("a_intf_valid", Output(1));
let a_intf = block.def_intf_from_prefix("a_intf", "a_intf_");
block.add_port("b_intf_data", Output(8));
block.add_port("b_intf_valid", Input(1));
block.def_intf_from_prefix("b_intf", "b_intf_"); // will show how to retrieve this
a_intf.connect(&block.get_intf("b_intf"), false);
// connect by "crossover" (using regex connection)
block.add_port("c_intf_data_tx", Output(8));
block.add_port("c_intf_data_rx", Input(8));
block.add_port("c_intf_valid_tx", Output(1));
block.add_port("c_intf_valid_rx", Input(1));
let c_intf = block.def_intf_from_prefix("c_intf", "c_intf_");
block.add_port("d_intf_data_tx", Output(8));
block.add_port("d_intf_data_rx", Input(8));
block.add_port("d_intf_valid_tx", Output(1));
block.add_port("d_intf_valid_rx", Input(1));
let d_intf = block.def_intf_from_prefix("d_intf", "d_intf_");
c_intf.crossover(&d_intf, "^(.*)_tx$", "^(.*)_rx$");
// interface subdivision
block.add_port("e_intf_data_tx", Output(16));
block.add_port("e_intf_data_rx", Input(16));
block.add_port("e_intf_valid_tx", Output(2));
block.add_port("e_intf_valid_rx", Input(2));
let e_intf = block.def_intf_from_prefix("e_intf", "e_intf_");
block.add_port("f_intf_data_tx", Output(8));
block.add_port("f_intf_data_rx", Input(8));
block.add_port("f_intf_valid_tx", Output(1));
block.add_port("f_intf_valid_rx", Input(1));
let f_intf = block.def_intf_from_prefix("f_intf", "f_intf_");
block.add_port("g_intf_data_tx", Output(8));
block.add_port("g_intf_data_rx", Input(8));
block.add_port("g_intf_valid_tx", Output(1));
block.add_port("g_intf_valid_rx", Input(1));
let g_intf = block.def_intf_from_prefix("g_intf", "g_intf_");
let e_intf_array = e_intf.subdivide(2);
e_intf_array[0].crossover(&f_intf, "^(.*)_tx$", "^(.*)_rx$");
e_intf_array[1].crossover(&g_intf, "^(.*)_tx$", "^(.*)_rx$");
// marking interfaces as unused
block.add_port("h_intf_data_tx", Output(8));
block.add_port("h_intf_data_rx", Input(8));
block.add_port("h_intf_valid_tx", Output(1));
block.add_port("h_intf_valid_rx", Input(1));
let h_intf = block.def_intf_from_prefix("h_intf", "h_intf_");
h_intf.unused(); // marks all inputs as unused
h_intf.tieoff(0); // ties off all outputs to 0
// Emit the final Verilog code
let output_dir = examples.join("output");
std::fs::create_dir_all(&output_dir).expect("should be possible to create output dir");
let output_file = output_dir.join("block.sv");
block.emit_to_file(&output_file, true);
eprintln!("Emitted to output file: {}", output_file.display());
}Sourcepub fn slice(&self, msb: usize, lsb: usize) -> PortSlice
pub fn slice(&self, msb: usize, lsb: usize) -> PortSlice
Returns a slice of this port from msb down to lsb, inclusive.
Examples found in repository?
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
fn main() {
// Path to the "examples" folder
let examples = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples");
let block = ModDef::new("Block");
///////////////////////
// Basic connections //
///////////////////////
let a = block.add_port("a", Input(8));
let b = block.add_port("b", Input(64));
let c = block.add_port("c", Output(16));
block.add_port("d", Output(32)); // will show how this can be retrieved by name
let e = block.add_port("e", Input(1));
let f = block.add_port("f", Input(16));
let g = block.add_port("g", Output(8));
let h = block.add_port("h", Output(8));
// this would be an error due to width mismatch
// a.connect(&stub.get_port("c"));
a.connect(&c.slice(7, 0));
c.slice(15, 8).tieoff(0); // without this, will get an error, "Stub.c is not fully driven."
let d = block.get_port("d");
b.slice(31, 0).connect(&d);
b.slice(63, 32).unused(); // without this, will get an error, "Stub.b is not fully used."
e.unused(); // without this, will get an error, "Stub.e is not fully used."
let f_array = f.subdivide(2);
f_array[0].connect(&g);
f_array[1].connect(&h);
//////////////////
// Feedthroughs //
//////////////////
block.feedthrough("ft_in", "ft_out", 128);
////////////////
// Interfaces //
////////////////
// connect by matching function name
block.add_port("a_intf_data", Input(8));
block.add_port("a_intf_valid", Output(1));
let a_intf = block.def_intf_from_prefix("a_intf", "a_intf_");
block.add_port("b_intf_data", Output(8));
block.add_port("b_intf_valid", Input(1));
block.def_intf_from_prefix("b_intf", "b_intf_"); // will show how to retrieve this
a_intf.connect(&block.get_intf("b_intf"), false);
// connect by "crossover" (using regex connection)
block.add_port("c_intf_data_tx", Output(8));
block.add_port("c_intf_data_rx", Input(8));
block.add_port("c_intf_valid_tx", Output(1));
block.add_port("c_intf_valid_rx", Input(1));
let c_intf = block.def_intf_from_prefix("c_intf", "c_intf_");
block.add_port("d_intf_data_tx", Output(8));
block.add_port("d_intf_data_rx", Input(8));
block.add_port("d_intf_valid_tx", Output(1));
block.add_port("d_intf_valid_rx", Input(1));
let d_intf = block.def_intf_from_prefix("d_intf", "d_intf_");
c_intf.crossover(&d_intf, "^(.*)_tx$", "^(.*)_rx$");
// interface subdivision
block.add_port("e_intf_data_tx", Output(16));
block.add_port("e_intf_data_rx", Input(16));
block.add_port("e_intf_valid_tx", Output(2));
block.add_port("e_intf_valid_rx", Input(2));
let e_intf = block.def_intf_from_prefix("e_intf", "e_intf_");
block.add_port("f_intf_data_tx", Output(8));
block.add_port("f_intf_data_rx", Input(8));
block.add_port("f_intf_valid_tx", Output(1));
block.add_port("f_intf_valid_rx", Input(1));
let f_intf = block.def_intf_from_prefix("f_intf", "f_intf_");
block.add_port("g_intf_data_tx", Output(8));
block.add_port("g_intf_data_rx", Input(8));
block.add_port("g_intf_valid_tx", Output(1));
block.add_port("g_intf_valid_rx", Input(1));
let g_intf = block.def_intf_from_prefix("g_intf", "g_intf_");
let e_intf_array = e_intf.subdivide(2);
e_intf_array[0].crossover(&f_intf, "^(.*)_tx$", "^(.*)_rx$");
e_intf_array[1].crossover(&g_intf, "^(.*)_tx$", "^(.*)_rx$");
// marking interfaces as unused
block.add_port("h_intf_data_tx", Output(8));
block.add_port("h_intf_data_rx", Input(8));
block.add_port("h_intf_valid_tx", Output(1));
block.add_port("h_intf_valid_rx", Input(1));
let h_intf = block.def_intf_from_prefix("h_intf", "h_intf_");
h_intf.unused(); // marks all inputs as unused
h_intf.tieoff(0); // ties off all outputs to 0
// Emit the final Verilog code
let output_dir = examples.join("output");
std::fs::create_dir_all(&output_dir).expect("should be possible to create output dir");
let output_file = output_dir.join("block.sv");
block.emit_to_file(&output_file, true);
eprintln!("Emitted to output file: {}", output_file.display());
}Sourcepub fn subdivide(&self, n: usize) -> Vec<PortSlice>
pub fn subdivide(&self, n: usize) -> Vec<PortSlice>
Splits this port into n equal slices, returning a vector of port
slices. For example, if this port is 8-bit wide and n is 4, this will
return a vector of 4 port slices, each 2 bits wide: [1:0], [3:2],
[5:4], and [7:6].
Examples found in repository?
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
fn main() {
// Path to the "examples" folder
let examples = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples");
let input = examples.join("input");
// Parse the Verilog sources. Note that multiple sources can be specified.
let block = ModDef::from_verilog_files(
"block",
&[&input.join("pack.sv"), &input.join("block.sv")],
false,
false,
);
// Parameterization is optional; it's shown here to illustrate the feature. The
// parameterize() function returns a new ModDef with the given parameter values.
// Unspecified parameters will use their default values.
let block_parameterized = block.parameterize(&[("N", 32)], None, None);
// Create a stub for the parameterized block. Try replacing
// "block_parameterized" with "block" - it will still work, using default
// parameter values.
let stub = block_parameterized.stub("stub");
let a = stub.get_port("a");
let b_array = stub.get_port("b").subdivide(2);
a.connect(&b_array[0]);
b_array[1].tieoff(0);
stub.get_port("c").connect(&stub.get_port("d"));
// Emit the final Verilog code
let output_dir = examples.join("output");
std::fs::create_dir_all(&output_dir).expect("should be possible to create output dir");
let output_file = output_dir.join("stub.sv");
stub.emit_to_file(&output_file, true);
eprintln!("Emitted to output file: {}", output_file.display());
}More examples
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
fn main() {
// Path to the "examples" folder
let examples = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples");
let block = ModDef::new("Block");
///////////////////////
// Basic connections //
///////////////////////
let a = block.add_port("a", Input(8));
let b = block.add_port("b", Input(64));
let c = block.add_port("c", Output(16));
block.add_port("d", Output(32)); // will show how this can be retrieved by name
let e = block.add_port("e", Input(1));
let f = block.add_port("f", Input(16));
let g = block.add_port("g", Output(8));
let h = block.add_port("h", Output(8));
// this would be an error due to width mismatch
// a.connect(&stub.get_port("c"));
a.connect(&c.slice(7, 0));
c.slice(15, 8).tieoff(0); // without this, will get an error, "Stub.c is not fully driven."
let d = block.get_port("d");
b.slice(31, 0).connect(&d);
b.slice(63, 32).unused(); // without this, will get an error, "Stub.b is not fully used."
e.unused(); // without this, will get an error, "Stub.e is not fully used."
let f_array = f.subdivide(2);
f_array[0].connect(&g);
f_array[1].connect(&h);
//////////////////
// Feedthroughs //
//////////////////
block.feedthrough("ft_in", "ft_out", 128);
////////////////
// Interfaces //
////////////////
// connect by matching function name
block.add_port("a_intf_data", Input(8));
block.add_port("a_intf_valid", Output(1));
let a_intf = block.def_intf_from_prefix("a_intf", "a_intf_");
block.add_port("b_intf_data", Output(8));
block.add_port("b_intf_valid", Input(1));
block.def_intf_from_prefix("b_intf", "b_intf_"); // will show how to retrieve this
a_intf.connect(&block.get_intf("b_intf"), false);
// connect by "crossover" (using regex connection)
block.add_port("c_intf_data_tx", Output(8));
block.add_port("c_intf_data_rx", Input(8));
block.add_port("c_intf_valid_tx", Output(1));
block.add_port("c_intf_valid_rx", Input(1));
let c_intf = block.def_intf_from_prefix("c_intf", "c_intf_");
block.add_port("d_intf_data_tx", Output(8));
block.add_port("d_intf_data_rx", Input(8));
block.add_port("d_intf_valid_tx", Output(1));
block.add_port("d_intf_valid_rx", Input(1));
let d_intf = block.def_intf_from_prefix("d_intf", "d_intf_");
c_intf.crossover(&d_intf, "^(.*)_tx$", "^(.*)_rx$");
// interface subdivision
block.add_port("e_intf_data_tx", Output(16));
block.add_port("e_intf_data_rx", Input(16));
block.add_port("e_intf_valid_tx", Output(2));
block.add_port("e_intf_valid_rx", Input(2));
let e_intf = block.def_intf_from_prefix("e_intf", "e_intf_");
block.add_port("f_intf_data_tx", Output(8));
block.add_port("f_intf_data_rx", Input(8));
block.add_port("f_intf_valid_tx", Output(1));
block.add_port("f_intf_valid_rx", Input(1));
let f_intf = block.def_intf_from_prefix("f_intf", "f_intf_");
block.add_port("g_intf_data_tx", Output(8));
block.add_port("g_intf_data_rx", Input(8));
block.add_port("g_intf_valid_tx", Output(1));
block.add_port("g_intf_valid_rx", Input(1));
let g_intf = block.def_intf_from_prefix("g_intf", "g_intf_");
let e_intf_array = e_intf.subdivide(2);
e_intf_array[0].crossover(&f_intf, "^(.*)_tx$", "^(.*)_rx$");
e_intf_array[1].crossover(&g_intf, "^(.*)_tx$", "^(.*)_rx$");
// marking interfaces as unused
block.add_port("h_intf_data_tx", Output(8));
block.add_port("h_intf_data_rx", Input(8));
block.add_port("h_intf_valid_tx", Output(1));
block.add_port("h_intf_valid_rx", Input(1));
let h_intf = block.def_intf_from_prefix("h_intf", "h_intf_");
h_intf.unused(); // marks all inputs as unused
h_intf.tieoff(0); // ties off all outputs to 0
// Emit the final Verilog code
let output_dir = examples.join("output");
std::fs::create_dir_all(&output_dir).expect("should be possible to create output dir");
let output_file = output_dir.join("block.sv");
block.emit_to_file(&output_file, true);
eprintln!("Emitted to output file: {}", output_file.display());
}Sourcepub fn export_as(&self, name: impl AsRef<str>) -> Port
pub fn export_as(&self, name: impl AsRef<str>) -> Port
Create a new port called name on the parent module and connects it to
this port.
The exact behavior depends on whether this is a port on a module
definition or a module instance. If this is a port on a module
definition, a new port is created on the same module definition, with
the same width, but opposite direction. For example, suppose that this
is a port a on a module definition that is an 8-bit input; calling
export_as("y") will create an 8-bit output on the same module
definition called y.
If, on the other hand, this is a port on a module instance, a new port
will be created on the module definition containing the instance, with
the same width and direction. For example, if this is an 8-bit input
port x on a module instance, calling export_as("y") will create a
new 8-bit input port y on the module definition that contains the
instance.
Trait Implementations§
Source§impl ConvertibleToPortSlice for Port
impl ConvertibleToPortSlice for Port
fn to_port_slice(&self) -> PortSlice
Auto Trait Implementations§
impl Freeze for Port
impl !RefUnwindSafe for Port
impl !Send for Port
impl !Sync for Port
impl Unpin for Port
impl !UnwindSafe for Port
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more