Easy way of dividing an integer by 3 - vhdl

I'm working on a project that is to make a simple music player on an FPGA. It takes a music file of a specified format from the PC and plays it out loud in loops.
We need to implement the standard note lengths, i.e. Quaver for half a beat, Minim for 2 beats, etc. Currently we have a table of the lengths of a beat in numbers of clock cycles at various BPM values. We need to multiply them by these note lengths to yield the correct clock cycles. The only problem is Tuplet, which is a third of a full beat.
Without implementing a full-blown divider circuit, are there any maths tricks one can do to divide, approximately, an integer by 3?

Dividing by 3 is the same as multiplying by 1/3 (=0.33333). 0.3333 can be expressed as an addition of two or more (depending on the needed accuracy) (left) shifted input values.
input*2^-a + input*2^-b + input*2^-c ...
Just find suitable values for a, b, c, ...
This works for (almost) all divisions.

The following is a VHDL translation of some code from Hank Warren’s Hacker’s Delight. It divides an unsigned integer by the constant value 3 using only shifts, additions, and multiplications by the constant values 3 and 5 (which can also be reduced to shifts and additions).
-- q is quotient, d is dividend
q := (d srl 2) + (d srl 4); -- q = d*0.0101 (approx)
q := q + (q srl 4); -- q = d*0.01010101
q := q + (q srl 8);
q := q + (q srl 16);
r := resize(d - q * 3, 32); -- 0 <= r <= 15.
q := resize(q + (5 * (r + 1) srl 4), 32);

If the exact result of integer division by 3 (x / 3) is required for an unsigned value of length LEN, then truncating integer operations can be used with a little trick. The constant for 1/3 should be of length LEN + 1 and 1 should be added. Truncation can then be used afterwards. Pseudo code as:
C = 2 ** (LEN + 1) / 3 + 1
y = (x * C) / 2 ** (LEN + 1)
A Python function that shows and tests the algorithm for all values is:
def div_by_3_test(LEN):
DIVISOR = 3
C = 2 ** (LEN + 1) // DIVISOR + 1
for x in range(2 ** LEN):
if (x * C) // 2 ** (LEN + 1) != x // DIVISOR: exit('Failed')
A VHDL module that implements this as:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity div_by_3 is
generic(
LEN : natural := 12);
port(
x_i : in std_logic_vector(LEN - 1 downto 0);
y_o : out std_logic_vector(LEN - 1 downto 0));
end entity;
architecture syn of div_by_3 is
-- Constant to multiply, basically 1/3, but adding 1 to avoid error
constant C : std_logic_vector(LEN - 1 + 1 downto 0) :=
std_logic_vector(to_unsigned(2 ** (LEN + 1) / 3 + 1, LEN + 1));
-- Intermediate, with length as 2 * LEN + 1
signal t : std_logic_vector(2 * LEN + 1 - 1 downto 0);
begin
-- Intermediate with full length result
t <= std_logic_vector(unsigned(C) * unsigned(x_i));
-- Result after truncation for division by LEN + 1
y_o <= t(2 * LEN + 1 - 1 downto LEN + 1);
end architecture;
The advantage is that a division by 3 of an LEN bit number can be made in one cycle using only a single 2 * LEN + 1 bit multiplication.
Registers may be added to allow pipeline for high speed design.
Note that a similar scheme is possible for any divisor, but length of C must then be LEN + ceil(log2(DIVISOR)), with C scaled accordingly. Please see https://math.stackexchange.com/q/2444306/275980 regarding the mathematical foundation.

As mentioned by dieli, multiply by 0.333333.
However, instead of using several negative powers of 2 (i.e. a, b, c,..) just multiply 1/3 by some large power of 2, e.g. 2^24 * (1/3) = 5592405. After multiplying the clock cycles and 5592405, just divide by 2^24.
B = (clock cycles)*5592405
result = B/2^24
The size of B would depend the maximum size of clock cycles and can be computed by
maximum register size for B = integer of ( (log10((max size of clock cycles)*5592405)/log10(2)) + 0.5)

Related

How is this calculating CRC-A using polynomial - x^16 + x^12 + x^5 + 1

I came across this piece of code. But I am not sure how is CRC calculated here. I know the theoretical way of calculating CRC but I guess here it is using some kind of different logic, maybe. Please correct me.
r_o[14:13] <= r_o[13:12];
r_o[12] <= r_o[11]^r_o[15]^x16;
r_o[11] <= r_o[10];
r_o[10:6] <= r_o[9:5];
r_o[5] <= r_o[4]^r_o[15]^x16;
r_o[4] <= r_o[3];
r_o[3:1] <= r_o[2:0];
r_o[0] <= r_o[15]^x16;
Well, if you know about the theoretical way to do we can start with
Assuming u is the input bit, and that every iteration you calculate r = r * x + u*x^16, remember that in the given ring x^16 = x^12 + x^5 + 1, a direct implementation of this would be
parameter X16_MASK = 16'h1021; // (1 << 12) ^ (1 << 5) ^ 1
function [15:0] step(input [15:0] prev_state, input u);
logic [15:0] state;
begin
state = {prev_state[14:0], 1'b0};
if(state[15]) state = state ^ X16_MASK;
if(u) state = state ^ X16_MASK;
step = state;
end
endfunction
This could simply be written as {r_o[14:0], 1'b0} ^ (X16_MASK * (r_o[15] ^ u)) and let the synthesis to optimize whatever is necessary, it should be able to simplify the multiplication by a 1-bit signal. Now check the positions where the mask has an effect you will get to assignments above.
I would simplify
r_o[11] <= r_o[10];
r_o[10:6] <= r_o[9:5];
to r_o[11:6] = r_o[10:5]
and
r_o[4] <= r_o[3];
r_o[3:1] <= r_o[2:0];
to r_o[4:1] = r_o[3:0]
In the code you presented I am missing the assignment to r_o[15].
So you could say
r_o[15:13] <= r_o[14:12];
r_o[12] <= r_o[11]^r_o[15]^x16;
r_o[11:6] <= r_o[10:5];
r_o[5] <= r_o[4]^r_o[15]^x16;
r_o[4:1] <= r_o[3:0];
r_o[0] <= r_o[15]^x16;
And if you like the one linear bit packing
r_o <= {r_o[14:12], r_o[11]^r_o[15]^x16, r_o[10:5], r_o[4]^r_o[15]^x16,r_o[3:0], r_o[15]^x16}

How can I convert 4 bit std vector to 5 bit vector in VHDL?

I am stuck in converting my 4 bit std vector to 5 bit. I am supposed to do logic operations and arithmetic operations with 4 bit inputs. (4 bit ALU) However, for arithmetic operations, I might have a carry out bit and I don't know how to keep it. Here is my code, I tried to define a temp 5-bit vector and make temp(4) to carry out.
architecture Behavioral of alusmall is
signal temp: std_logic_vector (4 downto 0);
begin
--.--Here we write which operations are launched according to M and S signals:
temp <= (A and B) when (M='0' and S="00") else
(A or B) when (M='0' and S="01") else
(A xor B) when (M='0' and S="10") else
(A xnor B) when (M='0' and S="11") else
std_logic_vector(unsigned(A) + unsigned(C1)) when (M='1' and S="00") else --.--now, the arithmetic part starts (M is one).
std_logic_vector(unsigned(A) + unsigned(B) + unsigned(C1)) when (M='1' and S="01") else
std_logic_vector(unsigned(A) + unsigned(not B) + unsigned(C1)) when (M='1' and S="10") else
std_logic_vector(unsigned(not A) + unsigned(B) + unsigned(C1));
How can I seperate temp(4) and temp(3 downto 0) in 4-to-1 multiplexer?
Addition in VHDL does not automatically do bit-growth. To allow for a carry bit, simply append '0' to the MSB of the operands. (append the sign bit for signed arithmatic). This means you can simply take the resulting MSB as your carry bit.
eg.
op <= ('0' & A) + ('0' & B);
carry <= op(op'high);
numeric std also has a resize function to do this (for both signed and unsigned):
op <= resize(A, op'length) + resize(B, op'length)
carry <= op(op'high);
Another point - why not make your inputs and outputs unsigned, rather than SLV? then you wouldnt need all the type conversions (or you can use the numeric_std_unsigned library from VHDL 2008 to do arithmatic with std_logic_vector).

Pascal - Sum of odd numbers between 0 and X

I've beeng having some trouble with this code... I need to create an algorithm which makes the user input a number (X), and then the program calculates the sum of all the odd numbers below (x).
This what I've tried so far, but can't really wrap my head around the logic behind it:
Program odd_numbers;
Var
Num, Limite, Soma: integer;
Begin;
Soma := 0;
Writeln('Choose a limit:');
Readln(Limite);
While (Limite / 2 > 0) do
Begin;
Soma := ((Num < Limite) mod 2 > 0);
Writeln('The sum of odd numbers from 0 to ', Limite, ' é ', Soma);
End;
if (Limite mod 2 = 0) then
Begin;
Soma := ((Num < Limite) mod 2 = 0);
Writeln('The sum of odd numbers from 0 to ', Limite, ' é ', Soma);
End;
End.
*PS: Been writing the code with variables in Portuguese, so don't mind the variables appearing weird to understand. *
I see that everyone is happily looping, but this is not necessary. This is a simple arithmetic sequence, and the sum can be calculated without a loop.
Just think of the following:
1 + 3 = 2 * (1 + 3) / 2 = 2 * 2 = 4 ; limits 3 and 4
1 + 3 + 5 = 3 * (1 + 5) / 2 = 3 * 3 = 9 ; limits 5 and 6
1 + 3 + 5 + 7 = 4 * (1 + 7) / 2 = 4 * 4 = 16 ; limits 7 and 8
1 + 3 + 5 + 7 + 9 = 5 * (1 + 9) / 2 = 5 * 5 = 25 ; limits 9 and 10
1 + 3 + 5 + 7 + 9 + 11 = 6 * (1 + 11) / 2 = 6 * 6 = 36 ; limits 11 and 12
But not only that, you'll see that it is in fact always a perfect square: Sqr((n+1) div 2).
So just calculate:
program odd_numbers;
var
Num, Limite, Soma: Integer;
begin
Write('Choose a limit: ');
Readln(Limite);
Num := (Limite + 1) div 2;
Soma := Num * Num;
Writeln('The sum of odd numbers from 0 to ', Limite, ' is ', Soma);
end.
Looks a little simpler than what the others propose.
The loop While (Limite / 2 > 0) do ... uses real arithmetic and not integer arithmetic. I guess you mean While (Limite div 2 > 0) do ... And you should change Limite in the loop otherwise you get stuck because the exit condition can never be reached.
After you have asked the user to enter a number, Limite, you need to keep that unchanged, because you need it in the final message. You also need a loop where you go through all numbers from Limite towards 0.
You started with a while loop which is ok, you are just missing the loop control variable. That is a variable that eventually gets a terminating value which then stops the loop. Use for example the Num variable you already have declared. You can use the same variable to investigate the numbers between user input and 0, for being odd values.
num := limite-1; // give num a start value based on user input (-1 because of "... numbers below (x)")
while num > 0 do // stop the loop when 0 is reached
begin
// here you investigate if `num` is a odd number (e.g. using `mod` operator or
// possibly your pascal has a built in `function Odd(value: integer): boolean;`)
// and add it to `Soma` if it is
num := num - 1;// decrement num at every iteration
end;
Finally you need to consider changes to the above, to handle negative input from the user.
To test if an integer is an odd value, you could use following function:
function IsOdd( value : Integer) : Boolean;
begin
IsOdd := (value mod 2) <> 0;
end;
Many pascal compilers have a built-in function called Odd(), which you could use.
A while loop works well to solve this problem. If you start with lowest odd number above zero, i.e. one and continue upwards so long we do not exceed the limit value we have a simple start:
function GetOddSumBelowX( X : Integer) : Integer;
var
i,sum: Integer;
begin
i := 1; // Start with first odd number
sum := 0;
while (i < X) do begin // as long as i less than X, loop
if IsOdd(i) then begin
sum := sum + i; // add to sum
end;
i := i + 1; // Increment i
end;
GetOddSumBelowX := sum;
end;
Now, that was simple enough. Next step to simplify the loop is to increment the i variable by two instead, just to jump between all odd numbers:
function GetOddSumBelowX( X : Integer) : Integer;
var
i,sum: Integer;
begin
i := 1; // Start with first odd number
sum := 0;
while (i < X) do begin // as long as i less than X, loop
sum := sum + i; // add to sum
i := i + 2; // Increment to next odd number
end;
GetOddSumBelowX := sum;
end;

How to convert big integers to smaller integers in vhdl?

I have VHDL code where I'm trying to multiply pixel values. I have the following entity:
entity xGradient is
port(
clk : in std_logic;
x11, x12, x13, x21, x22, x23, x31, x32, x33 : in integer range 0 to 255;
gradientInX : out integer range 0 to 255
);
end xGradient;
I do the following operation on these:
gradientInX <= x11 + 2*x21 + x31 - x13 - 2*x23 - x33;
The issue as you may notice is that the values obtained from the operation exceed the range of possible values my output integer can be. My simulation crashes when this happens. I don't know the right word for what I'm trying to do and therefore can't seem to figure out how to fix this problem and it's driving me crazy. I basically just want to truncate, or reduce the size of the output to ensure it fits into the gradientInX output port. I tried using a process block like this:
-- declared signals
signal gradientMem: integer;
--beginning of my architecture
begin
SobelOperator : process(gradientMem)
begin
gradientMem <= x11 + 2*x21 + x31 - x13 - 2*x23 - x33;
if (gradientMem > 255) then
gradientMem <= 255;
elsif (gradientMem < 0) then
gradientMem <= 0;
end if;
end process SobelOperator;
then assigning gradientMem to gradientInX but it doesn't work for some reason. Any help would really be appreciated. Note: I haven't included all the VHDL code as I thought it would be unnecessarily long. The error message I get is that the signal resulting value from the operation is out of range (since the resulting value is negative and the output has a range of only 0 to 255).
Matthew
This is one of the few situations where you should use a variable instead of a signal.
SobelOperator : process(x11, x21, x31, x13, x23, x33)
variable gradientMem : integer;
begin
gradientMem := x11 + 2*x21 + x31 - x13 - 2*x23 - x33;
if (gradientMem > 255) then
gradientMem := 255;
elsif (gradientMem < 0) then
gradientMem := 0;
end if;
gradientInX <= gradientMem;
end process SobelOperator;
By the way, this operation is called clipping.
If you want to truncate, the process should be written like:
SobelOperator : process(x11, x21, x31, x13, x23, x33)
variable gradientMem : integer;
begin
gradientMem := x11 + 2*x21 + x31 - x13 - 2*x23 - x33;
gradientInX <= gradientMem mod 256;
end process SobelOperator;
As #Paebbels suggests in the comment, most likely the range of gradientMem is not sufficient to handle the output of the operation.
Thing to note: in the integer operations, the intermediate range is (mostly) considered as 32b signed and the range is checked in the assignment. This gives quite a lot to speculate for the synthesis tool and can yield much larger design than optimal.
To overcome this, ieee.numeric_std.all is used for unsigned and signed types and operations. This gives absolute control for the intermediate vector lengths. This also forces you to gain understanding on what's going on in addition, subtraction, multiplication etc which typically helps in RTL design.
However, a thing to note is that in vector form, the operations are evaluated in pairs using the longest of the two as intermediate vector length.
For example:
process
variable i1 : integer range 0 to 15 := 15;
variable i2 : integer range 0 to 15 := 9;
variable i3 : integer range 0 to 15 := 11;
variable i4 : integer range 0 to 31 := 2;
variable iSum : integer range 0 to 63;
variable u1 : unsigned(3 downto 0) := to_unsigned(15,4);
variable u2 : unsigned(3 downto 0) := to_unsigned(9,4);
variable u3 : unsigned(3 downto 0) := to_unsigned(11,4);
variable u4 : unsigned(5 downto 0) := to_unsigned(2,6);
variable uSum : unsigned(5 downto 0);
begin
iSum := i1 + i2 + i3 + i4;
uSum := u1 + u2 + u3 + u4;
write(output, "int: " & to_string(iSum) & lf &
"us : " & to_string(to_integer(uSum)) & lf);
wait;
end process;
Gives:
# int: 37
# us : 5
Using parenthesis solves the problem:
uSum := (u1 + (u2 + (u3 + u4)));
An error is in the sensitivity list of your process SobelOperator : process(gradientMem). Here must be signals which influence to result signal(s) in other words this is a list of signals a process is sensitive to. So there should be x11, x21, x31, x13, x23 and x33 like SobelOperator : process(x11, x21, x31, x13, x23, x33)

matrix enlargement in vhdl

I have a matrix (size n x m) in matlab. And I want to enlarge the matrix size to n+2x, m+2y) by adding zeros around the original n x m matrix.
Example:
original 2x2 matrix
1 2
3 4
New 4x4 matrix [0 0 0 0; 0 1 2 0; 0 3 4 0; 0 0 0 0]
0 0 0 0
0 1 2 0
0 3 4 0
0 0 0 0
How can I do it in vhdl?
type matrix is array(natural range <>, natural range <>) of natural;
signal matrix2x2 : matrix(0 to 1, 0 to 1);
signal matrix6x4 : matrix(0 to 5, 0 to 3);
function expand_matrix(m : matrix; x : natural; y : natural) return matrix is
constant ROWS : natural := m'length(1) + 2 * y;
constant COLS : natural := m'length(2) + 2 * x;
variable mx : matrix(0 to ROWS-1, 0 to COLS-1) := (others => (others => 0));
begin
for r in y to y + m'length(1) - 1 loop
for c in x to x + m'length(2) - 1 loop
mx(r, c) := m(r-y, c-x);
end loop;
end loop;
return mx;
end function;
begin
matrix2x2 <= ((1, 2), (3, 4));
matrix6x4 <= expand_matrix(matrix2x2, 1, 2);
For simplicity I made the matrix type a 2D array of natural. If you intend to eventually synthesize this you will be better off changing to a more constrained integer type or use the signed/unsigned vector types with only the number of bits you need.

Resources