Pull to refresh

Designing a circuit that calculates integer cube root

FPGA
Sandbox
Tutorial

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:verilogfpgacyclone iv
Hubs: FPGA
Total votes 9: ↑9 and ↓0+9
Views1.1K

Popular right now

Top of the last 24 hours