Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Help with use of m as qualifier in asm code

15 views
Skip to first unread message

Sian Mountbatten

unread,
Jan 1, 2012, 8:52:56 AM1/1/12
to
I am trying to find some way of converting floating point numbers
to integers. In Algol 68 their are two ways: two operators, ROUND
and ENTIER. The former uses rounding up to the nearest integer
while the latter rounds down to the next integer.

To ensure that the floating point unit does its rounding correctly,
I change the floating point unit control word. The two 16-bit
definitions of the control word are found here:
==================
SHORT BITS fpu cw algol68 round = SHORT 2r1111 00 11 11 100010;
SHORT BITS fpu cw algol68 entier = SHORT 2r0000 01 00 00 000000;
==================

The operator ROUND gets the current value of the control word
as a 16-bit unsigned integer (SHORT BITS). Then it sets the
fpu control word to the required value. After the rounding has
taken place, the original value of the control word is restored.
Here is the relevant code in Algol 68:
==================
OP ROUND = (REAL r)INT:
(
INT n;
SHORT BITS ocw; get fpu cw(ocw);
set fpu cw(ocw & fpu cw algol68 round);
ph round(r,n);
set fpu cw(ocw);
n
);

OP ENTIER = (REAL r)INT:
(
INT n;
SHORT BITS ocw; get fpu cw(ocw);
set fpu cw(ocw & fpu cw algol68 round OR fpu cw algol68 entier);
ph round(r,n);
set fpu cw(ocw);
n
);
===================
In the code below, I use =m and m as modifiers in the __asm__ code:

PROC(REF SHORT BITS)VOID get fpu cw = ALIEN "GET_FPU_CW"
"#define GET_FPU_CW(cw) __asm__(""fnstcw %0"" : ""=m"" (*cw))";

PROC(SHORT BITS)VOID set fpu cw = ALIEN "SET_FPU_CW"
"#define SET_FPU_CW(cw) __asm__ volatile(""fnclex; fldcw %0"" :: ""m""
(cw))";

What's wrong with that?

gcc gives
=====================
spops.c: In function ‘YGAAASP_entier’:
spops.c:1244:1: error: memory input 0 is not directly addressable
spops.c: In function ‘TGAAASP_round’:
spops.c:1218:1: error: memory input 0 is not directly addressable
=====================
Why is memory input 0 not directly addressable? And what do I do
to get these routines to work?

Any help will be greatly appreciated.

TIA
--
Dr Sian Mountbatten
User of siduction

Andrew Haley

unread,
Jan 1, 2012, 11:08:07 AM1/1/12
to
Sian Mountbatten <poen...@fastmail.co.uk> wrote:
> I am trying to find some way of converting floating point numbers
> to integers. In Algol 68 their are two ways: two operators, ROUND
> and ENTIER. The former uses rounding up to the nearest integer
> while the latter rounds down to the next integer.
>
> In the code below, I use =m and m as modifiers in the __asm__ code:
>
> PROC(REF SHORT BITS)VOID get fpu cw = ALIEN "GET_FPU_CW"
> "#define GET_FPU_CW(cw) __asm__(""fnstcw %0"" : ""=m"" (*cw))";
>
> PROC(SHORT BITS)VOID set fpu cw = ALIEN "SET_FPU_CW"
> "#define SET_FPU_CW(cw) __asm__ volatile(""fnclex; fldcw %0"" :: ""m""
> (cw))";
>
> What's wrong with that?
>
> gcc gives
> =====================
> spops.c: In function ?YGAAASP_entier?:
> spops.c:1244:1: error: memory input 0 is not directly addressable
> spops.c: In function ?TGAAASP_round?:
> spops.c:1218:1: error: memory input 0 is not directly addressable
> =====================
> Why is memory input 0 not directly addressable? And what do I do
> to get these routines to work?

It really is hard to say, because you haven't provided spops.c. Can
you provide a self-contained program that reproduces the problem?
What you're doing looks reasonable enough; for example, this C works;

int GET_FPU_CW()
{
int z;
__asm__("fnstcw %0" : "=m"(z));
return z;
}

Andrew.

Sian Mountbatten

unread,
Jan 3, 2012, 6:41:50 PM1/3/12
to
Here is the output of spops.c for ROUND:
================================
A68_INT TGAAASP_round(A68_REAL R)
{
A68_INT UGAAASP_n;
A68_SBITS VGAAASP_ocw;
A68_INT WGAAASP; /* clause result */
A_PROC_ENTRY(round);
/* line 101: */
/* line 102: */
{
/* line 103: */
VFAAASP_getfpucw((&VGAAASP_ocw));
/* line 104: */
WFAAASP_setfpucw((A68_SBITS )(VGAAASP_ocw&QGAAASP_fpucwalgol68round));
/* line 105: */
XFAAASP_phround(R, (&UGAAASP_n));
/* line 106: */
WFAAASP_setfpucw(VGAAASP_ocw);
/* line 107: */
/* line 108: */
WGAAASP = UGAAASP_n;
}
A_PROC_EXIT(round);
return( WGAAASP );
}
#undef NL
================================
And here are the two 16-bit definitions
================================
#define QGAAASP_fpucwalgol68round 0Xf3e2U
#define RGAAASP_fpucwalgol68entier 0X400U
================================
Not being a C programmer, I find it hard to produce a working C program.
Can you manage with the code snippet I've given? If not, I'll try to
produce a working C program.

Regards

Sian Mountbatten

unread,
Jan 3, 2012, 6:55:59 PM1/3/12
to
Here is a working C program which uses your function.
===================
#include <stdio.h>

int GET_FPU_CW()
{
int z;
__asm__("fnstcw %0" : "=m"(z));
return z;
}

main()
{
printf("%x",GET_FPU_CW());
}
===================
I note that you do not use a *z parameter. So I shall change the
get fpu cw routine to yield a value rather than assign to a parameter.
I shall also change the ph round routine.

Let's see what happens.

Sian Mountbatten

unread,
Jan 4, 2012, 9:30:47 AM1/4/12
to
Sian Mountbatten wrote:

> Sian Mountbatten wrote:
>
>> Andrew Haley wrote:
>>
>>> Sian Mountbatten <poen...@fastmail.co.uk> wrote:
>>>> I am trying to find some way of converting floating point numbers
>>>> to integers. In Algol 68 their are two ways: two operators, ROUND
>>>> and ENTIER. The former uses rounding up to the nearest integer
>>>> while the latter rounds down to the next integer.
>>>>
>
> Let's see what happens.
Many thanks for your example, Andrew. It was instructive and I have now
rewritten the routines and solved the problem.
0 new messages