Procedural Assignment not supported in System Verilog - verilog

I've written down this following "Design source" code (on Xilinx Vivado)
The code is written in System Verilog, and it is the Hamming 7,4 encoder
https://en.wikipedia.org/wiki/Hamming(7,4)
module eccproj(
input logic [3:0] data_in,
output logic [6:0] hamcode);
logic p1,p2,p4;
always #(*) begin
p1 = data_in[0] + data_in[1] + data_in[3];
p2 = data_in[0] + data_in[2] + data_in[3];
p4 = data_in[1] + data_in[2] + data_in[3];
// Input : d3 d2 d1 d0
//Output : d7 d6 d5 p4 d3 d2 d1
assign hamcode = {data_in[3:1] , p4 , data_in[0] , p2 , p1}; // Error on this line
end
endmodule
I am getting error in the line with the comment, and the error reads as follows :
[Synth 8-27] procedural assign not supported
I know that, in Verilog the above assignment works, but how to work it using System Verilog.
The above error line, must concatenate the input bits and parity bits at their corresponding positions*
It would be great if someone could suggest a way to get rid of the error.

It is unusual to use assign within an always block. You likely want to have the assign outside the always block to make your synthesis tool happy.
always #(*) begin
p1 = data_in[0] + data_in[1] + data_in[3];
p2 = data_in[0] + data_in[2] + data_in[3];
p4 = data_in[1] + data_in[2] + data_in[3];
// Input : d3 d2 d1 d0
//Output : d7 d6 d5 p4 d3 d2 d1
end
assign hamcode = {data_in[3:1] , p4 , data_in[0] , p2 , p1};

You do not need the assign keyword inside a combinational block
module eccproj(
input logic [3:0] data_in,
output logic [6:0] hamcode);
logic p1,p2,p4;
always_comb begin
p1 = data_in[0] + data_in[1] + data_in[3];
p2 = data_in[0] + data_in[2] + data_in[3];
p4 = data_in[1] + data_in[2] + data_in[3];
// Input : d3 d2 d1 d0
//Output : d7 d6 d5 p4 d3 d2 d1
hamcode = {data_in[3:1] , p4 , data_in[0] , p2 , p1};
end
endmodule

Related

"Not a valid l-value" Error in Verilog

I am new to Verilog (and, to a lesser extent, programming) and am trying to create a program that finds the absolute value of a set of numbers and then calculates for a running average. The running average is 5 points wide, and goes across a data set that is about 40 numbers wide.
I am having trouble with the running average (lines 14-17 design, 24-28 test-bench) and am receiving the errors "o2/out is not a valid l-value in tb.avg." and "o2/out is declared here as a wire". How should I fix this?
Here is my design:
module absolute_value(i1,o1);
input signed [11:0] i1;
output signed [11:0] o1;
assign o1 = i1[11] ? -i1 : i1;
endmodule
module moving_average(k1,k2,k3,k3,k4,o2,out);
input k1, k2, k3, k4, k5;
output [11:0] o2;
output [11:0] out;
integer t;
always begin
assign o2 = (k1 + k2 + k3 + k4 + k5) / 5;
assign out = o2;
end
endmodule
And here is my test-bench:
module tb;
reg signed [11:0] i1;
wire signed [11:0] o1;
reg k1;
reg k2;
reg k3;
reg k4;
reg k5;
wire [11:0] o2;
wire [11:0] out;
absolute_value abs(i1,o1);
moving_average avg(k1,k2,k3,k4,k5,o2,out);
integer t;
initial begin
for (t = -10; t < 30; t = t + 1) begin
#1
i1 <= t;
$display("i1 = %d, o1 = %d", i1, o1);
assign k5 = k4 ? k4 : o1;
assign k4 = k3 ? k3 : o1;
assign k3 = k2 ? k2 : o1;
assign k2 = k1 ? k1 : o1;
assign k1 = o1;
$display("out = %d", out);
$moniter($time, "i1 = %d, o1 = %d, o2 = %d, out = %d k1 = %d, k2 = %d, k3 = %d, k4 = %d, k5 = %d", i1, o1, o2, out, k1, k2, k3, k4, k5);
end
end
endmodule
I'd bet that there are other errors in my program too, so any help is much appreciated.
As mentioned in the comments:
Remove the always and keep the output [11:0] out
or
Change to:
reg [11:0] o2;
reg [11:0] out;
always #( * )
begin
o2 = (k1 + k2 + k3 + k4 + k5) / 5;
out = o2;
end
Second error:
Your port uses k1, k2, k3, k3, k4 and is missing k5.
Thirdly: please don't use the port style from last century. I advise you to switch to the new format:
module moving_average(
input k1, k2, k3, k4, k5,
output signed [11:0] o2,out
);
Or for the second case: output signed reg [11:0] o2,out
Fourth: it is $monitor, not $moniter

Pipelining a verilog module consisting 10 components connected in series

I am trying to pipeline a module which consists of 5 multipliers and 5 adders connected in series. The module is a polynomial calculator. Without pipelining the module is working perfectly so far.
multipliers [31:0] m0,m1,m2,m3,m4; // separate module
adders [31:0] a0,a1,a2,a3,a4; // separate module
user_input [31:0] input; // register
constants [31:0] c0,c1,c2,c3,c4; // registers
pipeliners [31:0] p0,p1,p3,p4,p4; // pipelining resisters
wires [31:0] w0,w1,w2,w3,w4; // wires
Without pipelining the structure looks like following,
[input]*[c0] => w0 => [w0]+[c1] => w1 => [w1]*[input] => w2 => [w2]+[c2] => w3 ... //goes on like this
As all of them are connected in series, the critical path consists of 10 components.
My implemented pipelining idea is following,
[input]*[c0] => w0 => p0 => [p0]+[c1] => w1 => p1 => [p1]*[input] => w2=> p2 => [p2]+[c2] => w3 ... //goes on like this
I have an error, "cannot be driven by primitives or continuous assignment."It is due to p0,p1,p3 ... registers. Converting them into wire solves the error but then they are not registers anymore. I am using iverilog as compiler.
My question is, how can I do the pipelining so that I get the output using least possible clock cycles and resolve the error as well?
******* Edited version with code *******
`timescale 1ns / 1ps
module poly (
clk,
q,
result
);
input clk;
input [31:0] q; //user input
output [31:0] result;
reg [31:0] c,c0,c1,c2,c3,c4;
reg [31:0] p, p0, p1, p2, p3, p4, p5, p6,p7,p8,p9,p10,p11,p12;
always #(q)
if (q>=32'h08000000 && q<32'h0A000000) begin
c <= 32'h058B90C0;
c0 <= 32'h74599F60;
c1 <= 32'h79481740;
c2 <= 32'h445B7440;
c3 <= 32'h5AF892E0;
c4 <= 32'h9E2C2258;
end else if (q>=32'h0A000000 && q<32'h0C000000)
begin
c <= 32'h258B90C0;
c0 <= 32'hFB942240;
c1 <= 32'h21558EC0;
c2 <= 32'h5D882000;
c3 <= 32'h75F846E8;
c4 <= 32'hF48F5786;
end
wire [31:0] x0,x1,x2,x3,x4;
wire [31:0] y0,y1,y2,y3,y4;
multiplier m4 (.i_multiplicand(q),.i_multiplier(c4),.o_result(x4));
assign = x4;
adder a4 (.a(p0),.b(c3),.c(y4));
assign p1 = y4;
assign p2 = q;
multiplier m3 (.i_multiplicand(p2),.i_multiplier(p1),.o_result(x3));
assign p3 = x3;
adder a3 (.a(p3),.b(c2),.c(y3));
assign p4 = y3;
assign p5 = q;
multiplier m2 (.i_multiplicand(p5),.i_multiplier(p4),.o_result(x2));
assign p6 = x2;
adder a2 (.a(p6),.b(c1),.c(y2));
assign p7 = y2;
assign p8 = q;
multiplier m1 (.i_multiplicand(p8),.i_multiplier(p7),.o_result(x1));
assign p9 = x1;
adder a1 (.a(p9),.b(c0),.c(y1));
assign p10 = y1;
assign p11 = q;
adder a0 (.a(p10),.b(p11),.c(y0));
assign p12 = y0;
multiplier m0 (.i_multiplicand(p12),.i_multiplier(c),.o_result(x0));
assign result = x0;
endmodule
As Morgan already stated you get only registers if you have a reg and a clock.
always #(posedge clk)
begin
p1 <= y4;
p2 <= q;
// etc.
end
Which if you think about it is rather obvious as this is a register:
Which as you can see has as input a signal and a clock.

Unusual behavior of verilog code

I am writing one simple asynchronous sequence detector, but i am getting unusual result at one point. Code is working fine with "assign a8 = ((y2&&inp1&&~inp2)||(y1&&inp1)); " but if i replace above line with following lines in my code its not giving the correct result.
assign a6 = (y2&&inp1&&~inp2);
assign a5 = (y1&&inp1);
assign a8 = a6||a5;
Both are technically the same but i am not able to understand why output is not coming correct when i use above lines of code.
module Async_Design(inp1,inp2,outp);
input inp1,inp2;
output outp;
wire y1 ,y2;
/*assign a6 = (y2&&inp1&&~inp2);
assign a5 = (y1&&inp1);
assign a8 = (a6||a5);*/
/*Uncommenting the above section and commenting below
line is not giving correct result*/
assign a8 = ((y2&&inp1&&~inp2)||(y1&&inp1));
Delay D1(y1,a8);
nand(a1,y1,1'b1);
nand(a2,a1,inp1);
nand(a3,a2,1'b1);
nand(a4,a3,inp2);
nand(a5,a4,1'b1);
Delay D2(y2,a5);
assign outp = y1;
endmodule
module Delay(q,inp);
output q;
input inp;
reg q;
initial
begin
q=1'b0;
end
always #(*)
begin
q=((inp&&1'b1)||(inp&&1'b1));
end
endmodule
/***********************************************/
TEST BENCH
/***********************************************/
module Async_Design_Test;
reg inp1,inp2;
wire outp;
reg[15:0] sequence1;
reg[15:0] sequence2;
integer i;
Async_Design Async(inp1,inp2, outp);
initial
begin
sequence1 = 16'b 0101_1111_0111_1111;
sequence2 = 16'b 1010_1010_1110_1111;
for( i = 0; i <= 15; i = i+1)
begin
inp1 = sequence1[i];
inp2 = sequence2[i];
#6
$display( " Input1 = ", inp1, " Input2 = ", inp2, " Output = ", outp,);
end
end
endmodule
Can anyone help me to understand this behavior as i am new to HDL coding
Your code after change is not valid one. Why?
assign a5 = (y1&&inp1);
...
nand(a5,a4,1'b1);
What you're trying to do is drive a5 wire in two different places (btw your compiler should print an error like "can't resolve multiple constant drivers for net a5"). And it won't work, since you can drive a wire only in one place. If you change one of this lines, e.g.:
assign a6 = (y2&&inp1&&~inp2);
assign a7 = (y1&&inp1);
assign a8 = (a6||a7);
you'll get the same output as if you use assign a8 = ((y2&&inp1&&~inp2)||(y1&&inp1)).
PS Consider usage of & and | operators.

Using created ALU to make a bigger one

I have a 8-bit ALU unit in verilog that can do addition, invert, etc. This single unit is tested and performs correctly. When I combine 4 of these to make a bigger ALU every output is correct except when I choose the addition operation it comes out as
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx01010101, basically the first alu does the work right then the output from the second is xxxxxxxx as is the third and fourth. This is really frustrating!!
the 8 bit module( it would be nice to point if this model is behavioral or structural model i go for the former!)
module alu_8bit(
output reg [7:0] out,
output reg cout,g,e,
input [7:0] A,B,
input cin,
input [2:0] S
);
//used functions
parameter BUF_A = 3'b000;
parameter NOT_A = 3'b001;
parameter ADD = 3'b010;
parameter OR = 3'b011;
parameter AND = 3'b100;
parameter NOT_B = 3'b101;
parameter BUF_B = 3'b110;
parameter LOW = 3'b111;
always #(A or B or S) begin
//Comparator
g = A>B;
e = A==B;
//Other selective functions
case(S)
BUF_A: out = A;
NOT_A: out = ~A;
ADD: {cout,out} = A+B+cin;
OR: out = A | B;
AND: out = A & B;
NOT_B: out = ~B;
BUF_B: out = B;
LOW: out = {8{1'b0}};
endcase
end
endmodule
Here is the code of the bigger one:
module alu_32bit(
output [31:0] out,
output cout,g,e,
input [31:0] A,B,
input cin,
input [2:0] S
);
wire e1,e2,e3,e4;
wire g1,g2,g3,g4;
alu_8bit ALU1(out[7:0],cin2,g1,e1,A[7:0],B[7:0],cin,S);
alu_8bit ALU2(out[15:8],cin3,g2,e2,A[15:8],B[15:8],cin2,S);
alu_8bit ALU3(out[23:16],cin4,g3,e3,A[23:16],B[23:16],cin3,S);
alu_8bit ALU4(out[31:24],cout,g4,e4,A[31:24],B[31:24],cin4,S);
assign g = g4 | (e4 & g3) |(e4 & e3 & g2) | (e4& e3 & e2 & g1);
assign e = e4 & e3 & e2 & e1;
endmodule
Can any one give some help?! if you need more info just tell me.
Edited:
Waveform pic clearly input comes in correct but output not
The dataflow diagram shows that ALU1 output is just fine
Your sensitivity list for the main part of the ALU doesn't include cin.

Verilog simulation gives x as output

I am trying to simulate the following circuit using veriwell. However, simulation results is giving me the value of each net as x. Since the circuit does not have any backward loop, I guess every net should have either 1 or 0 signals.
module dff (CK,Q,D);
input CK,D;
output Q;
wire NM,NCK;
wire NQ,M;
nmos N7 (M,D,NCK);
not P3 (NM,M);
nmos N9 (NQ,NM,CK);
not P5 (Q,NQ);
not P1 (NCK,CK);
endmodule
module s27(clk, in1, in2, GO, HO, AO, BO, CO, DO, EO, FO, a1, a2, a3, a4, o1, o2);
input clk, in1, in2;
output GO, HO, AO, BO, CO, DO, EO, FO, a1, a2, a3, a4, o1, o2;
wire AO, BO, CO, DO, EO, FO;
wire a1, a2, a3, a4;
wire o1, o2;
dff A(clk,AO,in1);
dff B(clk,BO,in2);
dff C(clk,CO,o1);
dff D(clk,DO,a1);
dff E(clk,EO,a2);
dff F(clk,FO,o2);
dff G(clk,GO,a3);
dff H(clk,HO,a4);
and AND2_1 (a1, AO, CO);
and AND2_2 (a2, CO, BO);
and AND2_3 (a3, AO, FO);
and AND2_4 (a4, FO, BO);
or OR2_1(o1, AO, BO);
or OR2_2(o2, DO, EO);
endmodule
I am using the following testbench (generated using a script):
`timescale 1ns/1ps
module testbench;
parameter sOutFileName = "beSimOut.txt";
parameter nVectorWidth = 3;
parameter nVectorSpace = 1000;
parameter nSimCycle = 10;
/* simulation memory */
reg [nVectorWidth - 1:0] mSimMemory [nVectorSpace - 1:0];
/* simulation vector */
reg [nVectorWidth - 1:0] vSimVector;
/* bench variables */
integer nOutFile, nIndex;
/* connection variable declarations */
wire clk, in1, in2, G0, H0, A0, B0, C0, D0, E0, F0, a1, a2, a3, a4, o1, o2;
/* drive inputs */
assign clk = vSimVector[2];
assign in1 = vSimVector[1];
assign in2 = vSimVector[0];
/* simulation memory population routine */
task populateSimulationMemory;
begin
for (nIndex = 0; nIndex < nVectorSpace; nIndex = nIndex + 1)
mSimMemory[nIndex] = { $random };
end
endtask
/* simulation */
initial
begin
/* start monitoring */
$monitor($time, ": clk = %b, in1 = %b, in2 = %b, GO = %b, HO = %b, AO = %b, BO = %b, CO = %b, DO = %b, EO = %b, FO = %b, a1 = %b, a2 = %b, a3 = %b, a4 = %b, o1 = %b, o2 = %b", clk, in1, in2, GO, HO, AO, BO, CO, DO, EO, FO, a1, a2, a3, a4, o1, o2);
/* populate simulation memory */
populateSimulationMemory;
/* open dump file */
nOutFile = $fopen(sOutFileName);
if (nOutFile == 0)
begin
$display("Can't open %s file for dumping. Exiting ...", sOutFileName);
$finish;
end
/* simulate inputs */
for (nIndex = 0; nIndex < nVectorSpace; nIndex = nIndex + 1)
#nSimCycle vSimVector = mSimMemory[nIndex];
#1 $fclose(nOutFile);
nOutFile = 0;
$finish;
end
/* instantiation */
s27 inst (.clk(clk), .in1(in1), .in2(in2), .GO(GO), .HO(HO), .AO(AO), .BO(BO), .CO(CO), .DO(DO), .EO(EO), .FO(FO), .a1(a1), .a2(a2), .a3(a3), .a4(a4), .o1(o1), .o2(o2));
/* dump */
always #(clk or in1 or in2 or GO or HO or AO or BO or CO or DO or EO or FO or a1 or a2 or a3 or a4 or o1 or o2)
if (nOutFile != 0)
$fdisplay(nOutFile, $time, ": clk = %b, in1 = %b, in2 = %b, GO = %b, HO = %b, AO = %b, BO = %b, CO = %b, DO = %b, EO = %b, FO = %b, a1 = %b, a2 = %b, a3 = %b, a4 = %b, o1 = %b, o2 = %b", clk, in1, in2, GO, HO, AO, BO, CO, DO, EO, FO, a1, a2, a3, a4, o1, o2);
endmodule
Any ideas on why I am not getting the correct output?
Thanks in advance.
The dff is not modeled correctly. With the current dff, M will float (high-Z) when CK is high.
dff should look like this:
not N1 (NCK,CK);
cmos C1 (M,D,NCK,CK);
cmos C2 (M,NNM,CK,NCK);
not N2 (NM,M);
not N3 (NNM,NM);
cmos C3 (NNQ,NNM,CK,NCK);
cmos C4 (NNQ,Q,NCK,CK);
not N3 (NQ,NNQ);
not N4 (Q,NQ);
or as nand gates:
nand DN1 (NM,D,CK);
nand DN2 (M,NM,CK);
nand DN3 (Q,NQ,NM);
nand ND4 (QN,Q,M);
or as behavioral:
always #(posedge CK)
Q <= D;
When I try to compile your code with the VCS simulator, I get a compilation error:
Identifier 'GO' has not been declared yet. If this error is not
expected, please check if you have set `default_nettype to none.
In your testbench module, you declare a wire G0 (the number zero), but then you use GO (capital letter O). You should change the zeroes to letter O's.
I don't think this will completely solve your problem, but this was too complicated to fit in a Comment.

Resources