RegInit initializes value only on reset - scala

I am implementing a pulse width modulation module to learn chisel3.
The module code is:
import chisel3._
import chisel3.util._
import chisel3.tester._
class Pwm(bitWidth: Int) extends Module {
val io = IO(new Bundle {
val duty = Input(UInt(bitWidth.W))
val period = Input(UInt(bitWidth.W))
val output = Output(Bool())
})
val context = RegInit(0.U(bitWidth.W))
val output = RegInit(false.B)
val sum = Wire(UInt(bitWidth.W + 1))
sum := context +& io.duty
when (sum >= io.period) {
context := sum - io.period
output := true.B
} otherwise {
context := sum
output := false.B
}
io.output := output
}
I was expecting the registers to be initialized to their RegInit values when I emit verilog with:
val emit_args = Array("--emission-options=disableMemRandomization,disableRegisterRandomization");
chisel3.emitVerilog(new Pwm(8), emit_args)
But I get the following verilog code:
module Pwm(
input clock,
input reset,
input [7:0] io_duty,
input [7:0] io_period,
output io_output
);
reg [7:0] context_; // #[Pwm.scala 12:26]
reg output_; // #[Pwm.scala 13:25]
wire [8:0] sum = context_ + io_duty; // #[Pwm.scala 15:20]
wire [8:0] _GEN_2 = {{1'd0}, io_period}; // #[Pwm.scala 17:15]
wire _T = sum >= _GEN_2; // #[Pwm.scala 17:15]
wire [8:0] _context_T_1 = sum - _GEN_2; // #[Pwm.scala 18:24]
wire [8:0] _GEN_0 = sum >= _GEN_2 ? _context_T_1 : sum; // #[Pwm.scala 17:29 18:17 21:17]
wire [8:0] _GEN_4 = reset ? 9'h0 : _GEN_0; // #[Pwm.scala 12:{26,26}]
assign io_output = output_; // #[Pwm.scala 25:15]
always #(posedge clock) begin
context_ <= _GEN_4[7:0]; // #[Pwm.scala 12:{26,26}]
if (reset) begin // #[Pwm.scala 13:25]
output_ <= 1'h0; // #[Pwm.scala 13:25]
end else begin
output_ <= _T;
end
end
endmodule
Note that in the code context_ is set to 0 when reset is high but it is not initialized that way.
Is there an emission argument that allows registers to be initialized with the RegInit value?

In Chisel 3, RegInit is referring to a register with reset. There is experimental support for treating an asynchronous reset line as an "initial" line instead, but I want to caution that it's not something I would recommend using in typical digital design.
As you are probably aware, initial values are not universally supported in actual hardware. They are supported by some (but not all) FPGAs, and are not supported at all in ASICs. Thus writing code that relies on initial values is inherently unportable which runs counter to the ethos of Chisel for constructing resuable hardware generators.
That being said, they can make certain designs use resources on certain FPGAs much more efficiently, so we do have a way to do this:
// RequireAsyncReset makes the implicit reset Async because the default is Sync (only for top-level module)
// Only AsyncReset can be emitted as an initial value
class Pwm(bitWidth: Int) extends Module with RequireAsyncReset {
val io = IO(new Bundle {
val duty = Input(UInt(bitWidth.W))
val period = Input(UInt(bitWidth.W))
val output = Output(Bool())
})
val context = RegInit(0.U(bitWidth.W))
val output = RegInit(false.B)
val sum = Wire(UInt(bitWidth.W + 1))
sum := context +& io.duty
when (sum >= io.period) {
context := sum - io.period
output := true.B
} otherwise {
context := sum
output := false.B
}
io.output := output
// Experimental API
annotate(new ChiselAnnotation {
def toFirrtl = firrtl.annotations.PresetAnnotation(reset.toTarget)
})
}
I've tweaked your design to use async reset and used the experimental support for emitting initial values. (Scastie: https://scastie.scala-lang.org/rQtHVUCZROul4i1uEjClPw)
This is using Chisel v3.5.0. There is an important bug that was recently fixed (fix to be released in v3.5.1), and there is active discussion on how to expose this experimental API directly in Chisel without having to use FIRRTL annotations: https://github.com/chipsalliance/chisel3/pull/2330.

Related

How to use this built-in shiftRegister from Chisel3.util properly?

I tried to compare this built-in shiftRegister with some common shift registers in the chisel-tutorial. But this one seems not actually shifting the bits? https://github.com/freechipsproject/chisel3/blob/9f620e06bacc2882068adfd4972ec2e9a87ea723/src/main/scala/chisel3/util/Reg.scala#L33
class MyShiftRegister_chisel[T <: Data](val init: Int = 1) extends Module {
val io = IO(new Bundle {
val in = Input(Bool())
val out = Output(UInt(4.W))
})
val state = ShiftRegister(io.in, 1, true.B)
// val next_state = RegNext(UInt(4.W), state)
// val nextState = Cat(state(2,0), io.in)
// state := nextState
io.out := state
}
println(getVerilog(new MyShiftRegister_chisel()))
And I got the following verilog:
[info] [0.000] Elaborating design...
[info] [0.070] Done elaborating.
Total FIRRTL Compile Time: 28.7 ms
module MyShiftRegister_chisel(
input clock,
input reset,
input io_in,
output [3:0] io_out
);
reg state; // #[Reg.scala 15:16]
reg [31:0] _RAND_0;
assign io_out = {{3'd0}, state}; // #[cmd94.sc 11:10]
`ifdef RANDOMIZE_GARBAGE_ASSIGN
`define RANDOMIZE
`endif
`ifdef RANDOMIZE_INVALID_ASSIGN
`define RANDOMIZE
`endif
`ifdef RANDOMIZE_REG_INIT
`define RANDOMIZE
`endif
`ifdef RANDOMIZE_MEM_INIT
`define RANDOMIZE
`endif
`ifndef RANDOM
`define RANDOM $random
`endif
`ifdef RANDOMIZE_MEM_INIT
integer initvar;
`endif
initial begin
`ifdef RANDOMIZE
`ifdef INIT_RANDOM
`INIT_RANDOM
`endif
`ifndef VERILATOR
`ifdef RANDOMIZE_DELAY
#`RANDOMIZE_DELAY begin end
`else
#0.002 begin end
`endif
`endif
`ifdef RANDOMIZE_REG_INIT
_RAND_0 = {1{`RANDOM}};
state = _RAND_0[0:0];
`endif // RANDOMIZE_REG_INIT
`endif // RANDOMIZE
end
always #(posedge clock) begin
state <= io_in;
end
endmodule
So my question is, how to properly use this built-in shiftRegister from Chisel3.util?
From your link with the ScalaDoc comment:
/** Returns the n-cycle delayed version of the input signal.
*
* #param in input to delay
* #param n number of cycles to delay
* #param en enable the shift
*
* #example {{{
* val regDelayTwo = ShiftRegister(nextVal, 2, ena)
* }}}
*/
def apply[T <: Data](in: T, n: Int, en: Bool = true.B): T = { ...
The ShiftRegister delays the input data in, n cycles. It is generic as to the type being shifted in and out. I suspect you're referring to the stereotypical shift register which shifts in and out 1 bit of data per-cycle. You can easily do that with this construct by making the input type Bool:
class Foo extends Module {
val io = IO(new Bundle {
val in = Input(Bool())
val out = Output(Bool())
})
io.out := ShiftRegister(io.in, 4)
}
Gives
module Foo(
input clock,
input reset,
input io_in,
output io_out
);
reg _T; // #[Reg.scala 15:16]
reg [31:0] _RAND_0;
reg _T_1; // #[Reg.scala 15:16]
reg [31:0] _RAND_1;
reg _T_2; // #[Reg.scala 15:16]
reg [31:0] _RAND_2;
reg _T_3; // #[Reg.scala 15:16]
reg [31:0] _RAND_3;
assign io_out = _T_3; // #[main.scala 13:10]
// ...
always #(posedge clock) begin
_T <= io_in;
_T_1 <= _T;
_T_2 <= _T_1;
_T_3 <= _T_2;
end
endmodule
Note that the construct hides the underlying flops from you, it returns the output of the final flop which is the "shifted out value" each cycle.

Questa dont detect warning concerning always_comb

I have a simple module:
module always_comb_error_ex
(
input logic a, b,
output logic y, z
);
// Error (10166): SystemVerilog RTL Coding error at always_comb_error_ex.sv(13): always_comb
// construct does not infer purely combinational logic
// Info (10041): Inferred latch for "z" at always_comb_error_ex.sv(17)
// Info (10041): Inferred latch for "y" at always_comb_error_ex.sv(17)
always_comb begin
if (a > b) begin
y = 1;
z = 0;
end
else if (a < b) begin
// y = 0; // missing output will create latch
z = 1;
end
// else begin // missing 'else' block will create latch
// y = 1;
// z = 1;
// end
end
endmodule
Since I'm using always_comb I should have some warning about latches.. but there is no warning by using Questa 10.7b
The tcl sctipt for compilation:
set work work
vlib -type directory $work
vlog -work $work +acc -sv -vopt -O5 +incdir+./ ../src/sv_test.sv
exit
Not all errors can be caught by simple parsing of the code, which is what vlog does. Some errors/warning will not show up until elaboration, which is vsim

Streaming operators usage in the context of serializers in PHY

I have 8:1 serializers and de-serializers based on the data width in our RTL code.As of now we are using for loops for the data path loading and data path reading from the serializers. Can we use streaming operators for this functionality.
Iam new to the streaming operators so exactly i am not getting how to use them in this context.
input [8*DATA_WIDTH-1:0] data_from_user; //WRITE DATA
output [8*DATA_WIDTH-1:0] data_to_user; //READ DATA
output [7:0] data_to_phy_serializer [DATA_WIDTH-1:0];
input [7:0] data_from_phy_deserializer [DATA_WIDTH-1:0];
//WRITE DATA PATH FLOW
always#(posedge clk) begin:WRITE_PATH
for(i = 0 ; i < DATA_WIDTH ; i = i+ 1 )
data_to_phy_serializer[i] = '{
data_from_user[DATA_WIDTH*7 + i],
data_from_user[DATA_WIDTH*6 + i],
data_from_user[DATA_WIDTH*5 + i],
data_from_user[DATA_WIDTH*4 + i],
data_from_user[DATA_WIDTH*3 + i],
data_from_user[DATA_WIDTH*2 + i],
data_from_user[DATA_WIDTH*1 + i],
data_from_user[DATA_WIDTH*0 + i]
} ;
end
//READ DATA PATH FLOW
always#(posedge clk) begin:READ_PATH
for(j= 0 ; j < DATA_WIDTH ; j = j + 1)begin
{
data_to_user[j+DATA_WIDTH*7],
data_to_user[j+DATA_WIDTH*6],
data_to_user[j+DATA_WIDTH*5],
data_to_user[j+DATA_WIDTH*4],
data_to_user[j+DATA_WIDTH*3],
data_to_user[j+DATA_WIDTH*2],
data_to_user[j+DATA_WIDTH*1],
data_to_user[j+DATA_WIDTH*0]
} <= #TCQ data_from_phy_deserializer[j] ;
end
input will be in the form of 8 data words concatenated and i need to the send the data to PHY of each data bit separately by picking up that elements correspondingly from the input data.
this code is working fine but only doubt is can i use streaming operators in this context . Please don't tell the basics of streaming operators, like its for packed to unpacked conversions and viceversa. I need to stream the data for PHY . if i can use streaming operators in this context it will help me so much.
example code for write data path of 4 bit data width to 8:1 serializers
//write data for data width of 4
assign [8*4 -1:0] data = {4'hF,4'hE,4'hD,4'hC,4'hB,4'hA,4'h9,4'h8};
//so now data to each data bit serializer will be
//8:1 data for serializers of
// bit-- 3-- 2-- 1-- 0
// 4'b___1___1___1___1
// 4'b___1___1___1___0
// 4'b___1___1___0___1
// 4'b___1___1___0___0
// 4'b___1___0___1___1
// 4'b___1___0___1___0
// 4'b___1___0___0___1
// 4'b___1___0___0___0
// data for serializer of bit 0 is 8'b10101010
// data for serializer of bit 1 is 8'b11001100
// data for serializer of bit 2 is 8'b11110000
// data for serializer of bit 3 is 8'b11111111
assign [7:0] data_to_phy_serializers [3:0] = '{
8'b11111111,
8'b11110000,
8'b11001100,
8'b10101010
};
Yes you can use it in both cases.I guess this will work:
data_to_phy_serializer = {>>{data_from_user}};
and
data_to_user <= #TCD {>>{data_from_phy_deserializer}};
I have a small experimental example here which you can play with.
module ab;
logic [3:0][1:0]a;
logic [3:0]b[1:0];
logic [3:0][1:0]c;
initial begin
a = 8'hAB;
b = {>>{a}};
c = {>>{b}};
$displayh(a,b[1],b[0],c);
end
endmodule

SystemVerilog error in multiplexing channels : nonconstant index into instance array

I'm designing a module that accepts multiple channels and outputs one channel.
Each channel consists of valid signal and data of some widths.
If a channel has valid data, the module should output that channel. If multiple channels have valid data, the module should output one of them (in my case, channel with highest index) and rests are dropped.
My simple implementation looks like this:
module test1 #(
parameter NUM_CHANNEL = 8,
parameter DATA_WIDTH = 512
) (
input logic [DATA_WIDTH - 1 : 0] data_in [NUM_CHANNEL],
input logic valid_in [NUM_CHANNEL],
output logic [DATA_WIDTH - 1 : 0] data_out,
output logic valid_out
);
always_comb begin
valid_out = 0;
for (int i = 0; i < NUM_CHANNEL; ++i) begin
if (valid_in[i]) begin
valid_out = 1;
data_out = data_in[i];
end
end
end
endmodule
This works perfectly in both simulation and real circuit (FPGA).
However, channel can be complex type so I used interface like this:
interface channel #(
parameter DATA_WIDTH = 512
);
logic valid;
logic [DATA_WIDTH - 1 : 0] data;
modport in (
input valid,
input data
);
modport out (
output valid,
output data
);
endinterface // sub_csr_if
module test #(
parameter NUM_CHANNEL = 8,
parameter DATA_WIDTH = 512
) (
channel.in in[NUM_CHANNEL],
channel.out out
);
always_comb begin
out.valid = 0;
for (int i = 0; i < NUM_CHANNEL; ++i) begin
if (in[i].valid) begin
out.valid = 1;
out.data = in[i].data;
end
end
end
endmodule
Then, this code gets Nonconstant index into instance array 'sub_port'. error in ModelSim, and i is not a constant error in Quartus.
If I unroll the loop, it works but it becomes non-parametric code. (only works for fixed NUM_CHANNEL)
Why the latter one does not work, while the first one works flawlessly?
An array of instances (module or interface) is not a true array type. As your error message indicates, you cannot select a particular instance with a variable index. With a true array, every element is identical. Because of the way parameterization, defparam, and port connections work, each instance element could have differences. The elaboration process essentially flattens all hierarchy before simulation begins.
What you can do is use a generate construct to select your instance as follows
;
module test #(
parameter NUM_CHANNEL = 8,
parameter DATA_WIDTH = 512
) (
channel.in in[NUM_CHANNEL],
channel.out out
);
logic _valid[NUM_CHANNEL];
logic [DATA_WIDTH - 1 : 0] _data[NUM_CHANNEL];
for (genvar ii=0;ii<NUM_CHANNEL;ii++) begin
assign _valid[ii] = in[ii].valid;
assign _data[ii] = in[ii].data;
end
always_comb begin
out.valid = 0;
for (int i = 0; i < NUM_CHANNEL; ++i) begin
if (_valid[i]) begin
out.valid = 1;
out.data = _data[i];
end
end
end
endmodule

Assign vec to UInt ports

if I have a io port which is io.myoutput = UInt(width = 840)
Then I have a val a = vec.fill(140){UInt(width = 6)}
How do i assign the entire a vec into the output port? I tried for loop with
for (i = 0 until 140){
io.myoutput(i*6+5,i*6) := a(i)}
But it gives me
finished inference (1)
start width checking
finished width checking
started flattenning
finished flattening (2)
Lbi.scala:37: error: reassignment to Node in class TutorialExamples.Lbi
Lbi.scala:37: error: reassignment to Node in class TutorialExamples.Lbi
Lbi.scala:37: error: reassignment to Node in class TutorialExamples.Lbi
Thanks
val x = Vec.fill(140){UInt(1, width=6)}
io.myoutput := x.toBits
The "toBits" method is what you want. It flattens a Vec into its raw bits.
I'm not sure exactly what is causing the error message, but in general, you can't really reassign to specific bits in a wire in Chisel.
val y = Bits(0,width=32)
y(1) := UInt(0)
y(3) := UInt(3)
etc.
That will throw an error.