pub struct PortSlice { /* private fields */ }Expand description
Represents a slice of a port, which may be on a module definition or on a module instance.
A slice is a defined as a contiguous range of bits from msb down to lsb,
inclusive. A slice can be a single bit on the port (msb equal to lsb),
the entire port, or any range in between.
Implementations§
Source§impl PortSlice
impl PortSlice
Sourcepub fn subdivide(&self, n: usize) -> Vec<Self>
pub fn subdivide(&self, n: usize) -> Vec<Self>
Divides a port slice into n parts of equal bit width, return a vector
of n port slices. For example, if a port is 8 bits wide and n is 2,
the port will be divided into 2 slices of 4 bits each: port[3:0] and
port[7:4]. This method panics if the port width is not divisible by
n.
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 slice.
The exact behavior depends on whether this is a port slice on a module
definition or a module instance. If this is a port slice 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 slice 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 slice 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.
Source§impl PortSlice
impl PortSlice
Sourcepub fn connect<T: ConvertibleToPortSlice>(&self, other: &T)
pub fn connect<T: ConvertibleToPortSlice>(&self, other: &T)
Connects this port slice to another port or port slice. Performs some upfront checks to make sure that the connection is valid in terms of width and directionality. Panics if any of these checks fail.
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());
}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 slice 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
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 unused(&self)
pub fn unused(&self)
Marks this port slice as unused, meaning that if it is an module instance output or module definition input, validation will not fail if the slice drives nothing. In fact, validation will fail if the slice 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());
}Trait Implementations§
Source§impl ConvertibleToPortSlice for PortSlice
impl ConvertibleToPortSlice for PortSlice
fn to_port_slice(&self) -> PortSlice
Auto Trait Implementations§
impl Freeze for PortSlice
impl !RefUnwindSafe for PortSlice
impl !Send for PortSlice
impl !Sync for PortSlice
impl Unpin for PortSlice
impl !UnwindSafe for PortSlice
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