topstitch

Enum Port

Source
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§

§

ModDef

Fields

§mod_def_core: Weak<RefCell<ModDefCore>>
§name: String
§

ModInst

Fields

§mod_def_core: Weak<RefCell<ModDefCore>>
§inst_name: String
§port_name: String

Implementations§

Source§

impl Port

Source

pub fn name(&self) -> &str

Returns the name this port has in its (parent) module definition.

Source

pub fn io(&self) -> IO

Returns the IO enum associated with this Port.

Examples found in repository?
examples/demo.rs (line 31)
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

Source

pub fn connect<T: ConvertibleToPortSlice>(&self, other: &T)

Connects this port to another port or port slice.

Examples found in repository?
examples/stub.rs (line 33)
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
Hide additional examples
examples/demo.rs (line 38)
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());
}
examples/features.rs (line 32)
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());
}
Source

pub fn connect_pipeline<T: ConvertibleToPortSlice>( &self, other: &T, pipeline: PipelineConfig, )

Source

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?
examples/demo.rs (line 42)
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

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?
examples/features.rs (line 39)
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());
}
Source

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?
examples/features.rs (line 32)
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());
}
Source

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?
examples/stub.rs (line 31)
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
Hide additional examples
examples/features.rs (line 41)
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());
}
Source

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.

Source

pub fn export(&self) -> Port

Same as export_as(), but the new port is created with the same name as the port being exported. As a result, this method can only be used with ports on module instances. The method will panic if called on a port on a module definition.

Trait Implementations§

Source§

impl Clone for Port

Source§

fn clone(&self) -> Port

Returns a copy of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl ConvertibleToPortSlice for Port

Source§

impl Debug for Port

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

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> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dst: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.