diff --git a/doc/bootcamp/bootcamp-20130930.tex b/doc/bootcamp/bootcamp-20130930.tex index a2de19eb..ffddba81 100644 --- a/doc/bootcamp/bootcamp-20130930.tex +++ b/doc/bootcamp/bootcamp-20130930.tex @@ -8,7 +8,7 @@ \input{../style/scala.tex} \input{../style/talk.tex} -\title{Chisel Bootcamp} +\title{Chisel Bootcamp 3} \author{Jonathan Bachrach} \date{\today} \institute[UC Berkeley]{EECS UC Berkeley} diff --git a/doc/bootcamp/bootcamp-20140206.tex b/doc/bootcamp/bootcamp-20140206.tex index 0a6b1eec..0f44891c 100644 --- a/doc/bootcamp/bootcamp-20140206.tex +++ b/doc/bootcamp/bootcamp-20140206.tex @@ -8,7 +8,7 @@ \input{../style/scala.tex} \input{../style/talk.tex} -\title{Chisel Bootcamp} +\title{Chisel Bootcamp 4} \author{Jonathan Bachrach} \date{\today} \institute[UC Berkeley]{EECS UC Berkeley} @@ -45,7 +45,7 @@ \begin{frame}[fragile]{Goals for Bootcamp} \begin{itemize} -\item get yout started with Chisel +\item get you started with Chisel \item get a basic working knowledge of Chisel \item learn how to think in Chisel \item know where to get more information @@ -53,6 +53,23 @@ \end{frame} +\begin{frame}[fragile]{CS291C Specific Notes for Bootcamp} + +\begin{itemize} +\item teaching digital circuit design in chisel +\item will later teach +\begin{itemize} +\item floating point +\item fixed point +\item complex numbers +\item integration with matlab +\end{itemize} +\item new chisel release with DSP support coming soon +\end{itemize} + +\end{frame} + + \setbeamercolor{frametitle}{bg=\frametitleproblemcolor} \begin{frame}[fragile]{Logging into EC2} @@ -86,7 +103,7 @@ if you don't have chisel-tutorial already \begin{scala} -git clone git@github.com:ucb-bar/chisel-tutorial.git +git clone https://github.com/ucb-bar/chisel-tutorial.git cd chisel-tutorial \end{scala} @@ -123,7 +140,7 @@ \begin{center} \fbox{ -\url{chisel.eecs.berkeley.edu/bootcamp-20140206.pdf} +\url{chisel.eecs.berkeley.edu/2.0.6/chisel-bootcamp-20140206.pdf} } \end{center} @@ -783,7 +800,7 @@ } .elsewhen (io.opcode === UInt(2)) { io.output := io.a + UInt(1) // inc A by 1 } .elsewhen (io.opcode === UInt(3)) { - io.output := io.a - UInt(1) // inc B by 1 + io.output := io.a - UInt(1) // dec B by 1 } .elsewhen (io.opcode === UInt(4)) { io.output := io.a + UInt(4) // inc A by 4 } .elsewhen (io.opcode === UInt(5)) { @@ -826,7 +843,7 @@ \verb+^+ & Bitwise XOR & UInt\\ \hline \verb+&+ & Bitwise AND & UInt \\ \hline \verb+|+ & Bitwise OR & Bool \\ \hline -\verb+===+ & Equal & Bool \\ \hline +{\color{red}\verb+===+} & Equal & Bool \\ \hline \verb+!=+ & Not Equal & Bool \\ \hline \verb+>+ & Greater & Bool \\ \hline \verb+<+ & Less & Bool \\ \hline @@ -978,10 +995,10 @@ wire[15:0] T1; assign io_Lo = T0; - assign T0 = mult[4'hf/*15*/:1'h0/*0*/]; + assign T0 = mult[4'hf:1'h0]; assign mult = io_A * io_B; assign io_Hi = T1; - assign T1 = mult[5'h1f/*31*/:5'h10/*16*/]; + assign T1 = mult[5'h1f:5'h10]; endmodule \end{scala} } @@ -1215,7 +1232,7 @@ val out = UInt(OUTPUT, 1) } val delays = Vec.fill(4){ Reg(UInt()) } - when ( ...) { + when ( ... ) { // fill in here ... } .elsewhen (io.shift) { ... @@ -1362,7 +1379,7 @@ \setbeamercolor{frametitle}{bg=\frametitleproblemcolor} \begin{frame}[fragile]{Testbench for MaxN -- \tt MaxN.scala} \begin{columns} -\column{0.48\textwidth} +\column{0.49\textwidth} \begin{itemize} \item write a testbench for MaxN @@ -1389,7 +1406,7 @@ val x = rnd.nextInt(lim) \end{scala} -\column{0.43\textwidth} +\column{0.42\textwidth} {\lstset{basicstyle={\scriptsize\ttfamily}} \begin{scala} @@ -1433,7 +1450,7 @@ val list = Vec(UInt(0), UInt(4), UInt(15), UInt(14), UInt(2), UInt(5), UInt(13)){ UInt(width = 4) } val memVal = list(index) - val done = !io.en && ((memVal === io.target) || (index === UInt(7))) + val done = !io.en && ((memVal === io.target) || (index === UInt(7))) when (io.en) { index := UInt(0) } .elsewhen (done === Bool(false)) { @@ -1514,8 +1531,7 @@ \end{itemize} \begin{scala} -al ram1r1w = - Mem(UInt(width = 32), 1024, seqRead = true) +val ram1r1w = Mem(UInt(width = 32), 1024, seqRead = true) val reg_raddr = Reg(UInt()) when (wen) { ram1r1w(waddr) := wdata } when (ren) { reg_raddr := raddr } @@ -1880,7 +1896,34 @@ for example, you can create a parallel set of blocks using map and reduce to creation reduction trees and chain to create a pipeline.} \end{frame} -\begin{frame}[fragile]{Map / Reduce Generator} +\begin{frame}[fragile]{Flo Map / Reduce Generator} + +{\lstset{basicstyle={\scriptsize\ttfamily}} +\begin{scala} +object FloDelays { + def apply(x: Flo, n: Int): List[Flo] = + if (n <= 1) List(x) else x :: FloDelays(RegNext(x), n-1) +} +object FloFIR { + def apply(ws: Seq[Flo], x: T): T = + (ws, FloDelays(x, ws.length)).zipped.map( _ * _ ).reduce( _ + _ ) +} +class FIR extends Module { + val io = new Bundle { val x = Flo(INPUT); val z = Flo(OUTPUT) } + val ws = Array(Flo(0.25), Flo(0.75)) + io.z := FloFIR(ws, io.x) +} +\end{scala} +} +\begin{center} +\includegraphics[height=0.35\textheight]{../cs294-88/lectures/advanced-chisel/figs/inner-product-fir.png} +\end{center} +\note{as an advanced example, consider writing an FIR filter which is defined by the equation below. \\[1cm] +essentially it's a sum of products of coefficients and delayed versions of input.\\[1cm] +we can write this quite simply using map and reduce as above.} +\end{frame} + +\begin{frame}[fragile]{Generic Map / Reduce Generator} {\lstset{basicstyle={\scriptsize\ttfamily}} \begin{scala} @@ -2223,7 +2266,6 @@ \begin{tabular}{rl} \textbf{manual} & \code{manual.pdf} \\ \textbf{bootcamp2014} & \code{bootcamp-20140206.pdf} \\ -\textbf{bootcamp2013} & \code{bootcamp-20130930.pdf} \\ \textbf{bootcamp2012} & \code{bootcamp-20121026.pdf} \\ \textbf{tutorial} & \code{tutorial.pdf} \\ \textbf{getting started} & \code{getting-started.pdf} \\ @@ -2287,8 +2329,8 @@ \begin{frame}{Thanks} \begin{itemize} -\item \textbf{Arrangements} -- Roxana and Kostas -\item \textbf{EC2 configuration} -- Sebastien Mirolo +\item \textbf{Arrangements} -- Borivoje Nikolic +\item \textbf{Educational Machines} -- Michael Zimmer \item \textbf{Bootcamp Materials} -- Vincent Lee, Stephen Twigg, Huy Vo \item \textbf{Funding} -- Department of Energy, Department of Defense \end{itemize} diff --git a/doc/bootcamp/bootcamp.tex b/doc/bootcamp/bootcamp.tex index 02eb4311..cf83532e 100644 --- a/doc/bootcamp/bootcamp.tex +++ b/doc/bootcamp/bootcamp.tex @@ -8,7 +8,7 @@ \input{../style/scala.tex} \input{../style/talk.tex} -\title{Chisel Bootcamp} +\title{Chisel Bootcamp 2} \author{Jonathan Bachrach} \date{\today} \institute[UC Berkeley]{EECS UC Berkeley} diff --git a/doc/bootcamp/scala-intro.tex b/doc/bootcamp/scala-intro.tex index 822d2937..c54e6f70 100644 --- a/doc/bootcamp/scala-intro.tex +++ b/doc/bootcamp/scala-intro.tex @@ -31,11 +31,36 @@ val a :: b :: c :: Nil = els val m = els.length +// Tuple's +val (x, y, z) = (1, 2, 3) +\end{scala} +\end{frame} + +\begin{frame}[fragile]{Scala Maps and Sets} +\begin{scala} +import scala.collection.mutable.HashMap + +val vars = new HashMap[String, Int]() +vars("a") = 1 +vars("b") = 2 +vars.size +vars.contains("c") +vars.getOrElse("c", -1) +vars.keys +vars.values +\end{scala} + +\begin{scala} +import scala.collection.mutable.HashSet + +val keys = new HashSet[Int]() +keys += 1 +keys += 5 +keys.size -> 2 +keys.contains(2) -> false \end{scala} \end{frame} -% // Tuple's -% val (x, y, z) = (1, 2, 3) \begin{frame}[fragile]{Scala Iteration} @@ -50,6 +75,10 @@ val tbl2 = new ArrayBuffer[Int] for (e <- tbl) tbl2 += 2*e + +// loop over hashmap key / values +for ((x, y) <- vars) + println("K " + x + " V " + y) \end{scala} % // create second table with doubled elements diff --git a/doc/getting-started/modules-guts.tex b/doc/getting-started/modules-guts.tex index c4a4350c..2d0ffd04 100644 --- a/doc/getting-started/modules-guts.tex +++ b/doc/getting-started/modules-guts.tex @@ -178,18 +178,23 @@ \subsection{The Mux Class} val out = Mux(select, A, B) \end{scala} -Thus if \verb+A=10+, \verb+B=14+, and \verb+select+ was \verb+true+, the value of \verb+out+ would be assigned 10. Notice how using the \verb+Mux+ primitive type abstracts away the logic structures required if we had wanted to implement the multiplexor explicitly. The instantiation would look something like this: +Thus if \verb+A=10+, \verb+B=14+, and \verb+select+ was \verb+true+, the value of \verb+out+ would be assigned 10. Notice how using the \verb+Mux+ primitive type abstracts away the logic structures required if we had wanted to implement the multiplexor explicitly. -\begin{scala} -// where n is the width of A and m is the width of B -val mux = Module(new Mux(n, m)) -mux.io.select := select -mux.io.A := A -mux.io.B := B -val out = mux.io.out -\end{scala} +% Martin: I would drop the following as it is just confusing in a tutorial +% state simple that there is a Mux primitive and that is fine. -We see that clearly it is much cleaner to use the primitive \verb+Mux+ type instead of trying to write and implement our own general multiplexor since the \verb+Mux+ type does all the wiring for you. +%The instantiation would look something like this: +% +%\begin{scala} +%// where n is the width of A and m is the width of B +%val mux = Module(new Mux(n, m)) +%mux.io.select := select +%mux.io.A := A +%mux.io.B := B +%val out = mux.io.out +%\end{scala} +% +%We see that clearly it is much cleaner to use the primitive \verb+Mux+ type instead of trying to write and implement our own general multiplexor since the \verb+Mux+ type does all the wiring for you. %\section{Exercises} diff --git a/doc/getting-started/state-guts.tex b/doc/getting-started/state-guts.tex index 63976af8..eef7e3ae 100644 --- a/doc/getting-started/state-guts.tex +++ b/doc/getting-started/state-guts.tex @@ -79,6 +79,9 @@ \subsection{The .otherwise Clause} \subsection{The unless Clause} +% Martin: this feels a little bit strange as it is not a usual construct in a programming language. +% It is simple !condition, right? So I would drop it. + To complement the \verb+when+ statement, Chisel also supports an \verb+unless+ statement. The \verb+unless+ statement is a conditional assignment that triggers only if the condition is false. The general structure for the \verb+unless+ statement is: \begin{scala} @@ -193,6 +196,8 @@ \subsection{Synchronous vs. Combinational Read} val syncMem = Mem(UInt(width = 32), 128, seqRead = true) \end{scala} +% this needs more elaboration. Memories in hardware are tough... + By default, Chisel will assume that the read behavior is combinational. \subsection{Adding Write Ports} @@ -269,7 +274,10 @@ \subsubsection{Synchronous Read Ports} \subsection{Example of Mem in Action} -We introduced a basic stack pointer bookkeeping example earlier in the tutorial. In this section we show how the complete stack implementation would look like. +% Martin: no, it was not yet shown +%We introduced a basic stack pointer bookkeeping example earlier in the tutorial. In this section we show how the complete stack implementation would look like. + +Here we provide a small example of using a memory by implementing a stack. Suppose we would like to implement a stack that takes two signals \verb+push+ and \verb+pop+ where \verb+push+ tells the stack to push an input \verb+dataIn+ to the top of the stack, and \verb+pop+ tells the stack to pop off the top value from the stack. Furthermore, an enable signal \verb+en+ disables pushing or popping if not asserted. Finally, the stack should always output the top value of the stack. diff --git a/doc/talks/microsoft/libs-to-langs-guts-in-scala.tex b/doc/talks/microsoft/libs-to-langs-guts-in-scala.tex index 3f5933be..2277dc66 100644 --- a/doc/talks/microsoft/libs-to-langs-guts-in-scala.tex +++ b/doc/talks/microsoft/libs-to-langs-guts-in-scala.tex @@ -32,7 +32,7 @@ \end{itemize} \noindent -and \verb+new+ used to construct components and connect used to wire them together: +and \verb+new+ used to construct components and \verb+connect+ used to wire them together: \begin{itemize} \item \verb+new Register()+ \item ... @@ -47,7 +47,7 @@ \column{0.50\textwidth} {\lstset{basicstyle={\tiny\ttfamily}} \begin{scala} -def main (): Int = { +def main(args: Array[String]) = { // Create Components val reset = new Wire("reset"); val counter = new Register("counter"); @@ -82,7 +82,7 @@ \column{0.50\textwidth} {\lstset{basicstyle={\tiny\ttfamily}} \begin{scala} -def main (): Int = { +def main(args: Array[String]) = { // Create Components val reset = new Wire("reset"); val counter = new Register("counter"); @@ -121,7 +121,7 @@ \column{0.50\textwidth} {\lstset{basicstyle={\tiny\ttfamily}} \begin{scala} -def main (): Int = { +def main(args: Array[String]) = { // Create Components val reset = new Wire("reset"); val counter = new Register("counter"); @@ -159,7 +159,7 @@ \column{0.4\textwidth} {\lstset{basicstyle={\tiny\ttfamily}} \begin{scala} -def main (): Int = { +def main(args: Array[String]) = { // Create Components val reset = new Wire("reset"); val counter = new Register("counter"); @@ -190,7 +190,7 @@ {\lstset{basicstyle={\tiny\ttfamily}} \begin{scala} -def main (): Int = { +def main(args: Array[String]) = { // Create Components val reset = new Wire("reset"); val counter = new Register("counter"); @@ -219,7 +219,7 @@ \column{0.4\textwidth} {\lstset{basicstyle={\tiny\ttfamily}} \begin{scala} -def main (): Int = { +def main(args: Array[String]) = { // Create Components val reset = new Wire("reset"); val counter = new Register("counter"); @@ -246,7 +246,7 @@ \column{0.4\textwidth} {\lstset{basicstyle={\tiny\ttfamily}} \begin{scala} -def main (): Int = { +def main(args: Array[String]) = { // Create Components val reset = new Wire("reset"); val counter = new Register("counter"); @@ -273,7 +273,7 @@ \column{0.4\textwidth} {\lstset{basicstyle={\tiny\ttfamily}} \begin{scala} -def main (): Int = { +def main(args: Array[String]) = { // Create Components val reset = new Wire("reset"); val counter = new Register("counter"); @@ -298,7 +298,7 @@ \column{0.4\textwidth} {\lstset{basicstyle={\tiny\ttfamily}} \begin{scala} -def main (): Int = { +def main(args: Array[String]) = { // Create Components val reset = new Wire("reset"); val counter = new Register("counter"); @@ -323,7 +323,7 @@ \column{0.4\textwidth} {\lstset{basicstyle={\tiny\ttfamily}} \begin{scala} -def main (): Int = { +def main(args: Array[String]) = { // Create Components val reset = new Wire("reset"); val counter = new Register("counter"); @@ -346,7 +346,7 @@ \column{0.4\textwidth} {\lstset{basicstyle={\tiny\ttfamily}} \begin{scala} -def main (): Int = { +def main(args: Array[String]) = { // Create Components val reset = new Wire("reset"); val counter = new Register("counter"); @@ -371,7 +371,7 @@ \column{0.4\textwidth} {\lstset{basicstyle={\tiny\ttfamily}} \begin{scala} -def main (): Int = { +def main(args: Array[String]) = { // Create Components val reset = new Wire("reset"); val counter = new Register("counter"); @@ -394,7 +394,7 @@ \column{0.4\textwidth} {\lstset{basicstyle={\tiny\ttfamily}} \begin{scala} -def main (): Int = { +def main(args: Array[String]) = { // Create Components val reset = new Wire("reset"); val counter = new Register("counter"); @@ -419,7 +419,7 @@ \column{0.4\textwidth} {\lstset{basicstyle={\tiny\ttfamily}} \begin{scala} -def main (): Int = { +def main(args: Array[String]) = { // Create Components val reset = new Wire("reset"); val counter = new Register("counter"); @@ -442,7 +442,7 @@ \column{0.4\textwidth} {\lstset{basicstyle={\tiny\ttfamily}} \begin{scala} -def main (): Int = { +def main(args: Array[String]) = { // Create Components val reset = new Wire("reset"); val counter = new Register("counter"); @@ -468,7 +468,7 @@ \column{0.4\textwidth} {\lstset{basicstyle={\tiny\ttfamily}} \begin{scala} -def main (): Int = { +def main(args: Array[String]) = { // Create Components val reset = new Wire("reset"); val counter = new Register("counter"); @@ -492,7 +492,7 @@ \column{0.4\textwidth} {\lstset{basicstyle={\tiny\ttfamily}} \begin{scala} -def main (): Int = { +def main(args: Array[String]) = { // Create Components val reset = new Wire(); val counter = new Register(); @@ -518,7 +518,7 @@ \column{0.4\textwidth} {\lstset{basicstyle={\tiny\ttfamily}} \begin{scala} -def main (): Int = { +def main(args: Array[String]) = { // Create Components val reset = new Wire(); val counter = new Register(); @@ -552,7 +552,7 @@ counter } -def main (): Int = { +def main(args: Array[String]) = { // Create Components val reset = new Wire(); val counter = make_counter(reset); @@ -581,7 +581,7 @@ counter } -def main (): Int = { +def main(args: Array[String]) = { // Create Components val reset = new Wire(); val counter = make_counter(reset); @@ -608,7 +608,7 @@ counter } -def main (): Int = { +def main(args: Array[String]) = { // Create Components val reset = new Wire(); val counter = @@ -639,7 +639,7 @@ counter } -def main (): Int = { +def main(args: Array[String]) = { // Create Components val reset = new Wire(); val counter = diff --git a/src/main/scala/Backend.scala b/src/main/scala/Backend.scala index 2a4cca05..cf3e90b8 100644 --- a/src/main/scala/Backend.scala +++ b/src/main/scala/Backend.scala @@ -102,7 +102,7 @@ abstract class Backend { def nameChildren(root: Module) { // Name all nodes at this level - root.io.nameIt("io"); + root.io.nameIt("io", true); val nameSpace = new HashSet[String]; /* We are going through all declarations, which can return Nodes, ArrayBuffer[Node], Cell, BlackBox and Modules. @@ -120,7 +120,7 @@ abstract class Backend { /* XXX It seems to always be true. How can name be empty? */ if ((node.isTypeNode || name != "" || node.name == null || (node.name == "" && !node.named))) { - node.nameIt(asValidName(name)); + node.nameIt(asValidName(name), false); } nameSpace += node.name; } @@ -140,7 +140,7 @@ abstract class Backend { this has for side-effect to create modules with the exact same logic but textually different in input/output parameters, hence generating unnecessary modules. */ - elm.nameIt(asValidName(name + "_" + i)); + elm.nameIt(asValidName(name + "_" + i), false); } nameSpace += elm.name; i += 1; @@ -162,7 +162,7 @@ abstract class Backend { this has for side-effect to create modules with the exact same logic but textually different in input/output parameters, hence generating unnecessary modules. */ - elm.nameIt(asValidName(name + "_" + i)); + elm.nameIt(asValidName(name + "_" + i), false); } nameSpace += elm.name; i += 1; @@ -334,6 +334,11 @@ abstract class Backend { passed as input to sub-module without being tied to an output of *this.component*. */ + def isBitsIo(node: Node, dir: IODirection): Boolean = node match { + case b: Bits => b.isIo && b.dir == dir + case _ => false + } + def collectNodesIntoComp(dfsStack: Stack[Node]) { val walked = new HashSet[Node]() walked ++= dfsStack @@ -357,6 +362,10 @@ abstract class Backend { if (!node.component.nodes.contains(node)) node.component.nodes += node for (input <- node.inputs) { + if (input.component != null && input.component != node.component) { + if (!input.isLit && !isBitsIo(node, INPUT) && !isBitsIo(input, OUTPUT)) + ChiselErrors += new ChiselError(() => { "Illegal cross module reference between " + node + " and " + input}, node.line) + } if(!walked.contains(input)) { if( input.component == null ) { input.component = curComp @@ -376,6 +385,8 @@ abstract class Backend { } def pruneUnconnectedIOs(m: Module) { + m.checkIo // make sure all module ios are ports + val inputs = m.io.flatten.filter(_._2.dir == INPUT) val outputs = m.io.flatten.filter(_._2.dir == OUTPUT) @@ -397,7 +408,7 @@ abstract class Backend { if (o.inputs.length == 0) { if (o.consumers.length > 0) { if (Module.warnOutputs) - ChiselError.warning({"UNCONNETED OUTPUT " + emitRef(o) + " in component " + o.component + + ChiselError.warning({"UNCONNECTED OUTPUT " + emitRef(o) + " in component " + o.component + " has consumers on line " + o.consumers(0).line}) o.driveRand = true } else { diff --git a/src/main/scala/Bits.scala b/src/main/scala/Bits.scala index 5fcfa00c..40d33a74 100644 --- a/src/main/scala/Bits.scala +++ b/src/main/scala/Bits.scala @@ -54,6 +54,7 @@ abstract class Bits extends Data with proc { var canBeUsedAsDefault = false var dir: IODirection = null; + var isModuleIo = false def create(dir: IODirection, width: Int) { this.dir = dir; @@ -90,15 +91,27 @@ abstract class Bits extends Data with proc { else super.litOf // internal, non user exposed connectors - var assigned = false; - - override def assign(src: Node): Unit = + def checkAssign(src: Node): Unit = { + if (this.component != null) this.component.checkIo + if (this.dir == INPUT && this.component == Module.current && this.isModuleIo) { + ChiselError.error({"assigning to your own input port " + this + " RHS: " + src}); + } + if (this.dir == OUTPUT && this.component != Module.current && + src.component != null && src.component.parent != this.component) { + ChiselError.error({"assigning to a non parent module's output port: " + this + " RHS: " + src}); + } + } + override def assign(src: Node): Unit = { + checkAssign(src) if (inputs.isEmpty) inputs += src else ChiselError.error({"reassignment to Wire " + this + " with inputs " + this.inputs(0) + " RHS: " + src}); + } - override def procAssign(src: Node): Unit = + override def procAssign(src: Node): Unit = { + checkAssign(src) if (inputs.isEmpty) updates += ((Module.current.whenCond, src)) else ChiselError.error({"reassignment to Wire " + this + " with inputs " + this.inputs(0) + " RHS: " + src}); + } //code generation stuff diff --git a/src/main/scala/Bundle.scala b/src/main/scala/Bundle.scala index 66ebf79f..ca800cdb 100644 --- a/src/main/scala/Bundle.scala +++ b/src/main/scala/Bundle.scala @@ -154,14 +154,14 @@ class Bundle(view_arg: Seq[String] = null) extends CompositeData { elementsCache = elts; this } - override def nameIt (path: String) { + override def nameIt (path: String, isNamingIo: Boolean) { if( !named && (name.isEmpty || (!path.isEmpty && name != path)) ) { name = path val prefix = if (name.length > 0) name + "_" else "" for ((n, i) <- elements) { - i.nameIt(prefix + n) + i.nameIt(prefix + n, isNamingIo) } } else { /* We are trying to rename a Bundle that has a fixed name. */ diff --git a/src/main/scala/Data.scala b/src/main/scala/Data.scala index d2dd20d0..b37b7ecd 100644 --- a/src/main/scala/Data.scala +++ b/src/main/scala/Data.scala @@ -135,11 +135,11 @@ abstract class Data extends Node { } } - override def nameIt(path: String) { + override def nameIt(path: String, isNamingIo: Boolean) { if (isTypeNode && comp != null) { - comp.nameIt(path) + comp.nameIt(path, isNamingIo) } else { - super.nameIt(path) + super.nameIt(path, isNamingIo) } } diff --git a/src/main/scala/Module.scala b/src/main/scala/Module.scala index 0fefa16d..d3982789 100644 --- a/src/main/scala/Module.scala +++ b/src/main/scala/Module.scala @@ -223,8 +223,9 @@ object Module { } } + // XXX Remove and instead call current() def getComponent(): Module = if(compStack.length != 0) compStack.top else null - def current: Module = compStack.top + def current: Module = getComponent def setAsTopComponent(mod: Module) { topComponent = mod; @@ -355,6 +356,22 @@ abstract class Module(var clock: Clock = null, private var _reset: Bool = null) } def io: Data + + // for making sure that all module io's are ports and + // for marking all io's as module io's + var isIoChecked = false + def checkIo = { + if (io != null && !isIoChecked) { + isIoChecked = true; + for((n, flat) <- io.flatten) { + if (flat.dir == null) + ChiselError.error("All IO's must be ports (dir set): " + flat); + // else if (flat.width_ == -1) + // ChiselError.error("All IO's must be have width set: " + flat); + flat.isModuleIo = true; + } + } + } def nextIndex : Int = { nindex = nindex + 1; nindex } var isWalking = new HashSet[Node]; diff --git a/src/main/scala/Node.scala b/src/main/scala/Node.scala index 11ca0009..b9fc3795 100644 --- a/src/main/scala/Node.scala +++ b/src/main/scala/Node.scala @@ -152,8 +152,8 @@ abstract class Node extends nameable { inferWidth = fixWidth(w); } - def nameIt (path: String) { - if( !named ) { + def nameIt (path: String, isNamingIo: Boolean) { + if( (!isIo && !named) || (isIo && isNamingIo) ) { /* If the name was set explicitely through *setName*, we don't override it. */ name = path; diff --git a/src/main/scala/Reg.scala b/src/main/scala/Reg.scala index 9767e60f..a20856bb 100644 --- a/src/main/scala/Reg.scala +++ b/src/main/scala/Reg.scala @@ -177,10 +177,8 @@ class Reg extends Delay with proc { ChiselError.error("reassignment to Reg"); } val cond = Module.current.whenCond - if (Module.current.hasWhenCond) { - enable = if (isEnable) enable || cond else cond - isEnable = true - } + enable = if (isEnable) enable || cond else cond + isEnable = true updates += ((cond, src)) } override def genMuxes(default: Node): Unit = { diff --git a/src/main/scala/Vec.scala b/src/main/scala/Vec.scala index d2d58688..9ffb800f 100644 --- a/src/main/scala/Vec.scala +++ b/src/main/scala/Vec.scala @@ -294,7 +294,7 @@ class Vec[T <: Data](val gen: (Int) => T) extends CompositeData with VecLike[T] this } - override def nameIt (path: String) { + override def nameIt (path: String, isNamingIo: Boolean) { if( !named && (name.isEmpty || (!path.isEmpty && name != path)) ) { @@ -310,7 +310,7 @@ class Vec[T <: Data](val gen: (Int) => T) extends CompositeData with VecLike[T] } else { elm.name } - elm.nameIt(prefix + i + suffix) + elm.nameIt(prefix + i + suffix, isNamingIo) } } else { /* We are trying to rename a Vec that has a fixed name. */ diff --git a/src/test/resources/NameSuite_BindFithComp_1.v b/src/test/resources/NameSuite_BindFifthComp_1.v similarity index 97% rename from src/test/resources/NameSuite_BindFithComp_1.v rename to src/test/resources/NameSuite_BindFifthComp_1.v index 6f965011..9cf36997 100644 --- a/src/test/resources/NameSuite_BindFithComp_1.v +++ b/src/test/resources/NameSuite_BindFifthComp_1.v @@ -32,7 +32,7 @@ module NameSuite_Block_2(input clk, end endmodule -module NameSuite_BindFithComp_1(input clk, +module NameSuite_BindFifthComp_1(input clk, input io_imem_ptw_resp_valid, input io_imem_ptw_resp_bits_error, input [31:0] io_imem_ptw_resp_bits_ppn, diff --git a/src/test/resources/NameSuite_BindFirstComp_1.v b/src/test/resources/NameSuite_BindFirstComp_1.v index 422a84db..368814b2 100644 --- a/src/test/resources/NameSuite_BindFirstComp_1.v +++ b/src/test/resources/NameSuite_BindFirstComp_1.v @@ -10,7 +10,7 @@ module NameSuite_BlockDecoder_1( endmodule module NameSuite_BindFirstComp_1( - input valid_common, + input io_valid, output io_replay ); @@ -24,7 +24,7 @@ module NameSuite_BindFirstComp_1( wire dec_io_sigs_enq_cmdq; assign io_replay = T0; - assign T0 = valid_common && T1; + assign T0 = io_valid && T1; assign T1 = T3 || T2; assign T2 = ! mask_ximm1q_ready; assign mask_ximm1q_ready = ! dec_io_sigs_enq_ximm1q; diff --git a/src/test/resources/NameSuite_VecComp_1.v b/src/test/resources/NameSuite_VecComp_1.v index 1321afef..2dc0c8f1 100644 --- a/src/test/resources/NameSuite_VecComp_1.v +++ b/src/test/resources/NameSuite_VecComp_1.v @@ -1,4 +1,5 @@ module NameSuite_VecComp_1(input clk, + input [63:0] io_pcr_req_data, input io_r_en, input [4:0] io_r_addr, input [63:0] io_w_data, diff --git a/src/test/scala/ConnectTest.scala b/src/test/scala/ConnectTest.scala index ddc10b20..bf31ad4d 100644 --- a/src/test/scala/ConnectTest.scala +++ b/src/test/scala/ConnectTest.scala @@ -243,4 +243,33 @@ class ConnectSuite extends TestSuite { launchCppTester((m: A) => new RegisterHookTests(m)) } + // tests flagging bad cross module references + @Test def testCrossModuleReferences() { + try { + class ForeignMod extends Module { + val io = new Bundle { + val input = UInt(INPUT, width = 8) + val output = UInt(OUTPUT, width = 8) + } + val add = io.input + io.input + io.output := add + UInt(1) + } + + class ForeignRef extends Module { + val io = new Bundle { + val input = Bits(INPUT, width = 8) + val output = Bits(OUTPUT, width = 8) + } + val foreign = Module(new ForeignMod) + io.output := io.input + foreign.add + } + + chiselMain(Array[String]("--backend", "v"), () => Module(new ForeignRef())) + + } catch { + case _ : Throwable => ; + } + assertTrue(!ChiselError.ChiselErrors.isEmpty); + } + } diff --git a/src/test/scala/DataTest.scala b/src/test/scala/DataTest.scala index a77905b5..cc0bfffc 100644 --- a/src/test/scala/DataTest.scala +++ b/src/test/scala/DataTest.scala @@ -186,28 +186,55 @@ class DataSuite extends TestSuite { to be an error to so. This is fixed as well. */ @Test def testBypassData() { + try { class BypassDataIO(num_bypass_ports:Int) extends Bundle() { val data = UInt(INPUT, width=num_bypass_ports) - val valid = Vec.fill(num_bypass_ports){Bool()}.asOutput + val valid = Vec.fill(num_bypass_ports){ Bool() } + // XXX Module.findRoots does not support Vec as a graph root. + def get_num_ports: Int = num_bypass_ports } - class BypassData extends Module { + class BypassDataComp extends Module { val io = new BypassDataIO(3) io.valid := io.data | UInt(1) } - class BypassDataTests(m: BypassData) extends Tester(m, Array(m.io)) { - defTests { - val vars = new HashMap[Node, Node]() - (0 until 4).map { i => - vars(m.io.data) = UInt(i) - vars(m.io.valid(0)) = Bool(true) - for ( j <- 1 until 3 ) { - vars(m.io.valid(j)) = Bool(if(((i >> j) & 1) == 1) true else false) - } - step(vars) - } reduce(_&&_) + chiselMain(Array[String]("--backend", "c", + "--targetDir", dir.getPath.toString()), + () => Module(new BypassDataComp)) + // assertFile("DataSuite_BypassDataComp_1.h") + } catch { + case _ : Throwable => ; + } + assertTrue(!ChiselError.ChiselErrors.isEmpty); + } + + // tests assigning to non parent's outputs + @Test def testAssignToChildOutput() { + try { + class Child extends Module { + val io = new Bundle { + val input = Bits(INPUT, width = 8) + val output = Bits(OUTPUT, width = 8) } + io.output := io.input } - launchCppTester((m: BypassData) => new BypassDataTests(m)) + + class Parent extends Module { + val io = new Bundle { + val input = Bits(INPUT, width = 8) + val output = Bits(OUTPUT, width = 8) + } + val child = Module(new Child) + // child.io.input := io.input + child.io.output := io.input + io.output := child.io.output + } + + chiselMain(Array[String]("--backend", "v"), () => Module(new Parent())) + + } catch { + case _ : Throwable => ; + } + assertTrue(!ChiselError.ChiselErrors.isEmpty); } /** Test case derived from issue #1 reported on github. @@ -231,10 +258,13 @@ class DataSuite extends TestSuite { "--targetDir", dir.getPath.toString()), () => Module(new CarryChainComp(4))) } catch { - case _ : Throwable => assertTrue(!ChiselError.ChiselErrors.isEmpty); + case _ : Throwable => ; } + assertTrue(!ChiselError.ChiselErrors.isEmpty); } + + } diff --git a/src/test/scala/NameTest.scala b/src/test/scala/NameTest.scala index 3a5344e0..013d2c73 100644 --- a/src/test/scala/NameTest.scala +++ b/src/test/scala/NameTest.scala @@ -173,6 +173,7 @@ class NameSuite extends TestSuite { At the toplevel *Comp*, variables should be named conn_X instead of using a derived name derived from CompIO. + But importantly io names should be derived from their io names. */ @Test def testBindThird() { println("\nRunning testBindThird:") @@ -251,8 +252,8 @@ class NameSuite extends TestSuite { the last entry of the ArrayBuffer is attached to a io port of a subcomponent. */ - @Test def testBindFith() { - println("\nRunning testBindFith:") + @Test def testBindFifth() { + println("\nRunning testBindFifth:") class UnamedBundle extends Bundle { val error = Bool() val ppn = UInt(width = 32) @@ -276,7 +277,7 @@ class NameSuite extends TestSuite { io.out.resp.bits.ppn := Mux1H(tag_ram(0), tag_ram) } - class BindFithComp extends Module { + class BindFifthComp extends Module { val io = new Bundle { val imem_ptw = new BlockIO() val dmem_ptw = new BlockIO() @@ -292,8 +293,8 @@ class NameSuite extends TestSuite { chiselMain(Array[String]("--v", "--targetDir", dir.getPath.toString()), - () => Module(new BindFithComp)) - assertFile("NameSuite_BindFithComp_1.v") + () => Module(new BindFifthComp)) + assertFile("NameSuite_BindFifthComp_1.v") } /** Appending index to a node name in Vec::apply @@ -303,7 +304,7 @@ class NameSuite extends TestSuite { println("\nRunning testVec:") class VecComp extends Module { val io = new Bundle { - val pcr_req_data = UInt(width = 64) + val pcr_req_data = UInt(INPUT, width = 64) val r_en = Bool(INPUT) val r_addr = UInt(INPUT, log2Up(32)) diff --git a/src/test/scala/StdlibTest.scala b/src/test/scala/StdlibTest.scala index 92b40dcb..512d8f1f 100644 --- a/src/test/scala/StdlibTest.scala +++ b/src/test/scala/StdlibTest.scala @@ -417,13 +417,21 @@ try { */ @Test def testArbiter() { println("\ntestArbiter ...") -try { - class ArbiterTest extends Arbiter(SInt(width=8), 4) { - } + try { + def gen = SInt(width=8) + val n = 4 + class ArbiterTest extends Module { + val io = new ArbiterIO(gen, n) { + val fire = Bool(OUTPUT) + } + val arb = Module(new Arbiter(gen, n)) + io <> arb.io + io.fire := arb.io.out.fire() + } - chiselMain(Array[String]("--v", - "--targetDir", dir.getPath.toString()), - () => Module(new ArbiterTest())) + chiselMain(Array[String]("--v", + "--targetDir", dir.getPath.toString()), + () => Module(new ArbiterTest())) } catch { case e => e.printStackTrace() }