When using SInt and UInt to implement an adder I get the same Verilog code, see the codes below,
import Chisel._
class Unsigned_Adder extends Module{
val io = new Bundle{
val a = UInt(INPUT, 16)
val b = UInt(INPUT, 16)
val out = UInt(OUTPUT)
}
io.out := io.a + io.b
}
and
import Chisel._
class Signed_Adder extends Module{
val io = new Bundle{
val a = SInt(INPUT, 16)
val b = SInt(INPUT, 16)
val out = SInt(OUTPUT)
}
io.out := io.a + io.b
}
This will generate the same Verilog code,
module Signed_Adder(
input [15:0] io_a,
input [15:0] io_b,
output[15:0] io_out
);
wire[15:0] T0;
assign io_out = T0;
assign T0 = io_a + io_b;
endmodule
Of-course the modules names will differ. when implementing a multiplier in chisel using the multiplication operator (*)
io.out := io.a * io.b
I will get a different Verilog code for the UInt and SInt, where in the SInt the code will look like,
module Multi(
input [15:0] io_a,
input [15:0] io_b,
output[31:0] io_out
);
wire[31:0] T0;
assign io_out = T0;
assign T0 = $signed(io_a) * $signed(io_b);
endmodule
Adding $signed to the code. Why is that? why is it that in the addition case I get the same Verilog code but in the multiplication case I get a different code generated for UInt and SInt?
With addition if the size of variable are equal, the adder don't care about the sign, the addition will be correct thanks to overflow bit.
But with multiplication, we have to know the sign to manage it.
See this documentation about the signed arithmetic in verilog for more information :
enter link description here
If you use +& then the Addr.io.out's width will be 17 bit
and in verilog this Addr won't care of the sign as FabienM said, because it will be handled by the upper hierarchy design like unsigned to signed transform then connected to this Addr, and it will be transformed to the 2-complement form.
Related
Is there a one-liner that takes a Vec[Bool] and creates an inverted version of it?
Here is an example of taking 37 bits, inverting them, then doing an OR reduction across all of them. Is there a one-liner that can replace the assignment of inv_a?
class MyModule extends Module {
val io = IO(new Bundle {
val a = Input(Vec(37, Bool()))
val b = Output(Bool())
})
val inv_a = Wire(Vec(37, Bool()))
for (i <- 0 until 37) {
inv_a(i) := ~io.a(i)
}
io.b := inv_a.reduce((a, b) => (a | b))
}
I think this does what you want.
val inv_a = (~ io.a.asUInt).asBools()
Alternatively, you could map on the input Vec to invert each element:
val inv_a = io.a.map(!_)
Example in a Scastie (using Chisel v3.4.4): https://scastie.scala-lang.org/bcQIihPMThelC9h4jDfyxQ
Note that the type of inv_a is a Seq[Bool] which you can still do your reduce on, but if you need a Vec[Bool] back you'll need to wrap the result in VecInit(...):
val inv_a: Vec[Bool] = VecInit(io.a.map(!_))
I have an IO bundle as shown below
val io = IO(new Bundle{
val test = Input(UInt(32.W))
})
Now from the testbench I want to give inputs to the test pin. I know that we can use peekpoketesters to give an input like this
poke(dut.io.test, 40.U)
But is there a way I can use peekpoketester to set the individual bits of the test input pin?
For example something like this
poke(dut.io.test(31,23) , 6.U)
The short answer is no, poking to specific bits of an input is not directly supported, but using the fact that you can peek top level inputs here is a very simplistic workaround. You can run and test this on scastie here.
You could generalize this to operate on inputs more directly as in your example.
This code uses an extremely quick, dirty, and naive bit manipulation method, but I like working with binary text strings when I'm in a hurry. One more note, this is using the more modern chiseltest (vs old iotesters), but a similar method could be used in iotesters
import chisel3._
import chiseltest._
import chiseltest.experimental.ChiselTestShell
class PassThrough extends Module {
val io = IO(new Bundle {
val in = Input(UInt(32.W))
val out = Output(UInt(32.W))
})
io.out := io.in
}
/** use strings to construct bit mask to clear target range and then or in newbits */
def setBits(
target: BigInt,
topBit: Int,
lowBit: Int,
newBits: BigInt
): BigInt = {
val clearMask = BigInt(
"1" * (target.bitLength.max(
newBits.bitLength
) - topBit) + "0" * (topBit - lowBit + 1) + "1" * lowBit,
radix = 2
)
(target & clearMask) | (newBits << lowBit)
}
// crude verification of setBits
println(setBits(BigInt(31), 2, 1, 2).toString(2))
chiseltest.RawTester.test(new PassThrough) { c =>
c.io.in.poke(40.U)
c.clock.step()
c.io.out.expect(40.U)
val lastIn = c.io.in.peek().litValue()
val newVal = setBits(lastIn, 31, 23, 6)
val bitAddr = (0 to 31).map { x => x % 10 }.reverse.mkString("")
println(s" = $bitAddr")
println(f"lastIn = ${lastIn.toString(2)}%32s")
println(f"newVal = ${newVal.toString(2)}%32s")
c.io.in.poke(newVal.U)
c.clock.step()
c.io.out.expect(newVal.U)
}
I recently updated the Chisel version of a big project of mine from 3.1.1 to 3.4.0; however, I am getting a bunch of firrtl.passes.CheckHighFormLike$DefnameDifferentPortsException:
firrtl.passes.CheckHighFormLike$DefnameDifferentPortsException: : ports of extmodule XilinxSimpleDualPortNoChangeBRAM with defname XilinxSimpleDualPortNoChangeBRAM are different for an extmodule with the same defname
firrtl.passes.CheckHighFormLike$DefnameDifferentPortsException: : ports of extmodule XilinxSimpleDualPortNoChangeBRAM_1 with defname XilinxSimpleDualPortNoChangeBRAM are different for an extmodule with the same defname
// and so on 241 times
Here is the definition of XilinxSimpleDualPortNoChangeBRAM, together with its dependencies:
class XilinxSimpleDualPortNoChangeBRAM(width: Int,
depth: Int,
performance: String="HIGH_PERFORMANCE",
initFile: String="",
ramStyle: String="block",
val useReset: Boolean=false)
extends BlackBox(Map("RAM_WIDTH" -> width,
"RAM_DEPTH" -> depth,
"RAM_PERFORMANCE" -> performance,
"INIT_FILE" -> initFile,
"RAM_STYLE" -> ramStyle))
with HasBlackBoxResource with Memory {
val io = IO(new XilinxSimpleDualPortBRAMBlackBoxIO(log2Ceil(depth), width))
val acceptedRamStyles = Seq("block", "distributed", "registers", "ultra")
require(acceptedRamStyles contains ramStyle)
def write(wrAddr: UInt, wrData: UInt, wrEn: Bool): Unit = {
io.wea := wrEn
io.addra := wrAddr
io.dina := wrData
}
def read(rdAddr: UInt, rdEn: Bool): UInt = {
io.addrb := rdAddr
io.regceb := rdEn
io.enb := rdEn
io.doutb
}
def defaultBindings(clock: Clock, reset: core.Reset): Unit = {
io.clock := clock
if(useReset)
io.reset := reset
else
io.reset := false.B
}
setResource("/XilinxSimpleDualPortNoChangeBRAM.v")
}
trait Memory extends BaseModule {
def read(rdAddr: UInt, rdEn: Bool): UInt
def write(wrAddr: UInt, wrData: UInt, wrEn: Bool): Unit
val latency: Int = 2
}
class XilinxSimpleDualPortBRAMIO(addrWidth: Int, dataWidth: Int) extends Bundle {
val addra = Input(UInt(addrWidth.W))
val addrb = Input(UInt(addrWidth.W))
val dina = Input(UInt(dataWidth.W))
val wea = Input(Bool())
val enb = Input(Bool())
val regceb = Input(Bool())
val doutb = Output(UInt(dataWidth.W))
override def cloneType = (new XilinxSimpleDualPortBRAMIO(addrWidth, dataWidth)).asInstanceOf[this.type]
}
class XilinxSimpleDualPortBRAMBlackBoxIO(addrWidth: Int, dataWidth: Int) extends XilinxSimpleDualPortBRAMIO(addrWidth, dataWidth) {
val clock = Input(Clock())
val reset = Input(Reset())
override def cloneType = (new XilinxSimpleDualPortBRAMBlackBoxIO(addrWidth, dataWidth)).asInstanceOf[this.type]
}
The Verilog resource XilinxSimpleDualPortNoChangeBRAM.v is one of the BRAM instantiation templates available in Vivado:
module XilinxSimpleDualPortNoChangeBRAM #(
parameter RAM_WIDTH = 64, // Specify RAM data width
parameter RAM_DEPTH = 512, // Specify RAM depth (number of entries)
parameter RAM_PERFORMANCE = "HIGH_PERFORMANCE", // Select "HIGH_PERFORMANCE" or "LOW_LATENCY"
parameter INIT_FILE = "", // Specify name/location of RAM initialization file if using one (leave blank if not)
parameter RAM_STYLE = "block" // Target memory type. Accepted values: block, distributed, registers, ultra (UltraScale+ only)
) (
input [clogb2(RAM_DEPTH-1)-1:0] addra, // Write address bus, width determined from RAM_DEPTH
input [clogb2(RAM_DEPTH-1)-1:0] addrb, // Read address bus, width determined from RAM_DEPTH
input [RAM_WIDTH-1:0] dina, // RAM input data
input wea, // Write enable
input enb, // Read Enable, for additional power savings, disable when not in use
input regceb, // Output register enable
output [RAM_WIDTH-1:0] doutb, // RAM output data
input clock, // Clock
input reset // Output reset (does not affect memory contents)
);
(* ram_style = RAM_STYLE *) reg [RAM_WIDTH-1:0] BRAM [RAM_DEPTH-1:0];
reg [RAM_WIDTH-1:0] ram_data = {RAM_WIDTH{1'b0}};
// The following code either initializes the memory values to a specified file or to all zeros to match hardware
generate
if (INIT_FILE != "") begin: use_init_file
initial
$readmemh(INIT_FILE, BRAM, 0, RAM_DEPTH-1);
end else begin: init_bram_to_zero
integer ram_index;
initial
for (ram_index = 0; ram_index < RAM_DEPTH; ram_index = ram_index + 1)
BRAM[ram_index] = {RAM_WIDTH{1'b0}};
end
endgenerate
always #(posedge clock) begin
if (wea)
BRAM[addra] <= dina;
if (enb)
ram_data <= BRAM[addrb];
end
// The following code generates HIGH_PERFORMANCE (use output register) or LOW_LATENCY (no output register)
generate
if (RAM_PERFORMANCE == "LOW_LATENCY") begin: no_output_register
// The following is a 1 clock cycle read latency at the cost of a longer clock-to-out timing
assign doutb = ram_data;
end else begin: output_register
// The following is a 2 clock cycle read latency with improve clock-to-out timing
reg [RAM_WIDTH-1:0] doutb_reg = {RAM_WIDTH{1'b0}};
always #(posedge clock)
if (reset)
doutb_reg <= {RAM_WIDTH{1'b0}};
else if (regceb)
doutb_reg <= ram_data;
assign doutb = doutb_reg;
end
endgenerate
// The following function calculates the address width based on specified RAM depth
function integer clogb2;
input integer depth;
for (clogb2=0; depth>0; clogb2=clogb2+1)
depth = depth >> 1;
endfunction
endmodule
I tried to have a look at the file where this exception is thrown, CheckHighForm.scala, but I quickly got lost as I have no idea of what I should be looking for.
What I understood from the tests in CheckSpec.scala is that it should throw an exception if ExtModules have matching port names and widths, but a different order, so I tried to make the order of the inputs in the Chisel BlackBox the same as the ones in the Verilog module but I still get an exception.
The test throw an exception if parameterless ExtModules have the same ports, but different widths made me think that having multiple instantiations with different port widths could be the reason for the exception, but then there is another test that says that it should NOT throw an exception if ExtModules have parameters, matching port names, but different widths, which is the case here as the port widths are controlled by parameters.
What could be the reason for this exception?
Update: As requested, here is the FIRRTL IR of two instantiations of the black box:
extmodule XilinxSimpleDualPortNoChangeBRAM :
input addra : UInt<14>
input addrb : UInt<14>
input dina : UInt<1>
input wea : UInt<1>
input enb : UInt<1>
input regceb : UInt<1>
output doutb : UInt<1>
input clock : Clock
input reset : Reset
defname = XilinxSimpleDualPortNoChangeBRAM
parameter RAM_STYLE = "block"
parameter RAM_WIDTH = 1
parameter RAM_DEPTH = 16384
parameter RAM_PERFORMANCE = "HIGH_PERFORMANCE"
parameter INIT_FILE = ""
extmodule XilinxSimpleDualPortNoChangeBRAM_1 :
input addra : UInt<6>
input addrb : UInt<6>
input dina : UInt<518>
input wea : UInt<1>
input enb : UInt<1>
input regceb : UInt<1>
output doutb : UInt<518>
input clock : Clock
input reset : Reset
defname = XilinxSimpleDualPortNoChangeBRAM
parameter RAM_STYLE = "distributed"
parameter RAM_WIDTH = 518
parameter RAM_DEPTH = 64
parameter RAM_PERFORMANCE = "HIGH_PERFORMANCE"
parameter INIT_FILE = ""
Update 2: Apparently, some XilinxSimpleDualPortNoChangeBRAM were picking up an older version of XilinxSimpleDualPortBRAMBlackBoxIO where the reset was still of type Bool instead of Reset. Changing that solved the issue.
This check is supposed to disallow impossible situations when referring to a specific BlackBox. Namely, the following must be true:
If the BlackBox has no parameters, then all ports must have the same name, same width, and be in the same order
If the BlackBox has parameters, then all ports must have the same name and be in the same order (but may have different widths)
It sounds like either your example is producing BlackBoxes that violate the latter condition (since your BlackBoxes have parameters) or this has exposed a bug in that FIRRTL compiler check.
The actual Verilog module is never checked and can't cause any problems here.
Could you update your question to provide the FIRRTL IR that is producing these errors? Specifically, what does the FIRRTL IR for XilinxSimpleDualPortNoChangeBRAM and XilinxSimpleDualPortNoChangeBRAM_1 look like? This should be in a file like "Foo.fir". Alternatively, you can do something like:
import chisel3.stage.ChiselStage
/* Note: this is emitChirrtl ("chirrtl") as you want the FIRRTL emitted from Chisel. */
println(ChiselStage.emitChirrtl(new MyTopModule))
I am new to this.
I have some questions about the code.
What is different between these codes:
val myVec = Vec(5){Fix(width= 23)}
and
val myVec = Vec.fill(5){SInt(width = 23 )}
what does "fill" mean?
thanks
"Fill" is a Scala-ism, for initializing things like lists with elements:
scala> val x = List.fill(3)("foo")
x: List[java.lang.String] = List(foo, foo, foo)
In the same vein, Vec.fill(5){SInt(width=23)} is returning a Chisel Vec where each of the 5 elements is set to a 23b signed integer wire.
However, if you are using Chisel, you should move to Chisel3 (https://github.com/ucb-bar/chisel3/wiki), in which the new syntax is:
val myVec = Wire(Vec(5, SInt(width=23)))
That creates a Wire of a 5-element vector made up of 23b signed integers. (In Chisel3 any wires must be explicitly wrapped).
I am new to Chisel HDL. I have a question regarding to Vec assignment. Suppose I have a Vec has n elements, and each one has w-bit SInt,
How can I assign a range of elements, let's say I have two Vec: a = Vec(10, SInt(width=8)), I have b = Vec(3, SInt(width=8)), How can I assign b := a(2:4)?
I know I can do it in for loop, is there any more elegant way to do it? I haven't find any example code or materials on it
Seems you are looking for a slice function in Vec. Glancing through
the Vec class I could not find such a function.
So the short answer is no, there is no elegant way to do this out-of-the-box.
The second most elegant thing is then to put such a function
in your project's util library and try to eventually
get this function upstreamed.
Implementing it in Chisel3 might look something like this:
class FooTester extends BasicTester {
def slice[T <: Data](someVec: Vec[T], startIndex: Int, endIndex: Int) : Vec[T] = {
Vec( for (i <- startIndex to endIndex) yield someVec(i) )
}
// An initialized Vec
val a = Vec(
Range(0, 10)
.map(SInt(_, width=8))
)
// A declared Vec
val b = Wire(Vec(3, SInt(width=8)))
b := slice(a, 2, 4)
assert(b(1) === SInt(3, width=8))
when(Counter(10).inc()) {stop()}
}
for (i <- 3 to 8) { my_vec(i) := something_at_index(i) }