Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement basic abstract structural implementation #55

Closed
wants to merge 10 commits into from
Closed

Conversation

johanpel
Copy link
Member

@johanpel johanpel commented Mar 31, 2020

This PR will allow users to create structural implementations of streamlets, by combining primitive streamlets into larger designs, referencing them from various libraries within a project.

This should be geared towards two use cases:

  • For now, it should be able to build up the implementation using a hardware construction library approach (e.g. writing Rust to construct the implementation).
  • In the future, it should be possible to generate everything from the parser.

To-do:

  • Set up basic data structure for structural streamlet implementation.
  • Add parsers for types as per Add concrete type definitions #51
  • Implement data structure for named and anonymous types as per description in Add concrete type definitions #51 , but also:
  • Allow named types to be recursively defined in parsers.
  • Allow named types to be recursively defined in data structure. This involves either an overhaul of the logical type module or the creation of a companion module that allows named types to be used in other logical types.

Non-goals for this PR:

  • Back-end
  • Advanced hardware construction features such as being able to do automatic slices, buffers, syncs, profilers, functional style maps, reduces, filters, etc.. understanding the implications for specific logical types. This is being investigated by students.

@johanpel johanpel added enhancement New feature or request WIP: do not merge Work in progress, do not merge until tag is removed labels Mar 31, 2020
@johanpel johanpel self-assigned this Mar 31, 2020
@codecov
Copy link

codecov bot commented Mar 31, 2020

Codecov Report

Merging #55 into master will increase coverage by 2.54%.
The diff coverage is 87.65%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master      #55      +/-   ##
==========================================
+ Coverage   78.41%   80.95%   +2.54%     
==========================================
  Files          15       24       +9     
  Lines        2001     2626     +625     
==========================================
+ Hits         1569     2126     +557     
- Misses        432      500      +68     
Impacted Files Coverage Δ
src/generator/vhdl/mod.rs 87.85% <ø> (ø)
src/lib.rs 67.40% <ø> (ø)
src/logical.rs 64.14% <ø> (ø)
src/physical.rs 93.17% <ø> (ø)
src/traits.rs 100.00% <ø> (ø)
src/util.rs 100.00% <ø> (ø)
src/bin/tydi.rs 88.23% <50.00%> (-5.10%) ⬇️
src/error.rs 44.44% <50.00%> (+25.69%) ⬆️
src/design/implementation/structural/mod.rs 72.50% <72.50%> (ø)
src/parser/nom.rs 84.93% <79.16%> (-2.38%) ⬇️
... and 24 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 801fc01...d6e835b. Read the comment docs.

src/design/implementation.rs Outdated Show resolved Hide resolved
src/design/interface.rs Outdated Show resolved Hide resolved
src/design/interface.rs Outdated Show resolved Hide resolved
src/design/interface.rs Outdated Show resolved Hide resolved
src/design/interface.rs Outdated Show resolved Hide resolved
src/design/interface.rs Outdated Show resolved Hide resolved
src/design/interface.rs Show resolved Hide resolved

/// Trait to construct node interface references from various node types.
pub trait Interfaces {
fn io<K>(&self, key: K) -> Result<NodeIORef>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of the pattern where connect takes these Results. I understand from the example that this results in a friendly API. However, I prefer to keep handling of Resulttypes up to users i.e. modify the signature of connect to take NodeIORef instead of Result<NodeIORef>. Or allow users to pass impl TryInto<InterfaceKey> into the connect function instead.


/// The StructuralImplBuilder struct allows users to implement streamlets by structurally
/// combining streamlets into larger designs.
#[derive(Clone, PartialEq)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's good practice to have all pub items implement Debug.

/// This function returns an Error if the streamlet reference is invalid w.r.t. the project.
pub fn try_new(project: &'prj Project, streamlet: StreamletRef) -> Result<Self> {
// Check if the reference is OK.
project.get_streamlet(streamlet.clone())?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's more ergonomic when the get_streamlet function clones when it needs to. However the current implementation takes a reference of that key to get the value so the argument of get_streamlet can be &StreamletRef.

/// let mut builder = StructuralImplBuilder::try_new(&prj, foo)?;
///
/// let beans = builder.this().io("beans"); // Obtain a (valid) reference to the beans interface.
/// let coffee = builder.this().io("covfefe"); // Oops, made a typo! The reference is invalid.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition to the comment above, here I would expect users to check the result.

let coffee = builder.this().io("covfefe")?;

}

/// Return the node representing the external interfaces of the streamlet itself.
pub fn this(&self) -> Node {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reason to return an owned instance of the node instead of a reference here?


/// Return an iterator over all nodes in the structural graph.
pub fn nodes(&self) -> impl Iterator<Item = &Node> {
self.nodes.iter().map(|(_, v)| v)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a values method on IndexMap.

pub fn libraries(&self) -> impl Iterator<Item = &Library> {
self.libraries.iter()
self.libraries.iter().map(|(_, l)| l)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use the IndexMap Values iterator.

pub fn set_implementation(&self, implementation: Implementation) -> Result<()> {
if let Some(r) = implementation.streamlet() {
if r.streamlet == self.key {
*self.implementation.borrow_mut().deref_mut() = implementation;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may want to use try_borrow_mut here and return an error instead of a panic.

@@ -1,5 +1,6 @@
//! Error variants.
use log::SetLoggerError;
use nom::lib::std::convert::Infallible;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like your editor is trying to be smart.

Comment on lines 533 to 627
// UniqueKeyBuilder::new()
// .with_item(
// Interface::try_new(
// "a",
// Mode::In,
// Rc::new(
// TydiType::try_new(
// "TODO",
// LogicalType::try_new_group(vec![("a", 1), ("b", 2)])
// .unwrap()
// )
// .unwrap()
// ),
// None
// )
// .unwrap()
// )
// .with_item(
// Interface::try_new(
// "c",
// Mode::Out,
// Rc::new(TydiType::try_new("TODO", LogicalType::Null).unwrap()),
// None
// )
// .unwrap()
// ),
// None
// )
// .unwrap()
// ))
// );
// }

// #[test]
// fn parse_streamlet_docstring() {
// assert_eq!(
// streamlet(
// "/// Test
// // some other stuff
// /* that people could put here */
// /* even though */ // it's not pretty
// /// unaligned doc string
//
// Streamlet x (
// /// Such a weird interface
// a : in Null,
// /// And another one
// b : out Null )"
// ),
// Ok((
// "",
// Streamlet::from_builder(
// Name::try_new("x").unwrap(),
// UniqueKeyBuilder::new().with_items(vec![
// Interface::try_new(
// "a",
// Mode::In,
// Rc::new(TydiType::try_new("TODO", LogicalType::Null).unwrap()),
// Some(" Such a weird interface")
// )
// .unwrap(),
// Interface::try_new(
// "b",
// Mode::Out,
// Rc::new(TydiType::try_new("TODO", LogicalType::Null).unwrap()),
// Some(" And another one")
// )
// .unwrap(),
// ]),
// Some(" Test\n unaligned doc string"),
// )
// .unwrap()
// ))
// );
// }

// #[test]
// fn parse_list_of_streamlets() {
// assert_eq!(
// list_of_streamlets(concat!(
// "Streamlet a ( a: in Null, b: out Null)\n",
// "/* A comment */\n",
// "Streamlet b ( a: in Null, b: out Null)\n",
// "/// Multi-line...\n",
// "/// doc string...\n",
// "Streamlet c ( a: in Null, b: out Null)",
// )),
// Ok((
// "",
// UniqueKeyBuilder::new()
// .with_items(vec![
// streamlets::nulls_streamlet("a"),
// streamlets::nulls_streamlet("b"),
// streamlets::nulls_streamlet("c").with_doc(" Multi-line...\n doc string..."),
// ])
// .finish()
// .unwrap()
// ))
// );
// }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are these tests disabled?

@johanpel
Copy link
Member Author

This is stale.

@johanpel johanpel closed this Feb 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request WIP: do not merge Work in progress, do not merge until tag is removed
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants