How to change input signal to parameter in systemverilog? - verilog

I have an input logic sequence and I would like to convert it to a parameter in order to add it elsewhere in my program.
For example,
module myModule(input logic[7:0] SW, output logic[7:0] LEDR);
parameter shift = SW;
assign LEDR = SW[shift + 1: shift];
endmodule
I know that's not correct syntax, I just wanted to get the main idea.

Parameters are by definition compile time constants. That means you can not change their value based on an expression that can change over time.
What you can do is change the way you model so it does not require a parameter. For example , you could write your code as
module myModule(input logic[7:0] SW, output logic[7:0] LEDR);
assign LEDR = SW[SW +: 2];
endmodule

You cannot convert a variable to parameter. The value of the parameter will be locked after elaborations. A variable will not have a value until simulation.
Part-select (sometimes called range-slice) should do what you need. See
Indexing vectors and arrays with +: for more info.
Having SW slice itself does make sense since the resulting value would always be 0. Here is better example:
module myModule(input [8:0] IN, input [2:0] SW, output [1:0] LEDR);
assign LEDR = IN[SW +: 2];
endmodule

Related

Output is in undefined state

Image. I am trying to solve a problem that was written below. I confused why my output was in undefined state.
A "population count" circuit counts the number of '1's in an input vector. Build a population count circuit for a 255-bit input vector.
module top_module(
input [254:0] in,
output [7:0] out );
reg [7:0] counter=8'b0;
reg [7:0] counter_next=8'b0;
always # (*)
begin
counter=counter_next;
end
always # (*)
begin
for (int i=0; i<$bits(in);i++)
counter_next=counter+in[i];
end
assign out=counter;
endmodule
confused why my output was in undefined state.
All HDL variables are undefined ('X' or 'U') until you give them a value.
Then, you add a value to that undefined value counter_next=counter+in[i]; which still gives undefined. So it stays that way.
Also you are using 'counter=counter_next' which suggest you have seen some existing HDL code and you are trying to copy it, but you do not understand why it is implemented that way. The 'next' system is used when there is a clock. You do not have a clock and as such it is superfluous here.
The code you are looking for is probably something like this:
output reg [7:0] out
always #( * )
begin
out = 0;
for (int i=0; i<$bits(in);i++)
out =out+in[i];
end
Note that I am not using an extra variable counter here. All I do is make 'out' a reg type so I can use it directly.

How to use the input's values in "always" definiton in Verilog

I got the problem with using the input's value in Verilog.
I write:
module reg_vector (INPUT, ICLK, IENBL, NR, OUT);
parameter k = 6;
parameter n = 3;
input [(8*k)-1:0] INPUT;
input ICLK;
input IENBL;
input [n-1:0] NR;
reg [n-1:0] temp;
output reg [7:0] OUT;
always# (temp, posedge ICLK)
begin
if (IENBL)
begin
OUT = INPUT[temp*8 : temp*8+8];
end
end
endmodule
But got the error:
Error (10734): Verilog HDL error at reg_vector.v(25): temp is not a
constant
How should I fix it?
Thank you)
INPUT[temp*8 : temp*8+8] does not work because the : range syntax requires both sides to be a constant.
What you want is to use the +: array slicing: INPUT[temp*8 +: 8]
The left hand side of +: allows variables and represents the starting index. The right hand side is the width and must be a constant. For more on +: see Indexing vectors and arrays with +:
Other issues:
Remove temp from the sensitivity list.
temp needs to be assigned to something
OUT should be assigned with non-blocking (<=) not blocking (=) since it is sequential logic.
always #(posedge ICLK) // no temp in sensitivity list
begin
if (IENBL)
begin
OUT <= INPUT[temp*8 +: 8]; // non-blocking and +:
end
end
Even if your vector is always 1 byte wide, the tool understands it as a variable size and it does not know how to deal with it. (you also inverted the indexes temp*8 and temp*8+8 in the vector selection)
Another way to do it is to use the shift operator
OUT = INPUT >> (temp*8);
This should work as OUT will take the lower 8bits of the shifting by 8*temp of INPUT

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];

How do you manipulate input arrays in an always block (verilog)?

I'm very new to verilog and i'm just starting to understand how it works.
I want to manipulate an input to a module mant[22:0], in an always block but I am not sure how to go about it.
module normalize(mant,exp,mant_norm,exp_norm);
input [22:0]mant;
input [7:0]exp;
output [22:0]mant_norm;
output [7:0]exp_norm;
reg mantreg[22:0];
reg count=0;
always#(mant or exp)
begin
mantreg<=mant; //this gives an error
if(mant[22]==0)
begin
mant<={mant[21:0],1'b0};//this also gives an error
count<=count+1;
end
end
endmodule
so i have to shift the mant register if the bit22 is zero and count the number of shifts. I am so confused about when to use reg and when to use wire and how to do the manipulation. please help let me know how to go about it.
As you can see in your code you are assigning vector value (mant) to array of 23(mantreg). Instead you should declare mantreg as reg [22:0] mantreg (which is vector of 23 bit).
Wire type variable can not be assigned procedurally. They are used only in continues assignment. Other way around reg varible can only be procedural assigned.
For that try to read out LRM of Verilog .

How to write a module with variable number of ports in Verilog

I would like to write a module with a variable number of inputs, i.e. depending on some parameter, the result would be:
module my_module #(LENGTH)(
input clk,
input rst_n,
input [LENGTH-1:0] data_1
);
//...
endmodule
or
module my_module #(LENGTH)(
input clk,
input rst_n,
input [LENGTH-1:0] data_1,
input [LENGTH-1:0] data_2,
input [LENGTH-1:0] data_3
);
//...
endmodule
Would it be possible to do this in Verilog or Systemverilog or would I have to write a script, let's say in Python, in order to generate the code for a specific module with fixed number of inputs? (it might be more than 1000 inputs)
There are no variable number of ports in SystemVerilog, but you could use a port that is a parameterized array.
module my_module #(int LENGTH, DEPTH)(
input clk,
input rst_n,
input [LENGTH-1:0] data[DEPTH]
);
//...
endmodule
Otherwise, you would need to use a script to generate the code.
Use a two dimensional input with a parameterized size. Added a generate for loop that can be used to set signals individually. Although many operations can be done with smart array operations.
module my_module #(SIZE, LENGTH)(
input clk,
input rst_n,
input [SIZE-1:0][LENGTH-1:0] data_in_array,
output [SIZE-1:0][LENGTH-1:0] data_out_array
);
genvar N;
generate for (N=0; N<SIZE; N++) begin :la_coolOps
//Do cool operations here. For example instantiate a module for every data_in
end
//...
endmodule
Edit:
As Mehran Torki points out: The syntax above will work for SystemVerilog only. Verilog does not allow for multiple packed arrays. Use input [LENGTH*SIZE-1:0] data_in_array.
I would add to these other answers that ports are just groupings of wires. While having 3, 1-bit wires named a, b, and c might be easier to read and understand, there is no physical/logical difference between a single, 3-bit wire abc, where abc[0] corresponds to a, abc[1] corresponds to b, and abc[2] corresponds to c.
So, you can always just expand or shrink a single (or multiple) signal(s) to get however many bits you need. It may not be as neat, but it will work. In the receiving module, you can then part-select the bus in whatever manner you like. So, you could have one really long wire the shrinks or expands (wire [(SOME_PARAM*8)-1:0] my_input_wire), or with SystemVerilog an array (wire [7:0] my_input_wire[0:SOME_PARAM-1])
If this is just testbench/verification code, the other thing you could do in SystemVerilog is use a dynamic array
As others said, there is no direct way to do this, but another workaround is to use SystemVerilog interfaces, where you define all the inputs that you want in the interface definition and inside the module only use the ones that correspond to the parameter. Below is a sample:
module my_module #(LENGTH)(
input clk;
input rst_n;
output o;
interface i_data;
);
logic outValue;
generate
case (LENGTH) //Based on the value of LENGTH, use corresponding data
1: outValue = i_data.data_1;
2: outValue = i_data.data_1 + i_data.data_2;
3: outValue = i_data.data_1 + i_data.data_2 + i_data.data_3;
endcase
endgenerate
always #(posedge clk) begin
if (~rst_n)
o <= '0;
else
begin
o <= outValue;
end
endmodule
You can still use a parameterized array for data and a for-generate loop if your outputs are similar.
With System verilog we can import a package instead of having parameterization and define types in the package to be used in the portlist.
module mymodule
import mymodule_pkg::*;
(
input portlist_t portlist
);
endmodule
And define multiple copies of the package with different variants of the port list and compile whichever version is required. eg
package mymodule_pkg;
localparam LENGTH=5;
typedef struct packed {
logic [LENGTH-1:0] data_1,
logic [LENGTH-1:0] data_2,
logic [LENGTH-1:0] data_3
} portlist_t;
endpackage
As with the interface solution there will be situations where you run into issues, like having different iterations of the module instantiated together.

Resources