Hi all,
I'm writing an audio driver and the hardware requires floating point
arithmetic. When I build the kernel I get the following errors at link
time:
*** Warning: "__subdf3" [sound/sh/siu_sh7343.ko] undefined!
*** Warning: "__muldf3" [sound/sh/siu_sh7343.ko] undefined!
*** Warning: "__divdf3" [sound/sh/siu_sh7343.ko] undefined!
*** Warning: "__adddf3" [sound/sh/siu_sh7343.ko] undefined!
These symbols are coming from gcc. What I would like to do is link the
kernel with libgcc to solve this errors. I'm looking at the kernel
makefiles and it doesn't seem obvious to me how to do it. Does anyone
know how I can link the kernel with libgcc, or point me in the right
direction ?
By the way this is for the Renesas SH7343 processor.
Thanks,
Carlos Munoz
On Thu, 09 Mar 2006 17:44:16 PST, Carlos Munoz said:
> I'm writing an audio driver and the hardware requires floating point
> arithmetic. When I build the kernel I get the following errors at link
> time:
Tough break, that. You sure you can't figure a way to either push the
floating point out to userspace, or do funky fixed-point math instead?
> These symbols are coming from gcc. What I would like to do is link the
> kernel with libgcc to solve this errors. I'm looking at the kernel
> makefiles and it doesn't seem obvious to me how to do it.
You can't find it because you can't do it. It isn't as simple as linking
against libgcc - there's lots of other issues that make floating point
in the kernel Really Really Hard (for starters, it means you need to save
and restore the FP state across interrupts and scheduling within the kernel).
> Does anyone
> know how I can link the kernel with libgcc, or point me in the right
> direction ?
The right direction - either push it to userspace, or find a way to do it
with fixed point math.
On Thu, 2006-03-09 at 17:44 -0800, Carlos Munoz wrote:
> Hi all,
>
> I'm writing an audio driver
This is a better question for the alsa-devel and possibly linux-sh lists
than linux-kernel.
Lee
On Thu, 2006-03-09 at 20:45 -0500, [email protected] wrote:
> On Thu, 09 Mar 2006 17:44:16 PST, Carlos Munoz said:
> > I'm writing an audio driver and the hardware requires floating point
> > arithmetic. When I build the kernel I get the following errors at link
> > time:
>
> Tough break, that. You sure you can't figure a way to either push the
> floating point out to userspace
Audio drivers should never have to directly manipulate the samples -
they just manage the DMA buffers and interrupts and wake up the process
at the right time. Mixing, routing, volume control, DSP go in
userspace.
Lee
Carlos Munoz wrote:
> Hi all,
>
> I'm writing an audio driver and the hardware requires floating point
> arithmetic. When I build the kernel I get the following errors at link
> time:
Floating point + kernel = no no. If the hardware requires floating point
manipulations this should go in userspace.
> These symbols are coming from gcc. What I would like to do is link the
> kernel with libgcc to solve this errors. I'm looking at the kernel
> makefiles and it doesn't seem obvious to me how to do it. Does anyone
> know how I can link the kernel with libgcc, or point me in the right
> direction ?
This is almost certainly a bad idea. The functions inside libgcc are not
designed to run inside a kernel.
--
Robert Hancock Saskatoon, SK, Canada
To email, remove "nospam" from [email protected]
Home Page: http://www.roberthancock.com/
Lee Revell wrote:
>On Thu, 2006-03-09 at 20:45 -0500, [email protected] wrote:
>
>
>>On Thu, 09 Mar 2006 17:44:16 PST, Carlos Munoz said:
>>
>>
>>>I'm writing an audio driver and the hardware requires floating point
>>>arithmetic. When I build the kernel I get the following errors at link
>>>time:
>>>
>>>
>>Tough break, that. You sure you can't figure a way to either push the
>>floating point out to userspace
>>
>>
>
>Audio drivers should never have to directly manipulate the samples -
>they just manage the DMA buffers and interrupts and wake up the process
>at the right time. Mixing, routing, volume control, DSP go in
>userspace.
>
>Lee
>
>
>
Hi Lee,
Unfortunately, the driver needs to populate several coefficient tables
for the hardware to perform silence suppression and other advance
features. The values for these tables are calculated using log10
operations. I don't see a clean way to push these operations to user
space without the need for custom applications that build the tables and
pass them to the driver.
Thanks,
Carlos Munoz
(added alsa-devel to cc:)
On Thu, 2006-03-09 at 19:01 -0800, Carlos Munoz wrote:
> >Audio drivers should never have to directly manipulate the samples -
> >they just manage the DMA buffers and interrupts and wake up the process
> >at the right time. Mixing, routing, volume control, DSP go in
> >userspace.
>
> Unfortunately, the driver needs to populate several coefficient tables
> for the hardware to perform silence suppression and other advance
> features. The values for these tables are calculated using log10
> operations. I don't see a clean way to push these operations to user
> space without the need for custom applications that build the tables and
> pass them to the driver.
Unless you can do it with fixed point math, or use a static table, you
might have to do just that, with a sysfs interface. For example the
emu10k1 driver uses an ioctl interface to upload code to the built in
(floating point) DSP. But new ioctls are frowned upon...
Lee
Carlos Munoz wrote:
> Lee Revell wrote:
>
>> On Thu, 2006-03-09 at 20:45 -0500, [email protected] wrote:
>>
>>
>>> On Thu, 09 Mar 2006 17:44:16 PST, Carlos Munoz said:
>>>
>>>
>>>> I'm writing an audio driver and the hardware requires floating
>>>> point arithmetic. When I build the kernel I get the following
>>>> errors at link time:
>>>>
>>>
>>> Tough break, that. You sure you can't figure a way to either push the
>>> floating point out to userspace
>>>
>>
>>
>> Audio drivers should never have to directly manipulate the samples -
>> they just manage the DMA buffers and interrupts and wake up the process
>> at the right time. Mixing, routing, volume control, DSP go in
>> userspace.
>>
>> Lee
>>
>>
>>
> Hi Lee,
>
> Unfortunately, the driver needs to populate several coefficient tables
> for the hardware to perform silence suppression and other advance
> features. The values for these tables are calculated using log10
> operations. I don't see a clean way to push these operations to user
> space without the need for custom applications that build the tables
> and pass them to the driver.
>
> Thanks,
>
>
> Carlos Munoz
>
Anyway,
I figured out how to get the driver to use floating point operations. I
included source code (from an open source math library) for the log10
function in the driver. Then I added the following lines to the file
arch/sh/kernel/sh_ksyms.c:
DECLARE_EXPORT(__subdf3);
DECLARE_EXPORT(__muldf3);
DECLARE_EXPORT(__divdf3);
DECLARE_EXPORT(__adddf3);
DECLARE_EXPORT(__floatsidf);
DECLARE_EXPORT(__eqdf2);
DECLARE_EXPORT(__fixdfsi);
Everything works now.
Thanks,
Carlos Munoz
On Thu, 2006-03-09 at 19:25 -0800, Carlos Munoz wrote:
> I figured out how to get the driver to use floating point operations.
> I included source code (from an open source math library) for the
> log10 function in the driver. Then I added the following lines to the
> file arch/sh/kernel/sh_ksyms.c:
Where is the source code to your driver?
Lee
Lee Revell wrote:
>On Thu, 2006-03-09 at 19:25 -0800, Carlos Munoz wrote:
>
>
>>I figured out how to get the driver to use floating point operations.
>>I included source code (from an open source math library) for the
>>log10 function in the driver. Then I added the following lines to the
>>file arch/sh/kernel/sh_ksyms.c:
>>
>>
>
>Where is the source code to your driver?
>
>Lee
>
>
>
Hi Lee,
Be warned. This driver is in the early stages of development. There is
still a lot of work that needs to be done (interrupt, dma, etc, etc).
You can untar it in the linux/sound directory (it will overwrite the
Kconfig and Makefile) and it will build (you will need to modify the
arch/....../kernel/ksyms.c to resolve the undefined symbols, see my
previous email). It won't do anything useful yet. Please let me know if
you have any questions.
Thanks,
Carlos Munoz
> Unfortunately, the driver needs to populate several coefficient tables
> for the hardware to perform silence suppression and other advance
> features. The values for these tables are calculated using log10
> operations. I don't see a clean way to push these operations to user
> space without the need for custom applications that build the tables and
> pass them to the driver.
can you calculate these at build time instead and store it as a table in
the .c file ?
>>>>> "Carlos" == Carlos Munoz <[email protected]> writes:
Carlos> I figured out how to get the driver to use floating point
Carlos> operations. I included source code (from an open source math
Carlos> library) for the log10 function in the driver. Then I added
Carlos> the following lines to the file arch/sh/kernel/sh_ksyms.c:
Bad bad bad!
You shouldn't be using floating point in the kernel at all! Most
architectures do not save the full floating point register set on
entry so if you start messing with the fp registers you may corrupt
user space applications.
You need to either write a customer user space app or use a table as
Arjan suggested.
Cheers,
Jes
On Friday 10 March 2006 05:47, Carlos Munoz wrote:
> Lee Revell wrote:
>
> >On Thu, 2006-03-09 at 19:25 -0800, Carlos Munoz wrote:
> >
> >
> >>I figured out how to get the driver to use floating point operations.
> >>I included source code (from an open source math library) for the
> >>log10 function in the driver. Then I added the following lines to the
> >>file arch/sh/kernel/sh_ksyms.c:
> >>
> >>
> >
> >Where is the source code to your driver?
> >
> >Lee
> >
> >
> >
> Hi Lee,
>
> Be warned. This driver is in the early stages of development. There is
> still a lot of work that needs to be done (interrupt, dma, etc, etc).
What? You are using log10 only twice!
if (!(siu_obj_status & ST_OPEN)) {
...
/* = log2(over) */
ydef[22] = (u_int32_t)(log10((double)(over & 0x0000003f)) /
log10(2));
...
}
else {
...
if (coef) {
ydef[16] = 0x03045000 | (over << 26) | (tap - 4);
ydef[17] = (tap * 2 + 1);
/* = log2(over) */
ydef[22] = (u_int32_t)
(log10((double)(over & 0x0000003f)) / log10(2));
}
Don't you think that log10((double)(over & 0x0000003f)) / log10(2)
can have only 64 different values depending on the result of (over & 0x3f)?
Obtain them from precomputed uint32_t log10table[64].
--
vda
Denis Vlasenko wrote:
> On Friday 10 March 2006 05:47, Carlos Munoz wrote:
>> Lee Revell wrote:
>
> What? You are using log10 only twice!
>
> if (!(siu_obj_status & ST_OPEN)) {
> ...
> /* = log2(over) */
> ydef[22] = (u_int32_t)(log10((double)(over & 0x0000003f)) /
> log10(2));
> ...
> }
> else {
> ...
> if (coef) {
> ydef[16] = 0x03045000 | (over << 26) | (tap - 4);
> ydef[17] = (tap * 2 + 1);
> /* = log2(over) */
> ydef[22] = (u_int32_t)
> (log10((double)(over & 0x0000003f)) / log10(2));
> }
>
> Don't you think that log10((double)(over & 0x0000003f)) / log10(2)
> can have only 64 different values depending on the result of (over & 0x3f)?
>
> Obtain them from precomputed uint32_t log10table[64].
And since you're actually trying to do log2 [log10(x)/log10(2) =
log2(x)] and casting the result to an integer, aren't you really looking
for the position of the highest 1 bit or something like that? That
doesn't need FP at all.
Groeten,
Bart
> --
> vda
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
--
Bart Hartgers - TUE Eindhoven - http://plasimo.phys.tue.nl/bart/contact/
Denis Vlasenko wrote:
>On Friday 10 March 2006 05:47, Carlos Munoz wrote:
>
>
>>Lee Revell wrote:
>>
>>
>>
>>>On Thu, 2006-03-09 at 19:25 -0800, Carlos Munoz wrote:
>>>
>>>
>>>
>>>
>>>>I figured out how to get the driver to use floating point operations.
>>>>I included source code (from an open source math library) for the
>>>>log10 function in the driver. Then I added the following lines to the
>>>>file arch/sh/kernel/sh_ksyms.c:
>>>>
>>>>
>>>>
>>>>
>>>Where is the source code to your driver?
>>>
>>>Lee
>>>
>>>
>>>
>>>
>>>
>>Hi Lee,
>>
>>Be warned. This driver is in the early stages of development. There is
>>still a lot of work that needs to be done (interrupt, dma, etc, etc).
>>
>>
>
>What? You are using log10 only twice!
>
> if (!(siu_obj_status & ST_OPEN)) {
> ...
> /* = log2(over) */
> ydef[22] = (u_int32_t)(log10((double)(over & 0x0000003f)) /
> log10(2));
> ...
> }
> else {
> ...
> if (coef) {
> ydef[16] = 0x03045000 | (over << 26) | (tap - 4);
> ydef[17] = (tap * 2 + 1);
> /* = log2(over) */
> ydef[22] = (u_int32_t)
> (log10((double)(over & 0x0000003f)) / log10(2));
> }
>
>Don't you think that log10((double)(over & 0x0000003f)) / log10(2)
>can have only 64 different values depending on the result of (over & 0x3f)?
>
>Obtain them from precomputed uint32_t log10table[64].
>--
>vda
>
>
Hi Denis,
Yes, the driver code so far only uses log10 twice, but there will be
more uses for it as I populate the rest of the tables. However, I think
its use will be some what limited. I wasn't aware that the floating
point registers are not saved. I'll investigate a way to create a table
with pre-calculated log10 values.
Thanks,
Carlos
Jes Sorensen wrote:
>>>>>>"Carlos" == Carlos Munoz <[email protected]> writes:
>>>>>>
>>>>>>
>
>Carlos> I figured out how to get the driver to use floating point
>Carlos> operations. I included source code (from an open source math
>Carlos> library) for the log10 function in the driver. Then I added
>Carlos> the following lines to the file arch/sh/kernel/sh_ksyms.c:
>
>Bad bad bad!
>
>You shouldn't be using floating point in the kernel at all! Most
>architectures do not save the full floating point register set on
>entry so if you start messing with the fp registers you may corrupt
>user space applications.
>
>You need to either write a customer user space app or use a table as
>Arjan suggested.
>E_OK
>Cheers,
>Jes
>
>
Hi Jes,
I wasn't aware that floating point registers are not save. I guess I
have no choice but to use a table.
Thanks,
Carlos Munoz
On Fri, 10 Mar 2006, Carlos Munoz wrote:
> Denis Vlasenko wrote:
>
>> On Friday 10 March 2006 05:47, Carlos Munoz wrote:
>>
>>
>>> Lee Revell wrote:
>>>
>>>
>>>
>>>> On Thu, 2006-03-09 at 19:25 -0800, Carlos Munoz wrote:
>>>>
>>>>
>>>>
>>>>
>>>>> I figured out how to get the driver to use floating point operations.
>>>>> I included source code (from an open source math library) for the
>>>>> log10 function in the driver. Then I added the following lines to the
>>>>> file arch/sh/kernel/sh_ksyms.c:
>>>>>
>>>>>
>>>>>
>>>>>
>>>> Where is the source code to your driver?
>>>>
>>>> Lee
>>>>
>>>>
>>>>
>>>>
>>>>
>>> Hi Lee,
>>>
>>> Be warned. This driver is in the early stages of development. There is
>>> still a lot of work that needs to be done (interrupt, dma, etc, etc).
>>>
>>>
>>
>> What? You are using log10 only twice!
>>
>> if (!(siu_obj_status & ST_OPEN)) {
>> ...
>> /* = log2(over) */
>> ydef[22] = (u_int32_t)(log10((double)(over & 0x0000003f)) /
>> log10(2));
>> ...
>> }
>> else {
>> ...
>> if (coef) {
>> ydef[16] = 0x03045000 | (over << 26) | (tap - 4);
>> ydef[17] = (tap * 2 + 1);
>> /* = log2(over) */
>> ydef[22] = (u_int32_t)
>> (log10((double)(over & 0x0000003f)) / log10(2));
>> }
>>
>> Don't you think that log10((double)(over & 0x0000003f)) / log10(2)
>> can have only 64 different values depending on the result of (over & 0x3f)?
>>
>> Obtain them from precomputed uint32_t log10table[64].
>> --
>> vda
>>
>>
> Hi Denis,
>
> Yes, the driver code so far only uses log10 twice, but there will be
> more uses for it as I populate the rest of the tables. However, I think
> its use will be some what limited. I wasn't aware that the floating
> point registers are not saved. I'll investigate a way to create a table
> with pre-calculated log10 values.
>
> Thanks,
>
>
> Carlos
Since the log in base n is the log in any base times a constant,
you can probably use log base 2 (binary bit position) and multiply
the result by a constant, which may simply be shifts and adds.
I assume you are using 16-bit audio. If so, the dynamic range
is only 20 * log10(2^16) = 96.3 dB. That means that attenuation
from mininum to maximum, in 1 dB steps, requires only 94 values.
Your code shows something whacked off at 0x3f = 0->0x40 = 64
20 * log10(64) = 36 dB for only 36 values. Clearly, you don't
need floating point, just some thought ahead of time.
Cheers,
Dick Johnson
Penguin : Linux version 2.6.15.4 on an i686 machine (5589.54 BogoMips).
Warning : 98.36% of all statistics are fiction, book release in April.
_
****************************************************************
The information transmitted in this message is confidential and may be privileged. Any review, retransmission, dissemination, or other use of this information by persons or entities other than the intended recipient is prohibited. If you are not the intended recipient, please notify Analogic Corporation immediately - by replying to this message or by sending an email to [email protected] - and destroy all copies of this information, including any attachments, without reading or disclosing them.
Thank you.
On Fri, 10 Mar 2006 13:33:02 -0500, linux-os (Dick Johnson) wrote:
>
> On Fri, 10 Mar 2006, Carlos Munoz wrote:
>
> > Denis Vlasenko wrote:
> >
> >> On Friday 10 March 2006 05:47, Carlos Munoz wrote:
> >>
> >>
> >>> Lee Revell wrote:
> >>>
> >>>
> >>>
> >>>> On Thu, 2006-03-09 at 19:25 -0800, Carlos Munoz wrote:
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>> I figured out how to get the driver to use floating point operations.
> >>>>> I included source code (from an open source math library) for the
> >>>>> log10 function in the driver. Then I added the following lines to the
> >>>>> file arch/sh/kernel/sh_ksyms.c:
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>> Where is the source code to your driver?
> >>>>
> >>>> Lee
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>
> >>> Hi Lee,
> >>>
> >>> Be warned. This driver is in the early stages of development. There is
> >>> still a lot of work that needs to be done (interrupt, dma, etc, etc).
> >>>
> >>>
> >>
> >> What? You are using log10 only twice!
> >>
> >> if (!(siu_obj_status & ST_OPEN)) {
> >> ...
> >> /* = log2(over) */
> >> ydef[22] = (u_int32_t)(log10((double)(over & 0x0000003f)) /
> >> log10(2));
> >> ...
> >> }
> >> else {
> >> ...
> >> if (coef) {
> >> ydef[16] = 0x03045000 | (over << 26) | (tap - 4);
> >> ydef[17] = (tap * 2 + 1);
> >> /* = log2(over) */
> >> ydef[22] = (u_int32_t)
> >> (log10((double)(over & 0x0000003f)) / log10(2));
> >> }
> >>
> >> Don't you think that log10((double)(over & 0x0000003f)) / log10(2)
> >> can have only 64 different values depending on the result of (over & 0x3f)?
> >>
> >> Obtain them from precomputed uint32_t log10table[64].
> >> --
> >> vda
> >>
> >>
> > Hi Denis,
> >
> > Yes, the driver code so far only uses log10 twice, but there will be
> > more uses for it as I populate the rest of the tables. However, I think
> > its use will be some what limited. I wasn't aware that the floating
> > point registers are not saved. I'll investigate a way to create a table
> > with pre-calculated log10 values.
> >
> > Thanks,
> >
> >
> > Carlos
>
> Since the log in base n is the log in any base times a constant,
> you can probably use log base 2 (binary bit position) and multiply
> the result by a constant, which may simply be shifts and adds.
>
> I assume you are using 16-bit audio. If so, the dynamic range
> is only 20 * log10(2^16) = 96.3 dB. That means that attenuation
> from mininum to maximum, in 1 dB steps, requires only 94 values.
>
> Your code shows something whacked off at 0x3f = 0->0x40 = 64
> 20 * log10(64) = 36 dB for only 36 values. Clearly, you don't
> need floating point, just some thought ahead of time.
>
> Cheers,
> Dick Johnson
As Bart pointed out earlier, what this code is really trying to do is not
log10(foo) but int(log2(foo)) for some positive integer foo. This can be
simply expressed as fls(foo)-1 for all foo < 0. No floating point
necessary.
--
Ben Slusky | Trust is your enemy.
[email protected] | -Dan Farmer and
[email protected] | Wietse Venema
PGP keyID ADA44B3B
On Fri, Mar 10, 2006 at 10:03:58AM -0800, Carlos Munoz wrote:
> > ydef[22] = (u_int32_t)(log10((double)(over & 0x0000003f)) /
> > log10(2));
You've got to be kidding. Let's take a good look at that expression:
log10(x)/log10(2) is what? Right, base-2 logarithm of x. Then you cast
it to unsigned, i.e. round it down. In other words, you want to know the
highest bit in (over & 0x3f). Which is to say, (fls(over & 0x3f) - 1).
Sigh...
Al Viro wrote:
>On Fri, Mar 10, 2006 at 10:03:58AM -0800, Carlos Munoz wrote:
>
>
>>> ydef[22] = (u_int32_t)(log10((double)(over & 0x0000003f)) /
>>> log10(2));
>>>
>>>
>
>You've got to be kidding. Let's take a good look at that expression:
>log10(x)/log10(2) is what? Right, base-2 logarithm of x. Then you cast
>it to unsigned, i.e. round it down. In other words, you want to know the
>highest bit in (over & 0x3f). Which is to say, (fls(over & 0x3f) - 1).
>Sigh...
>
>
Hi Al,
You are right, so easy. I will look at the data sheet and make sure the
same approach can be applied to all places calling for log10
calculations. I wonder why the data sheet calls for log10 calculations.
It threw me off... should have know better though.
Thanks,
Carlos Munoz