Pull to refresh

Designing a circuit that calculates integer cube root

Reading time9 min
Views1.9K

Good day everyone. In this article I will tell you how to make a circuit in Verilog HDL on FPGA which will calculate cube root from integer number.

I will write code in Quartus Prime Lite. My device is Cyclone IV E.

Pins and declarations

Firstly, let’s create our top level module and specify which input/output pins we will use:

Pins declaration part

module cube_root(

input clk, // Clock signal 50Mhz

input [7:0] number, // Input value

output reg [3:0] Anode_Activate, // Setter for activating segments

output reg [7:0] LED_out // Value on the segment

);

Number - value from which we will extract cube root.

Anode_Activate will specify currently activated segment of display. I will use only 3 segments: 1st for integer part of result, second and third for fractional. Last segment is not used but specified in order to make updating working properly.

LED_out specifies which number will be shown one current segment.

clk – clock signal for updating segments.

There are also other terms which can be declared in program:

reg [4:0] result1;   // First segments's value

reg [4:0] result2;   // Second segments's value

reg [4:0] result3;   // Third segments's value

reg [4:0] LED_BCD;   // Current segments's value (not used)

reg [19:0] refresh_counter;         // Segmens update counter

wire [1:0] LED_activating_counter;  // Segment activation counter

result1 – result3 - for storing result of calculations.

LED_BCD stores which of digits will be shown on activated segment.

About refresh_counter and LED_activating_counter I will talk in the next part.

Showing results on 7-segment display

Cyclone IV can’t show several digits activated simultaneously, therefore I had to implement segments updater for it:

Updater

always @(posedge clk)

begin

refresh_counter <= refresh_counter + 1;

end

// Setting LED_activating_counter as 2 last bits of refresh_counter

// in order to update segments each 5.2 ms

assign LED_activating_counter = refresh_counter[19:18];

LED_activating_counter will store 2 last bits of refresh_counter. These bits will change their value from 00 to 11 each 2^18 / 50*10^6 s = 5.2 ms.

Here is the code for setting currently activated segment according to LED_activating_counter:

Segment setter

// Setting one segment activated accorfing to LED_activating_counter

always @(*)

begin case(LED_activating_counter)

2'b00: begin

Anode_Activate = 4'b0111;

LED_BCD = result1;

LED_BCD[4] = 1; // This bit is responsible for showing dot

end

2'b01: begin

Anode_Activate = 4'b1011;

LED_BCD = result2;

LED_BCD[4] = 0;

end

2'b10: begin

Anode_Activate = 4'b1101;

LED_BCD = result3;

LED_BCD[4] = 0;

end

2'b11: begin

Anode_Activate = 4'b1110;

LED_BCD = 5'b01011;

end

endcase

end

// Setting value for activated segment

always @(*)

begin

case(LED_BCD)

5'b00000: LED_out = 8'b00000011; // "0"

5'b00001: LED_out = 8'b10011111; // "1"

5'b00010: LED_out = 8'b00100101; // "2"

5'b00011: LED_out = 8'b00001101; // "3"

5'b00100: LED_out = 8'b10011001; // "4"

5'b00101: LED_out = 8'b01001001; // "5"

5'b00110: LED_out = 8'b01000001; // "6"

5'b00111: LED_out = 8'b00011111; // "7"

5'b01000: LED_out = 8'b00000001; // "8"

5'b01001: LED_out = 8'b00001001; // "9"

5'b01011: LED_out = 8'b11111111; // " "

5'b10000: LED_out = 8'b00000010; // "0."

5'b10001: LED_out = 8'b10011110; // "1."

5'b10010: LED_out = 8'b00100100; // "2."

5'b10011: LED_out = 8'b00001100; // "3."

5'b10100: LED_out = 8'b10011000; // "4."

5'b10101: LED_out = 8'b01001000; // "5."

5'b10110: LED_out = 8'b01000000; // "6."

5'b10111: LED_out = 8'b00011110; // "7."

5'b11000: LED_out = 8'b00000000; // "8."

5'b11001: LED_out = 8'b00001000; // "9."

default:  LED_out = 8'b00000000; // "8."

endcase

end

Calculating cube root

Our number value will be input using pins using this scheme:

Maximum value of a number is 255, minimum – 0.

There already exists algorithm in a book Hacker’s Delight which can calculate cube root (code is in Java):

Java implementation of calculating cube root

public int cube_root(int val){

            int s = 0;

            int y = 0;

            int b = 0;

            for (s=30;s>=0;s=s-3){

               y = 2*y;

               b = (3*y*(y+1)+1) << s;

               if (x>=b){

                x = x-b;

                y = y+1;

               }

            }

     return y;

}

But it can only output integer results. In order to overcome this restriction we need to multiply our input value by 10^(3*n), n – natural number, and then split results into digits. Our n last digits will be fractional part. I decided to show results with 2 digits after point. It means that we need to multiply input value by 1 000 000.

Here is the code in Verilog:

Calculating cube root (Verilog)

// Calculating cube root of number

always@(*) begin : block_0

            reg [31:0] x;

            integer s;

   integer y;

   integer b;

   integer i;

            x = number;

            x = x * 1_000_000;

    y = 0;

    for (s=30;s>=0;s=s-3)

          begin : block_calc

          y=y*2;

          b = (3*y*(y+1)+1) << s;

          if (x>=b)

          begin : block_1

              x = x-b;

              y=y+1;

          end

      end

    result1 = y / 100;            // First digit

    result2 = (y % 100)/10;       // Second digit

    result3 = y % 10;             // Third digit

end

The whole code of my project:

Code of the project

module cube_root(

   input clk,       // Clock signal 50Mhz

   input [7:0] number,    // Input value

   output reg [3:0] Anode_Activate,  // Setter for activating segments

   output reg [7:0] LED_out          // Value on the segment

);

 

reg [4:0] result1;            // First segments's value

reg [4:0] result2;            // Second segments's value

reg [4:0] result3;           // Third segments's value

reg [4:0] LED_BCD;         // Current segments's value (not used)

reg [19:0] refresh_counter;   // Segmens update counter

wire [1:0] LED_activating_counter;  // Segment activation counter

 

// Calculating cubic root of number

always@(*) begin : block_0

   reg [31:0] x;

   integer s;

   integer y;

   integer b;

   integer i;

   x = number;

   x = x * 1_000_000;

    y = 0;

    for (s=30;s>=0;s=s-3)

         begin : block_calc

          y=y*2;

          b = (3*y*(y+1)+1) << s;

          if (x>=b)

          begin : block_1

              x = x-b;

              y=y+1;

          end

      end

    result1 = y / 100;

    result2 = (y % 100)/10;

    result3 = y % 10;

end

// Changing refresh_counter to update segments

always @(posedge clk)

    begin

        refresh_counter <= refresh_counter + 1;

    end

 

// Setting LED_activating_counter as 2 last bits of refresh_counter

// in order to update segments each 5.2 ms

assign LED_activating_counter = refresh_counter[19:18];

 

// Setting one segment activated accorfing to LED_activating_counter

always @(*)

    begin

        case(LED_activating_counter)

        2'b00: begin

            Anode_Activate = 4'b0111;

            LED_BCD = result1;

            LED_BCD[4] = 1;  // This bit is responsible for showing dot

        end

        2'b01: begin

            Anode_Activate = 4'b1011;

            LED_BCD = result2;

            LED_BCD[4] = 0;

               end

        2'b10: begin

            Anode_Activate = 4'b1101;

            LED_BCD = result3;

            LED_BCD[4] = 0;

        end

        2'b11:  begin

            Anode_Activate = 4'b1110;

            LED_BCD = 5'b01011;

        end

    endcase

end

 

// Setting value for activated segment

always @(*)

    begin

        case(LED_BCD)

            5'b00000: LED_out = 8'b00000011; // "0"

            5'b00001: LED_out = 8'b10011111; // "1"

            5'b00010: LED_out = 8'b00100101; // "2"

            5'b00011: LED_out = 8'b00001101; // "3"

            5'b00100: LED_out = 8'b10011001; // "4"

            5'b00101: LED_out = 8'b01001001; // "5"

            5'b00110: LED_out = 8'b01000001; // "6"

            5'b00111: LED_out = 8'b00011111; // "7"

            5'b01000: LED_out = 8'b00000001; // "8" 

            5'b01001: LED_out = 8'b00001001; // "9"

            5'b01011: LED_out = 8'b11111111; // " "

            5'b10000: LED_out = 8'b00000010; // "0." 

            5'b10001: LED_out = 8'b10011110; // "1."

            5'b10010: LED_out = 8'b00100100; // "2."

            5'b10011: LED_out = 8'b00001100; // "3."

            5'b10100: LED_out = 8'b10011000; // "4."

            5'b10101: LED_out = 8'b01001000; // "5."

            5'b10110: LED_out = 8'b01000000; // "6."

            5'b10111: LED_out = 8'b00011110; // "7."

            5'b11000: LED_out = 8'b00000000; // "8."

            5'b11001: LED_out = 8'b00001000; // "9."

            default:  LED_out = 8'b00000000; // "8."

        endcase

end

endmodule

Pin assignments.

Now, I have to specify which pins will be connected with declared ones in module. We can do it in pin planner:

Results of our work.

After compiling our project we can run it on FPGA. Here are photos with results of a program:

Useful links:

Lesson on how to deal with 7-segment display on Cyclone IV- [FPGA Tutorial] Seven-Segment LED Display on Basys 3 FPGA - FPGA4student.com

Algorithm for calculating cube root on C - Пролистал 2-е издание Hacker’s Delight в поисках занятных задач для лабника по Verilog & FPGA — Silicon Russia & Ukraine (silicon-russia.com)

Tags:
Hubs:
+9
Comments0

Articles

Change theme settings