I am trying to design a 4-bit adder subtracter in verilog. This is only the second thing I have ever written in verilog, and I don't know all the correct syntax yet. This is the module I have so far:
module Question3(carryin, X, Y, Z, S, carryout, overflow);
parameter n = 4;
input carryin, Z;
input [n-1:0]X, Y;
output reg [n-1:0]S;
output reg carryout, overflow;
if(Z==0)
begin
Y = not(y) + 4'b0001;
end
always #(X, Y, carryin)
begin
{carryout, S} = X + Y + carryin;
overflow = carryout ^ X[n-1]^Y[n-1]^S[n-1];
end
endmodule
My compiler (xilinx 10.1), keeps saying "Syntax error near if." I have tried many different ways of doing the conversion, including just using a Case that takes Y as an argument, then checks all the possible 4-bit combinations, and converts them to two's complement.
Z is what determines if the adder does subtraction or addition. If it's 0, it means subtraction, and I want to convert y to two's complement, then just do regular addition. I'm sure the rest of the adder is correct, I just do not know what is wrong with the part where I'm trying to convert.
reg [n-1:0] Y_compl;
always #( Z, Y, X, carryin ) begin
Y_ = ( ~Y + 4'b0001 );
if ( Z == 1'b0 ) begin
{carryout, S} = X + Y_compl + carryin;
overflow = carryout ^ X[n-1] ^ Y_compl[n-1] ^ S[n-1];
end
else begin
{carryout, S} = X + Y + carryin;
overflow = carryout ^ X[n-1] ^ Y[n-1] ^ S[n-1];
end
end
A couple of important points.
Put the if statement inside the always block. Do not use two always blocks, you'll create a race condition in the simulator.
I created a new variable, Y_ because using Y, which is an input, remember, on the left hand side of an assignment will probably infer latches or do something else nasty when you synthesize.
I suggest using the bitwise inversion operator '~' to invert Y instead if the 'not'
primitive. The synthesis tool has more freedom to optimize your code this way.
Double check for correct results, it's been awhile since I built an adder.
You are using a lower case "y" in "Y = not(y) + 4'b0001;"
Also, you're using more additions than you need to. X-Y is the same thing as NOT(NOT(X)+Y).
put the if statement within an initial block
http://www.asic-world.com/verilog/vbehave1.html
Related
I had some strange behavior when synthesizing some code with the expression:
logic [7:0] x;
//...
if ((~x) == 0)
In a situation where x is 8'hff), the above boolean evaluates to false. I saw this behavior in synthesized hardware and double-checked it in simulation.
Of course, changing the expression to
if ((~x) == '0)
Gives me the behavior I expect; It evaluates to true when x is 8'hff.
My question:
Why does adding the tick mark fix this problem? 0 by itself should give me an unsigned integer with width 32, and (~x) should give me an 8-bit unsigned number. Whether or not I specify the width of my 0, the result ought to be the same.
I assume that I'm missing something about signedness or type promotion in the Verilog spec.
Example code:
You can see this behavior across all Commercial simulators at this EDA playground link.
In case you have trouble accessing it, the code at the link is
module tb;
logic [7:0] x;
logic [7:0] y;
initial begin
x <= 8'hff;
y <= 8'h00;
#1;
$display("((~x) == 0) evaluates to %b", (~x) == 0); #1;
$display("((~x) == '0) evaluates to %b", (~x) == '0); #1;
$display("((y) == 0) evaluates to %b", (y) == 0); #1;
$display("((y) == 0) evaluates to %b", (y) == '0); #1;
$display("((~y) == ~0) evaluates to %b", (~y) == ~0); #1;
$finish;
end
endmodule
This is because operands get extended before apply any operations within the same context.
Since the width of the unsized decimal literal 0 is 32, the equality operator extends the width of the smaller operand to the width of the larger operand. So 8'hFF becomes 32'h0000_00FF. Then the bitwise-negation operator ~ gets applied.
The width of fill literal '0 depends on its context. When self-determined, its width is 1 bit. However, when in the context of the equality operator, its width gets extended to the width of x, which is 8-bits.
You can get the behavior you want by using the fill literal, or making sure there is no operand extension either by:
if ((~x) == 8'b0) // No extension -- both sides are 8-bits
or use a concatenation:
if ({~x} == 8'b0)
The concatenation works because each operand of a concatenation is self-determined. Only the result of the concatenation is the context of the equality expression.
I'm trying to write a synthesizable code in .sv to meet my requirements, but got stuck at the very end without a solution;
I've an incoming wire which is 99 bit wide and 10 (MAX) deep
I need to feed this to a module and get its output which is 99 bit
the output needs to be assigned to an array (99 bit wide ) from 0 .. max
I can't paste the snippet, but this is what I've coded:
--
param MAX = 10;
param TOT_INST = 45 ;
wire [98:0] inwire [MAX-1:0] ;
wire [98:0] outwire [TOT_INST-1:0]
genvar x,y,z ;
generate
for (x = 0, z=0; x<=MAX-1; x=x+1, z=z+1 )
begin : gen1
for (y = x + 1; y<=MAX-1; y=y+1)
begin : gen2
some_module mod_inst ( .in1(inwire[x]), .in2(inwire[y]), .y(outwire[z]) );
end
end
endgenerate
--
The expectation is to get outwire[0] to be an output of inwire[0] and inwire[1], outwire[1] to be a function of inwire[0], inwire[1] etc. So, it becomes necessary to increment the index of outwire.
I used another genvar z for this purpose (to increment from 0 to 44). But, it looks like the SV doesn't support multiple genvar variables to be incremented? im getting compilation error at the for loop itself.
Is there any way to achieve what i need? I really appreciate you taking time to go through this question. Any insight would be really helpful.
Thanks
Jr.
I understand your intent. It seems you are trying to use comma expressions, but they wont work here.
Also, it seems that the genvar can only be assigned in the initialization and increment of the for loop, otherwise it would be easy to increment them on the innermost loop.
Since you must have unique drivers to the outwires, and the number of entries you declared (45) matches the number of instances you will create I assume you simply want them to be set incrementally.
What I would do is to calculate the number of iterations algebraically and create a local parameter. If you can't see how, review triangular numbers.
parameter MAX = 10;
// Generalizing your TOT_INST
parameter TOT_INST = MAX * (MAX - 1) / 2 ;
wire [98:0] inwire [MAX-1:0] ;
wire [98:0] outwire [TOT_INST-1:0];
genvar x,y;
generate
for (x = 0; x <= MAX-1; x = x + 1 )
begin : gen1
for (y = x + 1; y<=MAX-1; y=y+1)
begin : gen2
localparam z = TOT_INST - ((MAX - x - 2) * (MAX - x - 1)) / 2 + y - MAX;
initial begin
$display("%d %d %d", x, y, z);
end
end
end
endgenerate
The formula would be simpler if we used the x in the inner loop.
i need to write a code in verilog but i'm new to it. I've actually tried $log10() function but when synthesize the code i get an error "Unsupported System Function Call" for $log10().
Maybe consider using a power series approximation? You could break it up into a piece-wise function for greater accuracy
See the Wolfram Mathematica screenshot below (click on it for a better view).
Maybe something to work with.
Since you have only 1024 possible inputs, I'm lazy enough that I would just do a lookup table. You can generate the module with the following Python code:
import math
import bitstring
s = """
module log10(
input wire [9:0] x,
output reg [32:0] y
);
always #*
case (x)
"""
for i in range(1, 1024):
# this will give you 32b floating point, not 8b fixed
# point but you can figure that part out
s += str(i) + ": y = 32'b" + bitstring.BitArray(float=math.log10(i), length=32).bin + ";\n"
s += """
default: y = 32'hdeadbeef;
endcase
endmodule
"""
print(s)
Gives you:
module log10(
input wire [9:0] x,
output reg [32:0] y
);
always #*
case (x)
1: y = 32'b00000000000000000000000000000000;
2: y = 32'b00111110100110100010000010011011;
3: y = 32'b00111110111101000100100100111101;
4: y = 32'b00111111000110100010000010011011;
5: y = 32'b00111111001100101110111110110011;
// ...
6: default: y = 32'hdeadbeef;
endcase
endmodule
I want to ask about switching one bit for example x[3] in bit vector x[0:3] to one if it's zero or to zero if it's one in verilog.So if x=0101 it will become x=0100 .I have tried concatination with not but it's error in verilog .Can you help me to do that?
My code is here :http://www.edaplayground.com/x/JAc
where x:input and y:x after mutate one bit
Thanks in advance.
To alter one bit as part of a bus:
module bit_mangle(
input [3:0] x,
output [3:0] y
);
always #* begin
y = {x[3:1], ~x[0]} ;
end
endmodule
I have updated a copy of your code on EDA playground, and fixed a few issues in the testharness.
Working simulation on EDA Playground.
It is more common to define buses from [SIZE-1:0]. Your old Mutation code was trying to drive the input in two places rather than letting the level above drive the value.
always_comb begin
x = 4'b0101 ;
x[3] = ~x[3] ; //overwrite x[3] with its complement
end
or
always_comb begin
x = 4'b0101 ;
x[3] = x[3] ^ 1'b1 ; //XOR x[3] with 1
end
I have a part of code of my design as follows.
parameter n=256;
input [n-1:0] x;
output y;
initial begin
x = 0;
if(0 >= unsigned'(x-9))
y = 1;
end
My expectation is, the unsigned subtraction operation should return decimal 247 but in actual it returns -9. Is anyone having better way of coding to achieve this?
My actual requirement is, even if I subtract a smaller value from larger, the value should rollover w.r.t. parameter width (As if 0-1 should yield 255). My question may be wrong but this requirement is necessary from my project.
247 and -9 are the same bit pattern so the arithmetic is correct. Signed vs unsigned is an interpretation of the bit pattern.
NB: 0-1 is only 255 with 8 bit numbers you have defined them as 256 bit numbers.
The following example should help clarify, We use $signed and $unsigned keywords which alters how the decimal representation is displayed but the underlying binary form does not change.
module tb;
parameter n=8;
logic [n-1:0] x;
logic y;
initial begin
x = 0;
$display("%1d", x-9);
$display("%1b", x-9);
$display("");
$display("%1d", $unsigned(x-9) );
$display("%1b", $unsigned(x-9) );
$display("");
$display("%1d", $signed(x-9) );
$display("%1b", $signed(x-9) );
$display("");
$finish;
end
endmodule
Which Outputs:
4294967287
11111111111111111111111111110111
4294967287
11111111111111111111111111110111
-9
11111111111111111111111111110111
For your example you just need to use $unsigned:
module tb;
parameter n=8;
logic [n-1:0] x;
logic y;
initial begin
x = 0;
if(0 >= $unsigned(x-9)) begin
y = 1;
end
else begin
y = 0;
end
$display("y: %b", y);
$finish;
end
endmodule