FPGA-based Verilog language signed unsigned operation && different bit width operations (boring chatter)

This article takes quartus as an example, and uses Verilog language to simply write verification. It also introduces common assignment operations, and readers can use the attached program to verify and understand.

It is amazing that machine operations can only complete the simplest “1 + 1”, while “1 + 1” can complete the addition and subtraction of different bits in binary. How did he achieve it?

1. The simplest method is addition, and there will be no negative numbers in addition, so add directly to the number of digits, and add up to one;

2. In subtraction, the machine is also implemented by addition, because in the machine, negative numbers are represented by the corresponding complement, not negative numbers.

1. Large numbers reduce numbers

a. (same bit width subtraction method) For example, -8’d8 can be expressed as 1000_1000, the first bit means positive or negative, named as the sign bit, 1 means negative, 0 means positive.

The complement of -8 is the inverse code 1111_0111 (complement code) plus one, that is, 1111_1000 (complement code).

1111_0111 (inverse code) + 0000_0001=1111_1000 (complement code)

Let’s calculate 10-8 (8bits),

0000_1010(10)
0000_1000(8)
0000_0010(2)

If we write -8 as complement 1111_1000, it should be 10 + (-8)

0000_1010(10)
+ 1111_1000 (-8 complement)
1_0000_0010

It can be seen that at this time, the calculation result overflows the ninth digit, and the intercepted result according to 8bits is still correct.

b. (Different bit width subtraction method) In the calculation of different bit widths, obviously there will be no problem with addition, and there will be no problem with subtraction directly using the source code (if the calculation result is greater than 0), let Let’s try whether the subtraction using two’s complement calculation with different bit widths is still valid. 8’d8-4’d4

0000_1000(8)
+ _____1100(-4 complement)
0001_0100 (2)

At this time, according to the 8bits high-order interception, an error occurred.

The problem is that the short bit width should be filled up to the high bit width (fill by the first digit), the calculation is as follows

0000_1000(8)
+ 1111_1100(-4 complement)
1_0000_0100 (2)

c1(signed) = a(unsigned) – b(unsigned)

2. Let’s try subtracting large numbers from decimals

a. The same bit width operation 8’d4-8’d6, we first use the source code to calculate

0000_0100(4)
0000_0110(6)

At this time, the discovery will be borrowed infinitely.

If we use two’s complement calculation,

0000_0100(4)
+ 1111_1010(-6 complement)
1111_1110 (-2 complement)

The calculation is correct at this time.

c1(signed) = a(unsigned) – b(unsigned)

c(unsigned) = a(unsigned) – b(unsigned)

In the simulation, regardless of whether we define whether the result is assigned a symbolic value, the complement is calculated by default. However, the result of undeclared symbol value will be regarded as 1_1111_1110 (510), and an error will occur if the calculation is continued.

b. Let’s try subtracting large numbers from decimals with different bit widths, 8’d4-4’d6

0000_0100(4)
+ 1111_1010(-6 complement)
1111_1110 (-2 complement)

If we fill in the highest position, the calculation can proceed smoothly. Therefore, in machine computing, negative numbers exist in two’s complement by default.

Third, as long as there is an unsigned bit in the Verilog operation, this formula is operated on the unsigned bit

As long as there is an unsigned bit in the Verilog operation, this formula operates on the unsigned bit. This sentence is often seen, but we subtract the two numbers with the unsigned bit and assign the value to the signed bit value, such as c1(signed) = a(unsigned) – b(unsigned), from the simulation results, the calculation result is still correct, but at this time the machine is not considered to be the complement code, but the source code, continue to calculate will go wrong. So we try to avoid mixing as much as possible.

This sentence is more suitable for describing logical operations. This brings up the simpler and interesting comparator.

If we compare an unsigned value with a signed value, there will be a big problem at this time, because this operation will be calculated in unsigned bits. However, in negative numbers, the machine stores it in two’s complement. For the source code, it will be a large positive value.

For example, 8’d6 and -8’d2

6 < -2
0000_0110 1111_1110

For example, -8’d6 and -8’d2

-6 < -2
1111_1010 1111_1110

When comparing, how to compare when negative numbers appear?

We recommend using parameter signed L0=1’b0; first define the value to be compared as a symbolic value.

reg signed [7:0] c1

if(c1 >= L0)

The following is the .v file, which can be copied directly.

module signed_1(
input clk,
input rst_n,
input wire unsigned [7:0] a,
input wire unsigned [7:0] b,
input wire signed [4:0] a1,
input wire signed [8:0] b1,
output reg unsigned [9:0] c,
output reg signed [8:0] c1
);
 
 parameter signed x0='d0;
 always @(posedge clk or negedge rst_n)
begin
if (!rst_n)begin
c1 <= 'd0;
c <= 'd0;end
\t  
else if (a1 > x0)
c1 <= 'd1;
else if (a1 < x0)
c1 <=(a1);
end
endmodule

The following is the test simulation file, which can be verified by simulation with modelsim.

`timescale 1ns/1ns
module signed_1_tb();
reg clk;
reg rst_n;
wire unsigned [7:0] a ;
wire unsigned [7:0] b ;
wire signed [4:0] a1 ;
wire signed [8:0] b1 ;
wire unsigned [9:0] c ;
wire signed [8:0] c1 ;
\t\t\t     
 unassign a = 8'd8;
 unassign b = 8'd5;
 assign a1 = -5'd8;
 assign b1 = 9'd5;
\t\t
\t\t\t\t
\t\t\t\t
initial
begin
clk = 1'b0;
#3000 $stop;
end
always #10 clk = ~clk;
\t\t\t
initial
begin
rst_n = 1'b0;
#80 rst_n = 1'b1;
end
\t\t\t\t
signed_1 signed_0(
.clk (clk ),
.rst_n (rst_n ),
.a (a ),
.a1 (a1 ),
.b (b ),
.b1 (b1 ),
.c (c ),
.c1 (c1 )
);
\t\t\t\t
endmodule