How to convert 4-digit hexadecimal number to bcd in verilog testbench - verilog

`include "bcd.v"
module bcd_4(A,B,Cin,S,Cout);
input [15:0] A,B;
input Cin;
output [15:0] S;
output Cout;
wire w1,w2,w3;
bcd_adder U1(.A(A[3:0]),.B(B[3:0]),.Cin(Cin),.S(S[3:0]),.Cout(w1));
bcd_adder U2(.A(A[7:4]),.B(B[7:4]),.Cin(w1),.S(S[7:4]),.Cout(w2));
bcd_adder U3(.A(A[11:8]),.B(B[11:8]),.Cin(w2),.S(S[11:8]),.Cout(w3));
bcd_adder U4(.A(A[15:12]),.B(B[15:12]),.Cin(w3),.S(S[15:12]),.Cout(Cout));
endmodule
I have designed a 4-digit BCD adder using four 4-bit BCD adders. The inputs 'A' and 'B' are taking hexadecimal values. How can I write a testbench so that the input values should be decimal only? I have to check the following condition also:
if({Cout,S}==A+B+Cin) $display("pass");
else $stop;

The inputs of your adder do not take hexadecimal values. They are 16-bit inputs which represent 4 BCD digits of 4 bits each. The input for each digit can range from 0 to 15 in decimal, but since they are BCD any value greater than 9 would be invalid.
The inputs can be specified in any base (binary, octal, decimal or hexadecimal).
The following are all equivalent:
A <= 10;
A <= 4'd10;
A <= 4'hA;
A <= 4'b1010;
If you want to only generate valid BCD values inputs in your testbench, you should generate the entire 4-digit number as an integer and then convert each digit to the appropriate bits to drive your design.
For example, to drive every valid value for input A (0 to 9999) you could do the following:
integer a;
for (a = 0; a < 10000; a = a + 1) begin
// a is an integer
// A is a 16-bit, 4-digit BCD value
A[3:0] = a % 10; // digit 0, ones place
A[7:4] = (a / 10) % 10; // digit 1, tens place
A[11:8] = (a / 100) % 10; // digit 2, hundreds place
A[15:12] = (a / 1000) % 10; // digit 3, thousands place
end
For sampling the output, you would do the inverse - convert 4 4-bit BCD digits to an integer.
Here is a full, runnable example which includes code for sampling and verifying the output: http://www.edaplayground.com/x/2pT

I got it. I can write it using following function
function integer hexatodecimal;
input [16:0] a;
integer b;
begin
b=a[3:0]+a[7:4]*10+a[11:8]*100+a[15:12]*1000+a[16]*10000;
hexatodecimal=b;
end
endfunction
I can call this function to convert {Cout,S} into hexadecimal.

Related

Undefined behaviour when using the system function $urandom_range(minval, maxval) with negative numbers

When I tried simulating the following code, there is a very strange behavior. The reg in actually displays values bigger than the range given in the system function $urandom_range. I have seen that this behavior happens when i tried it with unsigned reg and using negative values in the range given to the function. The code is given below.
Note: In the simulation results below we can see that there are greater values than 8 like "15" and "12".
`timescale 1ns/1ns
module test_tb();
parameter IN_SIZE = 5;
reg signed [IN_SIZE-1 : 0] in;
reg clk;
initial begin
clk = 0;
forever clk = #5 ~clk ;
end
always #(posedge clk) begin
in = $urandom_range(-16, 8);
$display("The generated number is %d ", in);
end
endmodule
#simulation results
The generated number is 15
The generated number is 4
The generated number is 4
The generated number is 4
The generated number is -16
The generated number is 15
The generated number is -2
The generated number is 12
The generated number is 8
The generated number is 1
The IEEE Std 1800-2017 declares $urandom_range as follows:
function int unsigned $urandom_range( int unsigned maxval, int
unsigned minval = 0 );
This shows that the inputs to the function must be unsigned values. Therefore, -16 is illegal. It is no surprise that the function returns unexpected values. Unfortunately, neither of the simulators I tried generated errors or warnings.
To get signed values in the range of -16 to 8, use a positive value, and subtract 16. Change:
in = $urandom_range(-16, 8);
to:
in = $urandom_range(24) - 16;

How to write string values in Verilog testbench?

I am trying to write a Verilog test-bench where I have to write output of some registers. I want to write L instead of 0, and H instead of 1 e.g '100101' as g 'HLLHLH'. I know about writing binary, hex or decimal value, but I am not sure whether it can be done in Verilog or not?
Assuming you're not using SystemVerilog, you could write a task, eg:
task LHwrite (input integer bin, input integer length);
integer i;
for (i=length-1; i>=0; i=i-1)
$write("%s", "L"-(bin[i]*8'h4));
endtask
bin is the value you want to display (up to 32 bits); length is the number of bits you want to display. The task iterates over the input:
for (i=length-1; i>=0; i=i-1)
and then uses the $write system task (which is like $display but without a newline) to display the string you want. This is calculated based on the knowledge that the ASCII code for 'H' is 8'h48 and for 'L' is 8'h4C.
https://www.edaplayground.com/x/4Ewk
module M;
task LHwrite (input integer bin, input integer length);
integer i;
for (i=length-1; i>=0; i=i-1)
$write("%s", "L"-(bin[i]*8'h4));
endtask
initial
begin : test
reg [5:0] bin = 6'b100101;
LHwrite(bin, 6);
$write("\n");
end
endmodule
System verilog testbench is a programming language. You can do normal programming things in it. However, in this case you would need to create your resulting string bit by bit like in the following example:
program a;
bit [3:0] data = 4'b1100;
initial begin
string out;
$display("%b ==> ", data);
for (int i = 0; i < $bits(data); i++) begin
if ((data & ($bits(data)) == 0)
out = {"L", out};
else
out = {"H", out};
data >>= 1;
end
$display(" ==> %s", out);
end
endprogram
result:
1100 ==>
==> HHLL

Verilog if statement always returns false

I need help with my if/else statement that's not working. No matter what I enter, it just doesn't work. It only ever assigns 1 to operand2. What am I doing wrong with the if/else statement?
module TestMod; // the "main" thing
parameter STDIN = 32'h8000_0000; // I/O address of keyboard input channel
reg [7:0] str [1:3]; // typing in 2 chars at a time (decimal # and Enter key)
reg [4:0] X, Y; // 5-bit X, Y to sum
wire [4:0] S; // 5-bit Sum to see as result
wire C5; // like to know this as well from result of Adder
reg operand, operand2; //operand
wire E; //exception overflow inidicator
AddSub addOrSub(X, Y, S, C5, E, operand2);
initial begin
$display("Enter X (two digit 00~15 (since max is 01111)):");
...
$display("Enter Y (two digit 00~15 (since max is 01111)):");
...
$display("Enter + or -");
operand = $fgetc(STDIN);
if (operand == "+") begin
operand2 = 0;
end
else begin
operand2 = 1;
end
#1; // wait until Adder getsthem processed
$display("operand", operand);
$display("X =",X, " (%b",X, ") Y =",Y, " (%b",Y,")", "C0=",operand2);
$display("Result =", S," (%b",S, ") C5 = ",C5);
end
endmodule
From IEEE Std 1800-2017, section 21.3.4.1 Reading a character at a time, $fgetc:
reads a byte from the file
A byte is 8 bits. If the user inputs + on STDIN, then $fgetc returns the string +, which in a numeric context is represented by the ASCII value 43.
You declared operand to be reg, which is a 1-bit value. Therefore, operand can only take on the value 0 or 1. In the case where $fgetc returns the string +, which is 43 (or 'b0010_1011), operand just gets the LSB, which is 1.
(operand == "+") compares 1 to 43, which is false, and the else code is executed.
As you pointed out in a Comment, you need to declare operand as 8 bits wide:
reg [7:0] operand;

How to convert Signed Binary to Integer in Verilog?

I am trying to convert signed binary numbers to integer in verilog for synthesis to display, I have a couple of questions. Below is my code,
.....
if(acc[i][j]>10) //acc is a 2d register
begin
m_reg <= j-const_10; // const_10 is 16'b0000000000001010
m_int <= m_reg;
$display("Current value of M(bits)=%b",m_reg);
$display("Current value of M(int)=%d",m_int);
end
else
....
j can be less than 10, meaning m_reg can be negative. In that case, I am assuming m_reg will give me a signed binary negative number.
If it does, how do I convert it to an integer to display because I guess m_int = m_reg will give me only unsigned.
All data is 'binary' when displaying we have the choice of visualising in binary, decimal of hexadecimal. When inputing data we have the same choice but what is set and stored remains the same.
These are all the same:
a = 4'b1111;
a = 4'd15;
a = 4'hf;
To display in the given format:
$display("Binary %b", a);
$display("Decimal %d", a);
$display("Hex %h", a);
Leading 0's are not displayed, at least for decimal so min widths can be used.
$display("min of 2 Decimal %2d", a);
Dealing with signed numbers: declare the reg, logic or wire as signed, or convert when displaying.
reg [3:0] a;
reg signed [3:0] a_s;
initial begin
a = 4'b1111; // is this 15 or -1 depends on if you read as signed
a_s = 4'b1111; // -1
#1ns;
$display("Decimal converted to signed %d", $signed(a));
$display("Signed Decimal %d", a_s);
end

How does Verilog behave with negative numbers?

For instance, say I have a reg [7:0] myReg
I assign it the value -8'D69
I know Verilog stores it as 2's complement so it should be stored as
10111011
The question I have now is if I were to perform an operation on it, say myReg/2
Would it evaluate to -34? Or would it take 10111011 and turn it into 187 then perform the division, returning 93?
You need to remember that -8d69 is just a bit pattern. reg is a type which holds bit patterns. It is the type of variable that instructs / to perform signed or unsigned arithmetic.
If this is for synthesis bare in mind that you want to try and avoid dividers, you really want to try and avoid signed dividers. It will likely synthesis smaller with >>> 1
reg [7:0] a;
reg signed [7:0] b;
reg [7:0] c;
reg signed [7:0] d;
initial begin
a = -8'd69 ;
b = -8'd69 ;
c = -8'd69 ;
d = -8'd69 ;
#10ns;
a = a/2 ;
b = b/2 ;
#10ns;
$display("a : %8b, %d", a, a);
$display("b : %8b, %d", b, b);
$display("c >>>1 : %8b, %d", c>>>1, c>>>1);
$display("d >>>1 : %8b, %d", d>>>1, d>>>1);
end
Gives:
a : 01011101, 93
b : 11011110, -34
c >>>1 : 01011101, 93
d >>>1 : 11011101, -35
>> x Shifts right by x places, >>> x Shifts right x places but sign extends for signed types.
NB: the /2 is also rounding up in my examples, >>> will round down/truncate.
For instance, say I have a reg [7:0] myReg I assign it the value
-8'D69
This actually isn't a signed number but instead an expression consisting of a unary negation applied to a positive constant. If the expression was -8'd130 the result would overflow. Signed constants are declared as 8'sd69 or just 69.
The question I have now is if I were to perform an operation on it,
say myReg/2
myReg is unsigned so the expression result will also be unsigned*. If you need the result to be signed than all operands must be signed. There are a couple ways to achieve this:
//Declare the reg as signed and divide by a signed value
reg signed [7:0] myReg;
assign result = myReg/2;
//Use system functions
assign result = $signed(myReg)/2;
*The complete rules regarding expression evaluation are much more complex but basically the result of any expression is unsigned, unless all operands are signed.
reg signed [7:0] a;
reg [7:0] b;
initial
begin
result = a; //Signed
result = a * a; //Signed
result = a * 10; //Signed
result = $unsigned(a); //Unsigned
result = a[0]; //Unsigned
result = a[7:0]; //Unsigned
result = {a,a}; //Unsigned
result = 10{a}; //Unsigned
result = a + b; //Unsigned
result = a * b; //Unsigned
end
I'll add that
1. Data types bit and reg are unsigned, by default.
2. Data types int, integer, longint, shortint, and byte are signed, by default.
3. All these data types can take a signed or unsigned qualifier to change the default.
So, assigning -8'D69 to myReg does an implicit conversion to 187. Then, myReg/2 = 187/2 = 93, unsigned. It's important to understand when and how SystemVerilog does implicit type conversions in expressions and assignments.
The best place to check is the Language Reference Manual. Predictably, given Verilog's "eh" attitude to proper typing, it's a bit of a mess.
Basically signed doesn't affect the actual data stored in the variable/net, but it does affect what the arithmetic operators do in some case. The obvious case is comparison, but also multiplication and division would behave differently. Addition and subtraction should be the same for both signed and unsigned.
Note especially that when one or more of the operands is unsigned it is treated as an unsigned comparison, which is different to what you would expect from C. So if we have
byte a = -10; // byte is signed
logic [7:0] b = 10; // this is unsigned
Then a > b is true.
Again if at least one operator is unsigned then it treats them both as unsigned so if we have:
byte a = -1;
logic [7:0] b = 255;
Then a == b is true.

Resources