3

I found the method for c language.But I do not know how to perform this in VHDL. Let a fixed point number (12 downto -19) like 3456.478396 I need break this number entirely into separate numbers 3456.478396 --> 3, 4, 5, 6, (dot) , 4, 7, 8, 3, 9, 6... into 11 integer type variables. How to perform this in VHDL?

signal example : sfixed(4 downto -4);
--'example' contains 9.75 then it is storage as "01001.1100".
--simply example ="10011100".
--10011100 --> integer 156

How to get back original 9.75 number from 156 to separate into single digits?

I USED,

library ieee;
library ieee_proposed;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee_proposed.float_pkg.ALL;
use ieee_proposed.fixed_pkg.ALL;
use ieee_proposed.fixed_float_types.ALL;
oppo
  • 537
  • 1
  • 7
  • 22
  • How is the original number represented? How do you want it to be represented once "broken"? – Eugene Sh. Jul 25 '17 at 16:07
  • 2
    depends how the number is held. If in BCD, then it's easy. If it's in binary, then you have to convert to decimal first. – Neil_UK Jul 25 '17 at 16:07
  • @Eugene Sh in the question I have mentioned that **I need break this number entirely into separate numbers 3456.478396 --> 3, 4, 5, 6, (dot) , 4, 7, 8, 3, 9, 6... into 11 integer type variables.** – oppo Jul 25 '17 at 16:38
  • See here: https://stackoverflow.com/questions/23871792/convert-8bit-binary-number-to-bcd-in-vhdl Once your binary integer is converted to BCD, each digit is separate... – Mishyoshi Jul 25 '17 at 17:06
  • 1
    @Mishyoshi That doesn't solve the right hand side of the problem. The decimal values. – Harry Svensson Jul 25 '17 at 17:08
  • @Harry Svensson sorry, I just undeleted this back, I thought this is a dummy question. – oppo Jul 25 '17 at 18:19
  • I think it's a good question, though I didn't look around for any duplicate. – Harry Svensson Jul 25 '17 at 18:51

1 Answers1

4

Here's some pseudocode.

Let's take the ones left of the decimal first, max number is \$15_{10}\$ => 2 decimal digits.

signal ex : sfixed(4 downto -4);

temp <= ex(4 downto 0);
L_0 <= temp mod 10;
temp <= temp/10;
L_1 <= temp mod 10;

Example:
ex=\$12_{10}\$=\$1100_{2}\$

temp <= 12
L_0 <= 12 mod 10 = 2
temp <= 12/10    = 1
L_1 <= 1 mod 10  = 1

And then the ones to the right, smallest number => 0.0625 => 4 decimal digits. Same method as before, just multiply by \$625_{10}\$ before you start. Because \$0001_{2}\$ in binary translates to \$.0625_{10}\$ in decimal. So the bit width of temp should be \$ceil(log_2(625×15))=\$ 14 bits because \$15_{10}\$ is \$1111_{2}\$ which is your highest value.

signal ex : sfixed(4 downto -4);

temp <= ex(0 downto -4);
temp <= temp*625

R_3 <= temp mod 10;
temp <= temp/10;
R_2 <= temp mod 10;
temp <= temp/10;
R_1 <= temp mod 10;
temp <= temp/10;
R_0 <= temp mod 10;

Example:
ex=\$0.1875_{10}\$=\$0011_{2}\$

temp <= 3 = 0011
temp <= 3*625 = 11101010011        = 1875

R_3 <= 1875 mod 10                 = 5
temp <= 1875/10                    = 187
R_2 <= 187 mod 10                  = 7
temp <= 187/10                     = 18
R_1 <= 18 mod 10                   = 8
temp <= 18/10                      = 1
R_0 <= 1 mod 10                    = 1

And it should be displayed like this:

\$L_1 L_0 . R_0 R_1 R_2 R_3\$

All the constant division by 10 can be replaced by a multiplication with \$\frac{1}{10}\$. So it's not too inefficient to implement. I'm fairly certain that the modulus operator comes with the standard library.

If you use 6 bits for the right hand side of the decimal point. Then the bit width for temp should be \$ceil(log2(63×15625))\$ = 20 bits. This is probably not the most efficient way, it's a way I came up with just now on my own. It should work without any major problems.

Since this is being done on an FPGA you can parallelize the multiplication, for R3,R2,R1 and R0, multiply their temp with 1, \$\frac{1}{10}\$, \$\frac{1}{100}\$ and \$\frac{1}{1000}\$ so you get the values straight away, instead of serially. And then use the mod 10 on them.


EDIT

Mishyoshi gave me an idea for how this could be solved in another way. \$L_0\$ and \$L_1\$ are solved like before, but the \$R_{0..3}\$ can be done in another more efficient way.

signal ex : sfixed(4 downto -4);

signal temp : sfixed(4 downto -4); 
//We need 4 to the left of the decimal point because then we can capture
//all the single digits

temp <= "0000" & ex(0 downto -4);
temp <= temp*10;

R_0 <= temp(3 downto 0); //Copy the 4 MSB bits 
temp <= "0000" & temp(-1 downto -4); //Delete the 4 MSB bits
temp <= temp*10;
R_1 <= temp(3 downto 0);
temp <= "0000" & temp(-1 downto -4);
temp <= temp*10;
R_2 <= temp(3 downto 0);
temp <= "0000" & temp(-1 downto -4);
temp <= temp*10;
R_3 <= temp(3 downto 0);

Example:
ex=\$0.1875_{10}\$=\$0011_{2}\$

signal temp : sfixed(4 downto -4);

temp <= "0000" & "0011"                     = 0000.0011 = 3
temp <= 3*10                           = 30 = 0001.1110 
R_0 <= "0001.1110"(3 downto 0)              = 0001 = 1
temp <= "0000" & temp(-1 downto -4)         = 0000.1110
temp <= 14*10                         = 140 = 1000.1100
R_1 <= "1000.1100"(3 downto 0)              = 1000 = 8
temp <= "0000" & "1100"                     = 0000.1100
temp <= 12*10                         = 120 = 0111.1000
R_2 <= "0111.1000"(3 downto 0)              = 0111 = 7
temp <= "0000" & "1000"                     = 0000.1000
temp <= 8*10                           = 80 = 0101.0000
R_3 <= "0101.0000"(3 downto 0)              = 0101 = 5

As you can see it's all about getting the bits to the "ones" place, the 4 bits to the left of the decimal point.

That's way fewer bits needed for this. In this other solution you can, like Mishyoshi said, put them in a pipeline.

Harry Svensson
  • 8,139
  • 3
  • 33
  • 53
  • I do not understand what is, and how is this got **smallest number => 0.0625 => 4 decimal digits**. the number **625** – oppo Jul 25 '17 at 18:52
  • 1
    if you put 1/16 in to the calculator, then it will show 0.0625, if you just look at the non-zero-numbers it says 625. That means that a 0000.0001 in binary is 0.0625 in decimal. So the "weight" of the 1 is 1/16. But since we're on the "right hand side", we can just ignore the decimal point and treat it as 0625. In other words, just multiply by 625. Because we're just converting to BCD, we're not doing anything fancy. – Harry Svensson Jul 25 '17 at 18:57
  • 1
    If it would be 6 bits then you would multiply by 15625 because the 0000.000001 in binary is 0.015625 in decimal. Remove the decimal and you got 000001 is 015625. So multiply the 1 by 015625 and then start chopping out the digits. – Harry Svensson Jul 25 '17 at 19:03
  • 1
    I might be wrong but for a 4 bit fixed point fractionnal value, you can perform a binary multiply of 10000 because it is valued 0.0625 (4digit => 10^4). Then convert that to BCD using link i provided. Value will be 10000 times too large, so consider decimal point 4 position to the left. There would only be a single multiply with readily available multiplier and a bunch of adders which could be pipelined. – Mishyoshi Jul 26 '17 at 03:06
  • Hmm, you're onto something @Mishyoshi. You need to do something more than just multiply by \$10^4\$ though. – Harry Svensson Jul 26 '17 at 03:17
  • @Harry Svensson in above calculation **temp** is vector, does it not need to convert to an integer before go for **mod 10** and ** /10** steps? i am using **david bishop's** fixed point package. – oppo Jul 31 '17 at 16:45
  • @Oppo I said that it's **[pseudocode](https://en.wikipedia.org/wiki/Pseudocode)**, meaning I ignore 90% of all the semantics and I just write code like an algorithm. The reason for that is because I don't want to dig deep into the VHDL language because **A**, I don't have time to verify the code, **B**, I don't have Quartus installed, **C**, that algorithm should be enough to get you set in the right direction. – Harry Svensson Jul 31 '17 at 20:08
  • @Harry Svensson I followed the exact method above for a **sfixed** (19 downto -19) number but I get **3**74334.738277 for the value **2**74334.738295 fractional part is fine the **left value has changed**. – oppo Aug 02 '17 at 19:34
  • I don't know what to tell you, without any code or any knowledge how you did it, there's nothing I can tell you. All I know is that it should work, if it's something wrong with the last bit then you did something right for every number except for the last one. sfixed stands for **signed** fixed number right? Maybe there's something buggy happening at the last bit because its a sign bit. – Harry Svensson Aug 02 '17 at 19:41
  • @Harry Svensson yeah, last bit is 1 if it is negative number and its 0 if it is positive number for sfixed (david bishop's lib) -9.75 = "10110010" and 9.75 = "01001110" – oppo Aug 02 '17 at 19:53
  • Well, there's the answer for why it's not working. – Harry Svensson Aug 02 '17 at 20:58
  • @Harry Svensson I don't get it what is need to be done ? – oppo Aug 02 '17 at 21:18
  • @oppo How do you expect to make the number 374334 with 18 bits? -- **You don't**. the 19th bit is the sign bit. So whatever hush push you're doing, imagine that you're 1 bit less and take care of the 19th bit specially. Like... if it's a 1, then output a "-", if it's a 0, don't output a "-". – Harry Svensson Aug 02 '17 at 21:41