chipsalliance / chipsalliance/chisel

Provide a way to normalize directions to distinguish between module ports and child module instance ports

Open
#2,884 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Scala
Stars
4.8k
Forks
658
Avg merge
18h 59m
Merged PRs (30d)
14

Description

**Type of issue**: Feature Request

**Is your feature request related to a problem? Please describe.**

I write quite a lot of glue code, especially in top-level modules, connecting various compoenents with little logic in the top-level module. As a simple example:

```scala
class Foo extends Module {
val q = Module( new Queue(UInt(8.W), 16) )
val enq = IO(Flipped(DecoupledIO(UInt(8.W))))
val deq = IO(DecoupledIO(UInt(8.W)))
nq <> q.io.enq
q.io.deq <> deq
}
```

Now, there's a bit of boilerplate here. It could be easier to infer the ports:

```scala
object IOX {
def apply[T<:Data](x: T) = {
val io = chisel3.experimental.IO.apply( chiselTypeOf(x) )
io <> x
io
}
}
```

Now the previos code becomes:

```scala
class Foo extends Module {
val q = Module( new Queue(UInt(8.W), 16) )
val enq = IOX(q.io.enq)
val deq = IOX(q.io.deq)
}
```

Which is a nice improvement. This is espcially useful in the beginning of the project, when ports and types are in flux. It saves typing and prevents errors.

The problem is that this fails when trying to infer from a module port.

```scala
class Foo extends Module {
val enq = IO(Flipped(DecoupledIO(UInt(8.W))))
val deq = IOX( deq ) // FAIL: Both Left and Right are drivers
}
```

This happens because signal direction is the declared direction. This ignores the function of the of signal. A module input is a source, while an input of the child module instance is a sink. Similarly, a module output is a sink, while an output of a child module instance is a source.

**Describe the solution you'd like**

I'd like to have some way of normalizing directions that takes into account whether the element is a module input/output or a child module instance input/output. For example, something like `normalizedChiselTypeOf()` that could correctly normalize directions, to enable writing something like:

```scala
object IOX {
def apply[T<:Data](x: T) = {
val io = chisel3.experimental.IO.apply( normalizedChiselTypeOf(x) )
io <> x
io
}
}
```

**Describe alternatives you've considered**

Maybe some mechanism to check whether a chisel element is a module port, child instance port, or something else.

**Additional context**

Many netlist libraries (e.g. Verific) make the distinction between ports and pins. A port an I/O of the current module. A pin is a connection to an I/O of a child module instance.

Ports and pins has reversed direction. A module input becomes an output from the perspective of its parent module, and a module output becomes and input from the persepctive a parent module.

What I'm missing is a way to distinguish the two in Chisel.

**What is the use case for implementing this feature?**

See above. I can provide other example where this could be useful.

Contributor guide

Open the contributing guide

Research direction

Start by reproducing the IOX examples in the issue and examine how chisel3.experimental.IO, chiselTypeOf, and <> handle directions for module ports versus child-module ports. Determine where direction normalization would belong and define tests covering both cases, including the requested normalizedChiselTypeOf-style behavior. Done means the inferred IOX connections no longer report both sides as drivers.

Written by the indexing model from the issue text.

Assessment

Tech stack
scala
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.