Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/sifive/duh-scala

⛏️ DUH component export to Scala
https://github.com/sifive/duh-scala

duh hacktoberfest

Last synced: 3 months ago
JSON representation

⛏️ DUH component export to Scala

Awesome Lists containing this project

README

        

[![NPM version](https://img.shields.io/npm/v/duh-scala.svg)](https://www.npmjs.org/package/duh-scala)
[![Actions Status](https://github.com/sifive/duh-scala/workflows/Tests/badge.svg)](https://github.com/sifive/duh-scala/actions)

DUH component export to Scala

## Installation
```
npm i duh-scala
```

### Exporting a blackbox wrapper and `attach` method
This is a scala `LazyModule` that has diplomatic nodes corresponding to the bus
interfaces of the duh component.
```bash
duh-export-scala .json5 -o
```

### Exporting a `RegisterRouter`
`duh-export-regmap` will export a `RegisterRouter` corresponding the the
`memoryMap`s in a duh component. A `RegisterRouter` is an abstract Scala
description of memory-mapped registers that is generic to any bus interface.
Concrete implementations for TileLink and AXI4 are included in the generated
Scala.
```bash
duh-export-regmap .json5 -o
```

### Exporting a monitor wrapper and `attach` method
This is a special kind of chisel `Module` that can be attached to diplomatic
edges corresponding to the monitor's bus interface type.
```bash
duh-export-monitor .json5 -o
```

## Blackbox wrapper API
This section describes the API of the blackbox wrapper generated by
`duh-export-scala`. The hierarchy of the output modules is looks like
```
top: N${name}Top
└── imp: L${name}
└── blackbox: ${name}
```
The reason for having two layers of wrapping is to separate the purely
combinational wrapper logic from the sequential logic. The inner `L${name}`
module only contains combinational wrapper logic while the outer `N${name}Top`
module contains sequential logic

The `L${name}` module contains the node declarations, blackbox instantiation,
and connections between node bundles and blackbox ports. There is also an
`extraResources` method that is called when the DTS data structure is
constructed. The fields returned by this method are included in the entry
corresponding the component in the DTS.
```scala
class L${name}Base(c: ${name}Params)(implicit p: Parameters) extends LazyModule {

// device declaration
val device = new SimpleDevice("${name}", Seq("sifive,${name}-${version}")) {
...
}

// extra fields to include in the entry of this device in the DTS
def extraResources(resources: ResourceBindings) = Map[String, Seq[ResourceValue]]()

// node declarations
val axiNode = ...
val apbNode = ...
...

// blackbox instantiation and wiring
lazy val module = new L${name}BaseImp
}
```

The corresponding user class that extends `L${name}Base` looks like
```scala
class L${name}(c: ${name}Params)(implicit p: Parameters) extends L${name}Base(c)(p)
{

// User code here

}
```

To add another integer field called `data-width` and string field called `name`
you would add the following code into the user `L${name}` class.
```scala
override def extraResources(resources: ResourceBindings) =
Map("data-width" -> Seq(ResourceInt(dataWidth)),
"name" -> Seq(ResourceString(name)))
```

The result should look like
```scala
class L${name}(c: ${name}Params)(implicit p: Parameters) extends L${name}Base(c)(p)
{
override def extraResources(resources: ResourceBindings) =
Map("data-width" -> Seq(ResourceInt(dataWidth)),
"name" -> Seq(ResourceString(name)))
}
```

The `N${name}` module contains methods to instantate TileLink adapters for the
nodes. It also contains a method called `userOM` that is called when the object
model of the component is constructed. The object returned by `userOM` is
included with the base object model. This can be overrided to include arbitrary
information in the object model and defaults to empty. The value returned by
this method should be an instance of a `case class` which is why it returns
`Product with Serializable`.
```scala
class N${name}TopBase(val c: N${name}TopParams)(implicit p: Parameters) extends SimpleLazyModule
with BindingScope {

// userOM method
def userOM: Product with Serializable = Nil

// adapter methods
def getaxilNodeTLAdapter(): TLInwardNode = ...
def getahblNodeTLAdapter(): TLInwardNode = ...
...
}
```

The corresponding user class that extends `N${name}Base` looks like
```scala
class N${name}Top(c: N${name}TopParams)(implicit p: Parameters) extends N${name}TopBase(c)(p)
{

// User code here

}
```

To add the following fields to the `OMDevice` of the component
```javascript
foo: "foo",
foobar: {
foo: "foo",
bar: "bar"
}
```

add the following code to the user `N${name}` by defining the following case class
```
case class MyOM(foo: String, foobar: Map[String, String])
```

and add the following code to `N${name}`
```scala
override def userOM = new MyOM("foo", Map("foo" -> "foo", "bar" -> "bar"))
```

The result should look like
```scala
class N${name}Top(c: N${name}TopParams)(implicit p: Parameters) extends N${name}TopBase(c)(p)
{
override def userOM = new MyOM("foo", Map("foo" -> "foo", "bar" -> "bar"))
}
```

And the output object model should look like
```javascript
{
"foo" : {
"foo" : "foo",
"bar" : "bar"
},
"memoryRegions" : [ ... ],
"interrupts" : [ ... ],
"_types" : [ "OM${name}", "OMDevice", "OMComponent", "OMCompoundType" ]
}
```

## Testing
```
npm test
```

## License
Apache 2.0 [LICENSE](LICENSE).