Skip to content

Commit 67c7e12

Browse files
committed
Merge branch 'master' into 3.6-release
2 parents d1b65eb + 9f080d5 commit 67c7e12

16 files changed

+478
-32
lines changed

build.sbt

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,8 @@ val defaultVersions = Map(
1212
)
1313

1414
lazy val commonSettings = Seq(
15-
resolvers ++= Seq(
16-
Resolver.sonatypeRepo("snapshots"),
17-
Resolver.sonatypeRepo("releases")
18-
),
15+
resolvers ++= Resolver.sonatypeOssRepos("snapshots"),
16+
resolvers ++= Resolver.sonatypeOssRepos("releases"),
1917
organization := "edu.berkeley.cs",
2018
version := "3.6.0-M1",
2119
autoAPIMappings := true,
@@ -39,6 +37,7 @@ lazy val commonSettings = Seq(
3937
)
4038

4139
lazy val publishSettings = Seq(
40+
versionScheme := Some("pvp"),
4241
publishMavenStyle := true,
4342
Test / publishArtifact := false,
4443
pomIncludeRepository := { x => false },
@@ -71,9 +70,9 @@ lazy val publishSettings = Seq(
7170
lazy val chiselSettings = Seq(
7271
name := "chisel3",
7372
libraryDependencies ++= Seq(
74-
"org.scalatest" %% "scalatest" % "3.2.12" % "test",
73+
"org.scalatest" %% "scalatest" % "3.2.14" % "test",
7574
"org.scalatestplus" %% "scalacheck-1-14" % "3.2.2.0" % "test",
76-
"com.lihaoyi" %% "os-lib" % "0.8.1"
75+
"com.lihaoyi" %% "upickle" % "2.0.0"
7776
)
7877
) ++ (
7978
// Tests from other projects may still run concurrently
@@ -94,7 +93,7 @@ lazy val pluginScalaVersions = Seq(
9493
// scalamacros paradise version used is not published for 2.12.0 and 2.12.1
9594
"2.12.2",
9695
"2.12.3",
97-
"2.12.4",
96+
// 2.12.4 is broken in newer versions of Zinc: https://github.com/sbt/sbt/issues/6838
9897
"2.12.5",
9998
"2.12.6",
10099
"2.12.7",
@@ -118,7 +117,7 @@ lazy val pluginScalaVersions = Seq(
118117
"2.13.7",
119118
"2.13.8",
120119
"2.13.9",
121-
"2.13.10",
120+
"2.13.10"
122121
)
123122

124123
lazy val plugin = (project in file("plugin"))
@@ -174,6 +173,10 @@ lazy val core = (project in file("core"))
174173
.settings(mimaPreviousArtifacts := Set())
175174
.settings(
176175
name := "chisel3-core",
176+
libraryDependencies ++= Seq(
177+
"com.lihaoyi" %% "upickle" % "2.0.0",
178+
"com.lihaoyi" %% "os-lib" % "0.8.1"
179+
),
177180
scalacOptions := scalacOptions.value ++ Seq(
178181
"-deprecation",
179182
"-explaintypes",

build.sc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@ object v {
2626
val firrtl = getVersion("firrtl")
2727
val treadle = getVersion("treadle")
2828
val chiseltest = ivy"edu.berkeley.cs::chiseltest:0.6-SNAPSHOT"
29-
val scalatest = ivy"org.scalatest::scalatest:3.2.12"
29+
val scalatest = ivy"org.scalatest::scalatest:3.2.14"
3030
val scalacheck = ivy"org.scalatestplus::scalacheck-1-14:3.2.2.0"
3131
val osLib = ivy"com.lihaoyi::os-lib:0.8.1"
32+
val upickle = ivy"com.lihaoyi::upickle:2.0.0"
3233
val macroParadise = ivy"org.scalamacros:::paradise:2.1.1"
3334
}
3435

@@ -61,7 +62,8 @@ trait CommonModule extends CrossSbtModule with PublishModule with ScalafmtModule
6162
override def moduleDeps = super.moduleDeps ++ firrtlModule
6263

6364
override def ivyDeps = super.ivyDeps() ++ Agg(
64-
v.osLib
65+
v.osLib,
66+
v.upickle
6567
) ++ firrtlIvyDeps
6668

6769
def publishVersion = "3.6.0-M1"
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package chisel3.experimental
2+
3+
import upickle.default._
4+
5+
import scala.reflect.runtime.universe
6+
7+
/** Parameter for SerializableModule, it should be serializable via upickle API.
8+
* For more information, please refer to [[https://com-lihaoyi.github.io/upickle/]]
9+
*/
10+
trait SerializableModuleParameter
11+
12+
/** Mixin this trait to let chisel auto serialize module, it has these constraints:
13+
* 1. Module should not be any inner class of other class, since serializing outer class is impossible.
14+
* 2. Module should have and only have one parameter with type `T`:
15+
* {{{
16+
* class FooSerializableModule[FooSerializableModuleParameter](val parameter: FooSerializableModuleParameter)
17+
* }}}
18+
* 3. user should guarantee the module is reproducible on their own.
19+
*/
20+
trait SerializableModule[T <: SerializableModuleParameter] { this: BaseModule =>
21+
val parameter: T
22+
}
23+
object SerializableModuleGenerator {
24+
25+
/** serializer for SerializableModuleGenerator. */
26+
implicit def rw[P <: SerializableModuleParameter, M <: SerializableModule[P]](
27+
implicit rwP: ReadWriter[P],
28+
pTypeTag: universe.TypeTag[P],
29+
mTypeTag: universe.TypeTag[M]
30+
): ReadWriter[SerializableModuleGenerator[M, P]] = readwriter[ujson.Value].bimap[SerializableModuleGenerator[M, P]](
31+
{ (x: SerializableModuleGenerator[M, P]) =>
32+
ujson
33+
.Obj(
34+
"parameter" -> upickle.default.writeJs[P](x.parameter),
35+
"generator" -> x.generator.getName
36+
)
37+
},
38+
{ (json: ujson.Value) =>
39+
SerializableModuleGenerator[M, P](
40+
Class.forName(json.obj("generator").str).asInstanceOf[Class[M]],
41+
upickle.default.read[P](json.obj("parameter"))
42+
)
43+
}
44+
)
45+
}
46+
47+
/** the serializable module generator:
48+
* @param generator a non-inner class of module, which should be a subclass of [[SerializableModule]]
49+
* @param parameter the parameter of `generator`
50+
*/
51+
case class SerializableModuleGenerator[M <: SerializableModule[P], P <: SerializableModuleParameter](
52+
generator: Class[M],
53+
parameter: P
54+
)(
55+
implicit val pTag: universe.TypeTag[P],
56+
implicit val mTag: universe.TypeTag[M]) {
57+
private[chisel3] def construct: M = {
58+
require(
59+
generator.getConstructors.length == 1,
60+
s"""only allow constructing SerializableModule from SerializableModuleParameter via class Module(val parameter: Parameter),
61+
|you have ${generator.getConstructors.length} constructors
62+
|""".stripMargin
63+
)
64+
require(
65+
!generator.getConstructors.head.getParameterTypes.last.toString.contains("$"),
66+
s"""You define your ${generator.getConstructors.head.getParameterTypes.last} inside other class.
67+
|This is a forbidden behavior, since we cannot serialize the out classes,
68+
|for debugging, these are full parameter types of constructor:
69+
|${generator.getConstructors.head.getParameterTypes.mkString("\n")}
70+
|""".stripMargin
71+
)
72+
require(
73+
generator.getConstructors.head.getParameterCount == 1,
74+
s"""You define multiple constructors:
75+
|${generator.getConstructors.head.getParameterTypes.mkString("\n")}
76+
|""".stripMargin
77+
)
78+
generator.getConstructors.head.newInstance(parameter).asInstanceOf[M]
79+
}
80+
81+
/** elaborate a module from this generator. */
82+
def module(): M = construct
83+
}

docs/src/appendix/chisel3-vs-chisel2.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ section: "chisel3"
99
import chisel3._
1010
```
1111

12+
**Note** Chisel2 Compatibility Mode is entirely deprecated in 3.6, so this entire page is relevant only for 3.6 and earlier.
13+
1214
## Chisel2 Migration
1315
For those moving from Chisel2, there were some backwards incompatible changes
1416
and your RTL needs to be modified to work with Chisel3. The required

docs/src/cookbooks/serialization.md

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
---
2+
layout: docs
3+
title: "Serialization Cookbook"
4+
section: "chisel3"
5+
---
6+
7+
# Serialization Cookbook
8+
9+
* [Why do I need to serialize Modules](#why-do-i-need-to-serialize-modules)
10+
* [How do I serialize Modules with SerializableModuleGenerator](#how-do-i-seerialize-modules-with-serializablemodulegenerator)
11+
12+
## Why do I need to serialize Modules
13+
Chisel provides a very flexible hardware design experience. However, it sometimes becomes too flexible to design a relative big designs, since parameters of module might come from: 1. Global variables; 2. Outer class; 3. Entropies(time, random). It becomes really hard or impossible to describe "how to reproduce this single module?". This forbids doing unit-test for a module generator, and introduces issues in post-synthesis when doing ECO: a change to Module A might lead to change in Module B.
14+
Thus `SerializableModuleGenerator`, `SerializableModule[T <: SerializableModuleParameter]` and `SerializableModuleParameter` are provided to solve these issues.
15+
For any `SerializableModuleGenerator`, Chisel can automatically serialize and de-serialize it by adding these constraints:
16+
1. the `SerializableModule` should not be inner class, since the outer class is a parameter to it;
17+
1. the `SerializableModule` has and only has one parameter with `SerializableModuleParameter` as its type.
18+
1. the Module neither depends on global variables nor uses non-reproducible functions(random, time, etc), and this should be guaranteed by user, since Scala cannot detect it.
19+
20+
It can provide these benefits:
21+
1. user can use `SerializableModuleGenerator(module: class[SerializableModule], parameter: SerializableModuleParameter)` to auto serialize a Module and its parameter.
22+
1. user can nest `SerializableModuleGenerator` in other serializable parameters to represent a relative large parameter.
23+
1. user can elaborate any `SerializableModuleGenerator` into a single module for testing.
24+
25+
26+
## How do I serialize Modules with `SerializableModuleGenerator`
27+
It is pretty simple and illustrated by example below, the `GCD` Module with `width` as its parameter.
28+
29+
```scala mdoc:silent
30+
import chisel3._
31+
import chisel3.experimental.{SerializableModule, SerializableModuleGenerator, SerializableModuleParameter}
32+
import upickle.default._
33+
34+
// provide serialization functions to GCDSerializableModuleParameter
35+
object GCDSerializableModuleParameter {
36+
implicit def rwP: ReadWriter[GCDSerializableModuleParameter] = macroRW
37+
}
38+
39+
// Parameter
40+
case class GCDSerializableModuleParameter(width: Int) extends SerializableModuleParameter
41+
42+
// Module
43+
class GCDSerializableModule(val parameter: GCDSerializableModuleParameter)
44+
extends Module
45+
with SerializableModule[GCDSerializableModuleParameter] {
46+
val io = IO(new Bundle {
47+
val a = Input(UInt(parameter.width.W))
48+
val b = Input(UInt(parameter.width.W))
49+
val e = Input(Bool())
50+
val z = Output(UInt(parameter.width.W))
51+
})
52+
val x = Reg(UInt(parameter.width.W))
53+
val y = Reg(UInt(parameter.width.W))
54+
val z = Reg(UInt(parameter.width.W))
55+
val e = Reg(Bool())
56+
when(e) {
57+
x := io.a
58+
y := io.b
59+
z := 0.U
60+
}
61+
when(x =/= y) {
62+
when(x > y) {
63+
x := x - y
64+
}.otherwise {
65+
y := y - x
66+
}
67+
}.otherwise {
68+
z := x
69+
}
70+
io.z := z
71+
}
72+
```
73+
using `write` function in `upickle`, it should return a json string:
74+
```scala mdoc
75+
val j = upickle.default.write(
76+
SerializableModuleGenerator(
77+
classOf[GCDSerializableModule],
78+
GCDSerializableModuleParameter(32)
79+
)
80+
)
81+
```
82+
83+
You can then read from json string and elaborate the Module:
84+
```scala mdoc:compile-only
85+
chisel3.stage.ChiselStage.emitVerilog(
86+
upickle.default.read[SerializableModuleGenerator[GCDSerializableModule, GCDSerializableModuleParameter]](
87+
ujson.read(j)
88+
).module()
89+
)

project/build.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
sbt.version=1.5.8
1+
sbt.version=1.8.0

project/plugins.sbt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@ addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.15")
1818

1919
addSbtPlugin("com.thoughtworks.sbt-api-mappings" % "sbt-api-mappings" % "3.0.2")
2020

21-
addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.3.2")
21+
addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.3.6")
2222

2323
addSbtPlugin("com.eed3si9n" % "sbt-sriracha" % "0.1.0")
2424

25-
addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "1.1.0")
25+
addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "1.1.1")
2626

27-
addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.5.10")
27+
addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.5.11")
2828

29-
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.6")
29+
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.0")
3030

3131
// From FIRRTL for building from source
3232
addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.33")

0 commit comments

Comments
 (0)