I'm wrapping a block of Mem in a fairly generic module called "bank" and instantiating it in a Vec as follows:
val rams = Vec.fill( 100 ) { Module( new bank ).io }
So far so good. I'm running into problems when I connect the signals. If I connect the vector of modules' signals directly to vectors of signals, like so:
rams(i).in := io.ins(i)
io.outs(i) := rams(i).out
...and so forth, I get no errors.
If I connect them in a non-trivial pattern, however, such as to a crossbar, I start getting a weird error that appears to refer to the Mem wrapper I call "bank":
"Parameterized Bundle class ascenium.bank$$anon$1 needs cloneType method."
This error is specifically a Chisel error. Can anybody tells me what it means and how to fix it?
I can provide source code if need be.
Errors like this can usually be addressed by adding a cloneType method to classes you define:
class MyModule extends Module
{
// Your class definition here
override def cloneType = new MyModule.asInstanceOf[this.type]
}
Related
Can anyone help me to understand how "read" macro is implemented? I have the feeling that "do_read" function below is actually called, but could not figure out how that is done. I'm intrigued by the "SourceInfoTransform" class. Can anyone give me a hint on its usage?
The "SyncReadMem" implementation is listed below.
Thanks in advance for any help!
Best regards,
-Fei
sealed class SyncReadMem[T <: Data] private (t: T, n: BigInt, val readUnderWrite: SyncReadMem.ReadUnderWrite) extends MemBase[T](t, n) {
def read(x: UInt, en: Bool): T = macro SourceInfoTransform.xEnArg
/** #group SourceInfoTransformMacro */
def do_read(addr: UInt, enable: Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = {
val a = Wire(UInt())
a := DontCare
var port: Option[T] = None
when (enable) {
a := addr
port = Some(read(a))
}
port.get
}
}
The SourceInfoTransform is a scala macro that transforms the def read into the def do_read. The code for the macro is in src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala of github.com/chipsalliance/chisel3. In that file there are a lot of transform classes for handling different chisel constructs with different numbers of arguments. The main use of the SourceInfoTransform is to get the line number of the Chisel/Scala source so it can be reported in Exceptions and in generated Firrtl and Verilog. Here is an article on macros, there are many more available.
Good luck.
Chick's answer is mostly correct--it's correct on the "how" and where to look, but slightly wrong on the "why":
The main use of the SourceInfoTransform is to get the line number of the Chisel/Scala source
This is not quite true, you can get source locators with merely having implicit sourceInfo: SourceInfo, and you could have that on the original def read if you wanted to. What the SourceInfoTransform macros do is resolve ambiguity when you want to do a bit extraction immediately following invoking the read method, eg.
myMem.read(addr, en)(16, 0)
If we had defined read with the implicits directly, the compiler would think you're trying to pass 16 and 0 as the implicit arguments, when in reality, you're trying to call .apply on the resulting T (if it's a subtype of Bits). The macro resolves the ambiguity so that the compiler knowns you're not trying to pass the implicits.
Here's a link to a talk where I describe this (warning while the little part about source locators and the macro are correct, much of this talk is out-of-date): https://youtu.be/2-ZiXNd9wbc?t=2756
I'm working on a scala object in order to perform some testing
My start object is as follows
object obj1 {
def readvalue : IO[Float] = IO{
scala.io.StdIn.readFloat()
}
}
The testing should be
1- value of type FLOAT
2- should be less than 3
As we can not mock singleton objects I've used mocking functions here is what I've done.
class FileUtilitiesSpec
extends FlatSpec
with Matchers
with MockFactory
{
"value" should "be of Type Float" in {
val alpha = mockFunction[() => IO[Float]]
alpha.expects shouldBe a[IO[Float]]
}
"it" should "be less than 3" in {
val alpha = mockFunction[() => IO[Float]]
alpha.expects shouldBe <(3)
}
}
Im getting an error saying that :
MockFunction0-1() once (never called - UNSATISFIED) was not an instance of cats.effect.IO, but an instance of org.scalamock.handlers.CallHandler0
ScalaTestFailureLocation: util.FileUtilitiesSpec at (FileUtilitiesSpec.scala:16)
Expected :cats.effect.IO
Actual :org.scalamock.handlers.CallHandler0 ```
I would recommend reading the examples here as a starting point: https://scalamock.org/quick-start/
Using mock objects only makes sense if you are planning to use them in some other code, e.g. dependencies you do not want to make part of your module under test, or are beyond your control.
An example might be a database connection where you would depend on an actual system, making the code hard to test without simulating it.
The example you provided only has mocks, but no code using it, hence the error you are getting is absolutely correct. The mock expects to be used, but was not called.
The desired behaviour for a mocking library in this case is to make the test fail as the developer intended for this interaction with a mock to happen, but it was not recorded - so something is wrong.
It seems not an easy thing to do or even impossible, but we are using a naming convention that prefix or postfix signals with "i_" or "o_" for inputs/outputs in verilog.
Is there some method to mess with or override inside the chisel library to to that?
I saw that except for clock and reset, all signals have "io" prefix.
Is is possible to use just "i" for input and "o" for output?
The easiest way to do this is to probably use a MultiIOModule. However, you can also do it with suggestName. Both approaches are shown below.
MultiIOModule
This a more flexible Module that lets you call the IO method to add ports to a module more than once. (Module requires that you define an io member and only allows you to call IO once.)
Because MultiIOModule frees you from the constraints of val io = ... you can use the prefix/postfix naming that you want with the names of your vals. Reflective naming will then get these right in the generated Verilog.
Consider the following Chisel code:
import chisel3._
import chisel3.stage.{ChiselStage, ChiselGeneratorAnnotation}
class Foo extends MultiIOModule {
val i_bar = IO(Input(Bool()))
val o_baz = IO(Output(Bool()))
o_baz := ~i_bar
}
(new ChiselStage).execute(Array.empty, Seq(ChiselGeneratorAnnotation(() => new Foo)))
This produces the following Verilog:
module Foo(
input clock,
input reset,
input i_bar,
output o_baz
);
assign o_baz = ~ i_bar;
endmodule
SuggestName
As an alternative, you can use the suggestName method to change the name to be different from what reflective naming (getting the name from the name of the val) would use.
Using suggestName you can coerce the names to be whatever you want. The following Chisel produces the same Verilog as above:
class Foo extends MultiIOModule {
val a = IO(Input(Bool())).suggestName("i_bar")
val b = IO(Output(Bool())).suggestName("o_baz")
b := ~a
}
If we take for example the following code excerpt (at the top of a module):
val write_indices = WireInit(VecInit(Seq.fill(wordsPerBeat)(0.U((log2Ceil(nWays)+log2Ceil(nSets)+log2Ceil(cacheBlockBytes/wordBytes)).W))))
val write_line_indices = WireInit(VecInit(Seq.fill(wordsPerBeat)(0.U(log2Ceil(cacheBlockBytes/wordBytes).W))))
dontTouch(write_indices)
dontTouch(write_line_indices)
// refill logic
when(mem_response_present) {
for (i <- 0 until wordsPerBeat) {
val beatIdx = i.U(log2Ceil(wordsPerBeat).W)
val write_line_index = Cat(d_refill_cnt(log2Ceil(cacheBlockBytes/wordsPerBeat/wordBytes)-1, 0), beatIdx)
val write_idx = Cat(refill_way, refill_set, write_line_index)
write_indices(i) := write_idx
write_line_indices(i) := write_line_index
cache_line(write_idx) := tl_out.d.bits.data((i + 1) * wordBits - 1, i * wordBits)
}
}
The only reason for the two top level signals is to get lower signals visible in waveforms.
Is there any way to achieve the same effect without having to manually create those signals?
In this example half the code is used just to get the ability to debug.
That seems a bit excessive.
That seems a bit excessive
Completely agreed, fortunately there is a solution. For implementation reasons, Chisel by default is only able to name public fields of the Module class. That is, only the values at the the top-level scope of your Module. However, there is a nifty macro chisel3.experimental.chiselName that can name these vals inside of the for loop. Try annotating your Module like so:
import chisel3._
import chisel3.experimental.chiselName
#chiselName
class MyModule extends Module {
...
}
Please check out this earlier answer discussing naming, it has more information than is relevant to answer this question alone, but it has other useful information about how naming works in Chisel.
In the docs it is written, that "Any C data that you explicitly allocated (e.g. via malloc) in your __cinit__() method should be freed in your __dealloc__() method."
This is not my case. I have following extension class:
cdef class SomeClass:
cdef dict data
cdef void * u_data
def __init__(self, data_len):
self.data = {'columns': []}
if data_len > 0:
self.data.update({'data': deque(maxlen=data_len)})
else:
self.data.update({'data': []})
self.u_data = <void *>self.data
#property
def data(self):
return self.data
#data.setter
def data(self, new_val: dict):
self.data = new_val
Some c function has an access to this class and it appends some data to SomeClass().data dict. What should I write in __dealloc__, when I want to delete the instance of the SomeClass()?
Maybe something like:
def __dealloc__(self):
self.data = None
free(self.u_data)
Or there is no need to dealloc anything at all?
No you don't need to and no you shouldn't. From the documentation
You need to be careful what you do in a __dealloc__() method. By the time your __dealloc__() method is called, the object may already have been partially destroyed and may not be in a valid state as far as Python is concerned, so you should avoid invoking any Python operations which might touch the object. In particular, don’t call any other methods of the object or do anything which might cause the object to be resurrected. It’s best if you stick to just deallocating C data.
You don’t need to worry about deallocating Python attributes of your object, because that will be done for you by Cython after your __dealloc__() method returns.
You can confirm this by inspecting the C code (you need to look at the full code, not just the annotated HTML). There's an autogenerated function __pyx_tp_dealloc_9someclass_SomeClass (name may vary slightly depending on what you called your module) does a range of things including:
__pyx_pw_9someclass_9SomeClass_3__dealloc__(o);
/* some other code */
Py_CLEAR(p->data);
where the function __pyx_pw_9someclass_9SomeClass_3__dealloc__ is (a wrapper for) your user-defined __dealloc__. Py_CLEAR will ensure that data is appropriately reference-counted then set to NULL.
It's a little hard to follow because it all goes through several layers of wrappers, but you can confirm that it does what the documentation says.