Does casez consider wires assigned z as high impedance during synthesis? - verilog

I am designing a R3000 MIPS processor, and for the instruction decoder, want to give a casez such that for cases involving immediate instructions eg ADDI, ANDI, I provide the bits 6:0 as z. I just want to know here {opcode, func} does it get synthesized to a high impedance open connection when the case is z?
module Instr_decoder (
input logic [31:0] instr,
output logic regDest,
output logic jump,
output logic branch,
output logic memtoReg,
output logic memRead,
output logic memWrite,
output logic ALUSrc,
output logic signExtendInstruction,
output logic immediateInstruction,
output logic regWrite);
logic immediate_i;
logic [5:0] opcode;
logic [4:0] rs;
logic [4:0] rt;
logic [4:0] rd;
logic [15:0] immediate_data;
logic [4:0] shamt;
logic [5:0] func;
logic [25:0] target;
assign opcode = instr[31:26];
assign shamt = instr[10:6];
assign func = instr[5:0];
assign target = instr[25:0];
assign immediate_i = (opcode == (ADDI || ANDI || ORI || SLTI || XORI));
always_comb
begin
casez({opcode, func}
{6'h00, 6'h20} : ADD = 1;
{6'h08, 6'dz} : ANDI = 1;

Anything you can compile and execute on a simulator is potentially synthesizable. It comes down to whether or not the tool you are using has an algorithm to recognize the code and map it to a hardware implementation.
BTW, one typically uses the ? character instead of z in a Verilog numeric literal to represent a don't care value in a casez statement.

Related

Is the array part select +: with variable start synthesizable by Vivado?

If I have a vector and I want to read a part of it starting somewhere. Can I use the syntax vector[staring_point +: output_length] with starting_point being an integer? Is it synthesizable?
If I write a code like this:
module my_mod(
input logic din,
input logic clk,
input logic[2:0] start_ptr,
output logic[3:0] dout);
logic[10:0] vector = 0;
always_ff#(posedge clk) vector <= {vector[9:0], din}; --shift register
always_comb dout <= vector[start_ptr +: 4];
endmodule
The design is just this and the input and output are bounded to GPIOs.
I'm expecting a mux for each output bit. Surprisingly Vivado will synthesize 1FF and 1LUTRAM that is an SRL16 so a shift register with integrated mux, but the primitive has only one output and the "dout" signal is driven only with the first bit.
The other 3bits are buffered to 0.
Is the syntax +: correct? Is that consistent or it's a bug of Vivado?
I cleaned code and built in Vivado 2020.2 As pointed out some outputs are inappropriately tied off in synthesis.
Cleaned up code:
module my_mod(
input logic din,
input logic clk,
input logic[2:0] start_ptr,
output logic[3:0] dout);
logic[10:0] vector;
always_ff#(posedge clk)
vector <= {vector[9:0], din}; //shift register
always_comb
dout = vector[start_ptr +: 4];
endmodule
And the RTL that the code infers:
Vivado is not doing the right thing (its a bug). This is worth reporting to Xilinx. The +: operator is capable of generating a mux/barrel shifter. How: Change the code to infer regs instead of SRL's (added a RTL reset) then it infers the design intent.
module my_mod(
input logic din,
input logic clk,
input logic[2:0] start_ptr,
input logic rst,
output logic[3:0] dout);
logic[10:0] vector;
always_ff#(posedge clk)
if(rst)
vector <= 0;
else
vector <= {vector[9:0], din}; //shift register
always_comb
dout = vector[start_ptr +: 4];
endmodule
To stay closer to what you posted (no reset) you can use the right shift operator. This also infers the mux as intended. This does not give an initial value of 0, in the reg, so you need to add the reset if you need an initial value.
module my_mod(
input logic din,
input logic clk,
input logic[2:0] start_ptr,
output logic[3:0] dout);
logic[10:0] vector;
always_ff#(posedge clk)
vector <= {vector[9:0], din}; //shift register
always_comb
dout = vector >> start_ptr ;
endmodule
Here is the RTL view of the design using the shift operator (>>).
At one point I was thinking Xilinx intended for the +: and -: operators to be used at elaboration time only, for example in a generate loop. If that were the case then Xilinx should state that in the synthesis guide UG901 (they do not). Also Vivado infers the combinational logic for a design with registers, why should it not work with SRL's?
To me its a bug.
Good catch.

Best way to optionally register inputs

I have a systemverilog module with a LOT of input signals of varying sizes. I want to optionally register them before use. Here is my desired criteria for the code that does this optional registering:
I should only need to write out the assignments once (no duplicate code)
I should not need to use any macros (I don't want scoping issues)
Here's a minimal reproducible example of my current solution:
module optional_register #(
parameter bit REGISTER_INPUTS=1
)(
input wire clk,
input wire a_in,
input wire b_in,
input wire c_in,
input wire d_in,
output logic a_out,
output logic b_out,
output logic c_out,
output logic d_out
);
function assign_inputs();
a_out <= a_in;
b_out <= b_in;
c_out <= c_in;
d_out <= d_in;
endfunction
generate if (REGISTER_INPUTS) begin
always_ff # (posedge clk)
assign_inputs();
end else begin
always_comb
assign_inputs();
end endgenerate
endmodule
This code synthesizes correctly in Vivado 2020.2 with both the registers on and off. But I am worried that the non-blocking assignments in the function are technically invalid, according to The IEEE Std for Verilog (1364-2001), section "10.3.4 Function rules" which states:
A function shall not have any nonblocking assignments.
So my concern is that this won't work in other synthesizers, and may cause unexpected behavior in simulation. Can anyone speak to this?
Any other ideas?
This is SystemVerilog code, you should be using the IEEE 1800-2017 LRM.
Nonblocking assignments are allowed inside function as long as LHS target is not a variable with an automatic lifetime. Do not use NBA to assign to argument outputs or the return value of a function with a static lifetime because their current values get copied out before the NBA updates happens.
You should declare your function with no return value.
function void assign_inputs();
Using NBAs in combinational logic is not the best for simulation performance, but is usually OK functionality wise.

What will the assign statements get synthesized as?

I am interested to know what will these lines synthesize to? I am designing a direct mapped cache and using assign to separate my index, offset and tag bits. Will it synthesize to a demultiplexer? I did not mention the whole code since I just want to know how the assign statements will look after synthesis. In 8085 programming, I had read the term as 'address demultiplexing" so it was confusing.
module cache
( input bit clk,
input bit rst,
input logic [15:0] address,
input logic valid_in,
input logic compare,
input logic wr,
input logic enable,
input logic write_through,
output logic dirty,
output logic [4:0] tag_out,
output logic [15:0] data_out,
output logic valid_out,
output hit
);
logic [7:0] index;
logic [1:0] offset;
logic [4:0] tag_in;
assign offset = address[1:0];
assign index = address[9:2];
assign tag_in = address[15:10];
endmodule
The above code will just simply get synthesized as wire's, since there are only assignments.
I am not sure what de-multiplexing logic you are trying to create, but generally for a de-multiplexer you need to have a select signal based on which you decode which output should be enabled.
An example for a 1:2 de-multiplexer logic is given below
module demux_1_2(
input [3:0] Q,
input Sel,
output reg [3:0] D1,
output reg [3:0] D2
);
always#(*)
begin
if(~Sel) begin
D1 = Q;
D2 = 0;
end else begin
D1 = 0;
D2 = Q;
end
end
endmodule
Since there are no Boolean or arithmetic operators on the RHS of the assign, these statements just become conveniently named references for part selects of the address input. This is the same thing that happens when you instantiate a module and connect to its ports - signals can go through a name change. In fact, you could have you could have written your address input port declaration as
input .address({tag_in,index,offset}),
You still connect the address port when instantiating this module, but inside the module, it only has tag_in, index, and offset available to reference, not address.
SystemVerilog has the alias construct to make it more obvious that you are just creating a convenient names for a signal, instead of declaring another set of signals and using the assign statement.
alias offset = address[1:0];
alias index = address[9:2];
alias tag_in = address[15:10];

illegal referance to net data in my inout datatype

I am new to verilog and I am writing a code in verilog for creating a memory block capable to read and write data. it has the following code
I tried all things written in some of the answers of similar type of questions but still I am getting an error.
module memory( wr_n , rst_n ,data ,clk ,add , en);
input wire wr_n;
input wire rst_n;
input wire clk;
input wire en;
parameter size = 255;
parameter n = 7;
inout wire [n:0] data;
input wire [n:0] add;
reg [n:0] mem [size:0];
integer i;
always #( posedge clk , negedge rst_n)
begin
if(!rst_n)
begin
for( i=0; i<=size; i=i+1 )
begin
mem[i] <= 8'hff;
end
end
else
begin
if(en)
begin
if(!wr_n) //read
data <= mem[add];
else //write
mem[add] <= data;
end
else
data = 8'h z;
end
end
endmodule
here when I use continuous assignment before data I get an error like
"LHS in procedural assignment may not be a net:data"
even if I have declared it as wire.
and yeah in my test bench I have declared data as reg type because when I declare it as net it shows again the
"Illegal reference to net error".
I am not able to fix it since long time..please help me out.
The inout port 'data' is of type wire. So, it cannot be used on the left hand side of the <= expression in a procedural block (always block and initial block).
So we should use continuous assignment statements like
assign data = (wr_n == 0)? mem[add]:n{1'bz};
The same holds true when we are driving any values on the inout port form the test bench. The signal connecting to the inout port from the test bench must be of type wire. And hence it should also be written using continuous assignment statements.
assign testbench_inout_signal = (wr_n == 0)? value_to_be_written :n{1'bz};
There is a better way of using an inout port, it should be isolated from the logic to avoid conflicts while reading and writing, remember whenever you use inout ports make sure the points mentioned in the link are satisfied.
One such solution is declare a temporary variable for reading and writing and
by using continuous assignment statement assign values to bidirectional port.
Following snippet will give you some more clearance of how the error can be avoided
reg [n:0] temp; // declare a variable and try to read and write with this variable
if(!wr_n) //read
temp <= mem[add];
else //write
mem[add] <= temp;
assign data = (wr_n==0)? temp : {n{1'bz}};
Remove the else part having data = 8'h z; there cannot be two else for single if statement as per LRM.

How can i make my verilog shifter more general?

Here i have a shifter but as of rite now it only works for up to 3 bits. I've been looking and i can't find out how to make it work for up to 8 bits.
module shifter(a,b,out);
input [7:0] a, b;
output [7:0] out;
wire [7:0] out1, out2, out3;
mux_8b_2to1 first(a[7:0], {a[3:0],a[7:4]}, b[2], out1);
mux_8b_2to1 second(out1[7:0], {out1[5:0],out1[7:6]}, b[1], out2);
mux_8b_2to1 third(out2[7:0], {out2[6:0],out2[7]}, b[0], out);
endmodule
What you have is a Barrel Shifter. Two ways to make it more generic are make it a functional model (still synthesis-able) or structural model with a generate block. Both approaches follow IEEE Std 1364-2001 (aka Verilog-2001).
The functional generic approach for a barrel shifter only needs a down-shifter. The general function is out = {in,in} >> (WIDTH-shift) where leftover bits can be ignored. To protect for double-roll (i.e. shift > WIDTH ), use the mod operator on the shift (WIDTH-(shift%WIDTH)).
module barrel_shifter_functional #( parameter CTRL=3, parameter WIDTH=CTRL**2 )
( input wire [WIDTH-1:0] in,
input wire [ CTRL-1:0] shift,
output wire [WIDTH-1:0] out );
assign out = {2{in}} >> (WIDTH-(shift%WIDTH));
endmodule
The structural generic approach for a barrel shifter needs a generate block. The for loop in the generate block will unravel at compile time, not run time like a for loop like in an always block. To keep it generic also have have the 2-to-1 mux have a parametrized width. FYI, you can use the generate block with functional code too, for example comment out the mux_2to1 instantiation and uncomment the assign statement below it. Learn more about the generate block by reading IEEE Std 1800-2012 ยง 27. Generate constructs.
module barrel_shifter_structeral #( parameter CTRL=3, parameter WIDTH=CTRL**2 )
( input wire [WIDTH-1:0] in,
input wire [ CTRL-1:0] shift,
output wire [WIDTH-1:0] out );
wire [WIDTH-1:0] tmp [CTRL:0];
assign tmp[CTRL] = in;
assign out = tmp[0];
genvar i;
generate
for (i = 0; i < CTRL; i = i + 1) begin : mux
mux_2to1 #(.WIDTH(WIDTH)) g(
.in0(tmp[i+1]),
.in1({tmp[i+1][WIDTH-(2**i)-1:0],tmp[i+1][WIDTH-1:WIDTH-(2**i)]}),
.sel(shift[i]),
.out(tmp[i]) );
// assign tmp[i] = shift[i] ? {tmp[i+1][WIDTH-(2**i)-1:0],tmp[i+1][WIDTH-1:WIDTH-(2**i)]} : tmp[i+1];
end : mux
endgenerate
endmodule
module mux_2to1 #( parameter WIDTH=8 )
( input wire [WIDTH-1:0] in0, in1,
input wire sel,
output wire [WIDTH-1:0] out );
assign out = sel ? in1 : in0;
endmodule
Both examples are functionally equivalent and synthesize provided CTRL is less than or equal to the ceiling of log2(WIDTH). Synthesis will likely give different results. The generate method will exclusively use 2-to-1 muxes while the pure functional method will depend on the quality of the optimizer.
Working example # http://www.edaplayground.com/s/6/500
I've used the >> and << operators to generate a synthetizable design using ISEWebPack, as this:
module shifter(
input wire [7:0] a,
input wire [7:0] b,
input wire leftright, // 0=shift right, 1=shift left
output reg [7:0] out
);
always #* begin
if (leftright==0)
out = a>>b;
else
out = a<<b;
end
endmodule
This way, the symthesis tool will know that you want to implement a shifter and can use its own macros to best synthetize it:
Synthesizing Unit <shifter>.
Related source file is "shifter.v".
Found 8-bit shifter logical right for signal <out$shift0002> created at line 30.
Found 8-bit shifter logical left for signal <out$shift0003> created at line 32.

Resources