How to write ANY value

S

Sjouke Burry

Ben said:
The whole point was to not give x a value; please read back to
the beginning of the thread.
So *p gets random data from who knows what location? Right,
I did not know about that valuable mechanism......
 
I

Ian Collins

So *p gets random data from who knows what location? Right,
I did not know about that valuable mechanism......

Did you read the OP?

"Some memory-mapped devices require a write to a specific
memory address in order to do something.
The data written is of no importance."

Hardware watchdogs are a common example of this.
 
B

Ben Pfaff

Ian Collins said:
Did you read the OP?

"Some memory-mapped devices require a write to a specific
memory address in order to do something.
The data written is of no importance."

Hardware watchdogs are a common example of this.

Some 16-color EGA/VGA display modes were another case. Here's
the comment that I put into the Linux 16-color framebuffer driver
many years ago when I wrote it:

/* The VGA's weird architecture often requires that we read a byte and
write a byte to the same location. It doesn't matter *what* byte
we write, however. This is because all the action goes on behind
the scenes in the VGA's 32-bit latch register, and reading and writing
video memory just invokes latch behavior.

To avoid race conditions (is this necessary?), reading and writing
the memory byte should be done with a single instruction. One
suitable instruction is the x86 bitwise OR. The following
read-modify-write routine should optimize to one such bitwise
OR. */

(It seems that someone modified the code and didn't update the
comment, though, since the code no longer uses a single
instruction to do it. I guess it wasn't necessary.)
 
J

James Waldby

It might be useful to give x some value.......

The OP doesn't care what value is written, and just
wants a write to occur to a specific address. This is
a common paradigm in embedded systems, where you may
need to strobe an address via a read or write, and the
data involved is don't-care.

I have a 525-line C program that runs on an AT90S2313
(2K program memory, 128 byte SRAM) clocked at 500KHz
and if making changes occasionally have to look at the
assembly listing to figure out where I can save a few
cycles -- so I can understand the OP's concern about
unnecessarily loading a register. It's a bit more
difficult to understand the expectation of doing so
in a portable way.
 
E

Edward A. Falk

It doesn't as I would like.
My compiler stores 0 in reg, then reg to memory.
(as opposed to just storing a reg to memory)

My guess is that the compiler is generating code to initialize x.

I'd just leave it alone; we're talking like a billionth of a second
here.

By the way, more importantly:

volatile unsigned char *p;
 
K

Keith Thompson

aleksa said:
Some memory-mapped devices require a write to a specific
memory address in order to do something.
The data written is of no importance.

How can I instruct the compiler to write
whatever value it finds handy in that moment?

P.S.
That won't make the code much better, I'm just curious.

This might do what you want:

volatile register int junk;
volatile int *p = /* ... */;
*p = junk;

But there are no guarantees. You're trying to generate specific machine
code. A compiler's job is to generate machine code that has a specified
effect.
 
A

aleksa

It's a bit more difficult to understand the
expectation of doing so in a portable way.

I didn't know if this is doable in portable C,
so I've asked here to be sure.

Since it looks like it is not,
I could post it somewhere else.
 
A

aleksa

Since it looks like it is not,
I could post it somewhere else.

I've wrote this before seeing that
there is a next page in google.

Gordon Burditt's "last assignment statement"
and Keith Thompson's "register" are good ideas.

Thanks, everyone.
 
A

aleksa

Some memory-mapped devices require a write to a specific
memory address in order to do something.
The data written is of no importance.

How can I instruct the compiler to write
whatever value it finds handy in that moment?

P.S.
That won't make the code much better, I'm just curious.

Andreas B. has an excellent idea - storing the pointer to itself!
http://embdev.net/topic/209508

*p = p;

or

BYTE *adr = ...; // or WORD / DWORD
*adr = adr;

Tested it on ARM and am quite sure it works on IA32:
mov [eax],al
mov [eax],ax
mov [eax],eax
 
A

aleksa

mov [eax],al
mov [eax],ax
mov [eax],eax

I'm more interested in ARM and
didn't think much about IA32.

IA32 could just store immediate to
direct address - one instruction only.
 
T

Tim Rentsch

Ben Pfaff said:
This may work:

unsigned char x;

*p = x;

Be warned! Even using 'unsigned char', under C1X this will be
undefined behavior. One way to fix that:

unsigned char x[1];

*p = *x;
 
B

BartC

aleksa said:
Some memory-mapped devices require a write to a specific
memory address in order to do something.
The data written is of no importance.

How can I instruct the compiler to write
whatever value it finds handy in that moment?

Surely for anything like this, you'd just use some inline assembly (perhaps
wrapped in a macro).

I wouldn't trust the compiler; it might do it once, then the next time won't
bother because it thinks that location already contains the same value!
 
A

Anders Wegge Keller

BartC said:
I wouldn't trust the compiler; it might do it once, then the next
time won't bother because it thinks that location already contains
the same value!

That's why we have the volatile keyword.
 
A

Anders Wegge Keller

OK, but I'd still be wary of pretending i/o locations are really
variables.

Why?

A volatile declaration may be used to describe an object
corresponding to a memory-mapped input/output port or an object
accessed by an asynchronously interrupting function. Actions on
objects so declared shall not be ‘‘optimized out’’ by an
implementation or reordered except as permitted by the rules for
evaluating expressions.
 
B

Ben Bacarisse

Tim Rentsch said:
Be warned! Even using 'unsigned char', under C1X this will be
undefined behavior.

Can you point to the change please? I had a look in what seemed like
the obvious places but did not find any smoking gun.
One way to fix that:

unsigned char x[1];

*p = *x;
 
E

Eric Sosman

Why?

A volatile declaration may be used to describe an object
corresponding to a memory-mapped input/output port or an object
accessed by an asynchronously interrupting function. Actions on
objects so declared shall not be ‘‘optimized out’’ by an
implementation or reordered except as permitted by the rules for
evaluating expressions.

One problem is that "What constitutes an access to an object that
has volatile-qualified type is implementation-defined" (6.7.3p6). It
is often the case that a magical memory address performs its magic
only if accessed by the right kind of instruction: For example, an
"I/O register" at location 0xFF001010 might respond to a four-byte
load or store at that address but not even notice a one-byte access
to location 0xFF001012. Since there's no way to get C-the-language
to generate any particular hardware instruction, there's no way to be
sure C-the-language will use the one you desire.

(This is not a theoretical matter, by the way. I once asked a lead
kernel engineer for a large computer vendor why none of their device
drivers were written in C. Her answer amounted to essentially this
issue: The special locations in the hardware worked only when accessed
as a unit, not when accessed byte-by-byte, and there was no reliable way
to ensure that C would use the former -- *especially* if somebody chose
to compile with a "tolerate misaligned pointers" switch enabled...)

On a given implementation there may be ways to ensure that C uses
the desired instructions -- it could be as simple as reading the
implementation's documents. But you can't just shout `volatile' and
expect that all problems are solved, nor should you assume that the
solution for one machine will behave as desired on another.
 
A

Anders Wegge Keller

Eric Sosman said:
One problem is that "What constitutes an access to an object
that has volatile-qualified type is implementation-defined"
(6.7.3p6).

Yes, and I don't see that as a problem. After all, in the case where
any particular register is mapped into the address space, the
situation is already very specific.

...
(This is not a theoretical matter, by the way.

I know. BTDTGTT, and all that.
On a given implementation there may be ways to ensure that C
uses the desired instructions -- it could be as simple as reading
the implementation's documents. But you can't just shout `volatile'
and expect that all problems are solved, nor should you assume that
the solution for one machine will behave as desired on another.

Will you please decide if you want to discuss a specific
implementatio, or if you want to talk about a general case?

In the general case, adress 0x0842 has no universal meaning beyond
beaing an address. Thus, we never get to the point of having to worry
about different compilers ways with memory access.

In the specific case, on the other hand, where we acutally have a
well-defined meaning for that adress, I see no problem in acessing
it. I take it as a given that anyone doing low-level programming that
involves any amount of bit-baning will be competent enough to do so.
 
T

Tim Rentsch

Ben Bacarisse said:
Can you point to the change please? I had a look in what seemed like
the obvious places but did not find any smoking gun.

Sorry, I should have mentioned this - last sentence of 6.3.2.1p2:

If the lvalue designates an object of automatic storage
duration that could have been declared with the register
storage class (never had its address taken), and that object
is uninitialized (not declared with an initializer and no
assignment to it has been performed prior to use), the
behavior is undefined.
 
K

Keith Thompson

Anders Wegge Keller said:
In the general case, adress 0x0842 has no universal meaning beyond
beaing an address. Thus, we never get to the point of having to worry
about different compilers ways with memory access.
[...]

In the general case, 0x0842 is not an address at all; it's of
type int. It can be *converted* to some pointer type, and such
a conversion is "intended to be consistent with the addressing
structure of the execution environment".

We often refer to things like " address 0x0842", but that's either a
convenient verbal shorthand for the above conversion, or something
outside the scope of the C language. (Address 0x0842 might well
be a meaningful concept in the context of a particular CPU.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,767
Messages
2,569,570
Members
45,045
Latest member
DRCM

Latest Threads

Top