comp.lang.ada
 help / color / mirror / Atom feed
* Caching & Annex C.6
@ 1999-09-03  0:00 Simon Wright
  1999-09-05  0:00 ` Robert Dewar
  1999-09-07  0:00 ` David Kristola
  0 siblings, 2 replies; 12+ messages in thread
From: Simon Wright @ 1999-09-03  0:00 UTC (permalink / raw)


In C.6 the AARM says

16 For a volatile object all reads and updates of the object as a
   whole are performed directly to memory.

   16.a Implementation Note: This precludes any use of register
      temporaries, caches, and other similar optimizations for that
      object.

We've been having an argument as to precisely what sort of "cache"
we're talking about here. Is it the CPU cache? does this imply that an
implementation must force a cache write-through for volatile objects?

My personal view is that the existence or otherwise of the cache is
transparent and that all that's required is that the write doesn't go
to registers. But then why does the AARM mention cache?

Are there (multi-processor, presumably) systems where you would have
to force a write-through to get the proper effect? Do Ada
implementations on such systems have to do that?

-- 
Simon Wright                        Work Email: simon.j.wright@gecm.com
Alenia Marconi Systems                         Voice: +44(0)1705-701778
Integrated Systems Division                      FAX: +44(0)1705-701800




^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Caching & Annex C.6
  1999-09-03  0:00 Caching & Annex C.6 Simon Wright
@ 1999-09-05  0:00 ` Robert Dewar
  1999-09-05  0:00   ` Simon Wright
  1999-09-07  0:00 ` David Kristola
  1 sibling, 1 reply; 12+ messages in thread
From: Robert Dewar @ 1999-09-05  0:00 UTC (permalink / raw)


In article <x7vyaenahw3.fsf@pogner.moho>,
  Simon Wright <simon@pogner.demon.co.uk> wrote:
> Are there (multi-processor, presumably) systems where you
would have
> to force a write-through to get the proper effect?

yes

 Do Ada
> implementations on such systems have to do that?

yes

The point is that for non-volatile objects, which you know
cannot be shared variables in the Ada sense, it is safe
to put them in cache, even if the cache is non-coherent,
but the point is that Volatile prevents this "optimization".

Machines with non-coherent caches always have a way of
signalling selected data as being non-cachable, forcing
access to a shared memory (well let's say, that's true
of shared memory machines).



Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.




^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Caching & Annex C.6
  1999-09-05  0:00 ` Robert Dewar
@ 1999-09-05  0:00   ` Simon Wright
  0 siblings, 0 replies; 12+ messages in thread
From: Simon Wright @ 1999-09-05  0:00 UTC (permalink / raw)


Robert Dewar <robert_dewar@my-deja.com> writes:

> Machines with non-coherent caches always have a way of
> signalling selected data as being non-cachable, forcing
> access to a shared memory

Oh, that's good. Can anyone name a typical machine of this type? (so I
know when to start worrying)

>                           (well let's say, that's true
> of shared memory machines).

Of course if it didn't have shared memory you wouldn't care .. I
suppose




^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Caching & Annex C.6
  1999-09-03  0:00 Caching & Annex C.6 Simon Wright
  1999-09-05  0:00 ` Robert Dewar
@ 1999-09-07  0:00 ` David Kristola
  1999-09-08  0:00   ` Robert Dewar
  1 sibling, 1 reply; 12+ messages in thread
From: David Kristola @ 1999-09-07  0:00 UTC (permalink / raw)


In article fsf@pogner.moho, Simon Wright <simon@pogner.demon.co.uk> () writes:
>In C.6 the AARM says
>
>16 For a volatile object all reads and updates of the object as a
>   whole are performed directly to memory.
>
>   16.a Implementation Note: This precludes any use of register
>      temporaries, caches, and other similar optimizations for that
>      object.
>
>We've been having an argument as to precisely what sort of "cache"
>we're talking about here. Is it the CPU cache? does this imply that an
>implementation must force a cache write-through for volatile objects?
>
>My personal view is that the existence or otherwise of the cache is
>transparent and that all that's required is that the write doesn't go
>to registers. But then why does the AARM mention cache?
>
>Are there (multi-processor, presumably) systems where you would have
>to force a write-through to get the proper effect? Do Ada
>implementations on such systems have to do that?


I work with real-time embedded systems, and we use pragma
Volatile to mark variables that represent (and are located
on) memory mapped registers.  The data must be written to
the memory mapped register when that code executes.
Likewise, many of those registers return values set by
hardware, so reads can't come from the cache.


--djk, keeper of arcane lore & trivial fluff
Home: David95037 at aol dot com
Spam: goto.hades@welovespam.com





^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Caching & Annex C.6
  1999-09-07  0:00 ` David Kristola
@ 1999-09-08  0:00   ` Robert Dewar
  1999-09-08  0:00     ` David Kristola
  0 siblings, 1 reply; 12+ messages in thread
From: Robert Dewar @ 1999-09-08  0:00 UTC (permalink / raw)


In article <7r1l93$9lq4@svlss.lmms.lmco.com>,
  dkristol@see-my.sig wrote:
> I work with real-time embedded systems, and we use pragma
> Volatile to mark variables that represent (and are located
> on) memory mapped registers.  The data must be written to
> the memory mapped register when that code executes.
> Likewise, many of those registers return values set by
> hardware, so reads can't come from the cache.

But usually the ensurance of non-caching of these addresses
will be done at the hardware level, it is not something the
compiler worries about. The compiler's responsibility is
simply to issue loads and stores, someone else must make
sure that the loads and stores work as planned (for example
on the MIPS one bit of the address space is used to indicate
cachability). There are machines with different loads and
stores to control caching, but not many!


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.




^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Caching & Annex C.6
  1999-09-08  0:00   ` Robert Dewar
@ 1999-09-08  0:00     ` David Kristola
  1999-09-08  0:00       ` Robert Dewar
  0 siblings, 1 reply; 12+ messages in thread
From: David Kristola @ 1999-09-08  0:00 UTC (permalink / raw)


In article 1@nnrp1.deja.com, Robert Dewar <robert_dewar@my-deja.com> () writes:
>In article <7r1l93$9lq4@svlss.lmms.lmco.com>,
>  dkristol@see-my.sig wrote:
>> I work with real-time embedded systems, and we use pragma
>> Volatile to mark variables that represent (and are located
>> on) memory mapped registers.  The data must be written to
>> the memory mapped register when that code executes.
>> Likewise, many of those registers return values set by
>> hardware, so reads can't come from the cache.
>
>But usually the ensurance of non-caching of these addresses
>will be done at the hardware level, it is not something the
>compiler worries about. The compiler's responsibility is
>simply to issue loads and stores, someone else must make
>sure that the loads and stores work as planned (for example
>on the MIPS one bit of the address space is used to indicate
>cachability). There are machines with different loads and
>stores to control caching, but not many!

True.  Those memory mapped register variables are also
placed at the correct location using the uncached
address in the representation specification.

And after being burned by one compiler, i started using
appropriately sized integers for the register overlay,
and calling unchecked conversion to convert the data
to the register's record structure.  This eliminated
the compiler's optimization which inadvertently read and
wrote bytes on either side of the register.  Those bytes
happened to be parts of other registers, and the hardware
did not handle byte access properly.  That particular bug
took a while to track down.


--djk, keeper of arcane lore & trivial fluff
Home: David95037 at aol dot com
Spam: goto.hades@welovespam.com





^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Caching & Annex C.6
  1999-09-08  0:00     ` David Kristola
@ 1999-09-08  0:00       ` Robert Dewar
  1999-09-09  0:00         ` Memory mapped registers (was Re: Caching & Annex C.6) David Kristola
  0 siblings, 1 reply; 12+ messages in thread
From: Robert Dewar @ 1999-09-08  0:00 UTC (permalink / raw)


In article <7r4ted$e892@svlss.lmms.lmco.com>,
  dkristol@see-my.sig wrote:
> This eliminated
> the compiler's optimization which inadvertently read and
> wrote bytes on either side of the register.  Those bytes
> happened to be parts of other registers, and the hardware
> did not handle byte access properly.  That particular bug
> took a while to track down.

That is not an optimization, it is a perfectly reasonable
and valid translation of the Ada code. It is always very
risky, and very implementation dependent, to assume you
know exactly what machine instructions the compiler will
generate for a given construct.

If you need an exact load/store instruction, it is really
much more appropriate to use an asm insertion to specify
the exact instruction you need, rather than coax the
compiler into generating the instruction you want. The
latter is often highly non-portable, and can introduce
insufficiently documented implementation dependencies
in innocent looking code. Who would think that

   A := 0;

could be a highly target dependent piece of code?

One of the worst cases I saw of this was the following,
someone had:
   Size : integer := 31;
   ...
   type x is array (0 .. Size) of Boolean;
   pragma Pack (x);
   for x use at bla bla;

so far, so good, a typical memory mapped I/O specification.

The code had things like

   Status := x (13);

This worked fine on compiler V, but blew up on GNAT. Why?
Because on the machine in question there were both word
and byte loads and stores, neither being particularly
preferred.

 Compiler V did a word load and a bit mask.
 GNAT did a byte load and a bit mask

But the hardware had been built only to recognize word loads,
and it blew up at the hardware level for a byte load, delivering
random data to the bus (wonderful eh?)

Needless to say this was hard to find. The kludge put in to fix
this was to make the size constant, in which case GNAT now knows
that the variable in question is exactly 32 bits long, and
happens to do a word load, but this is really a very brittle
way of "fixing" this. Much better would be to issue the exact
instruction required.

That being said, the suggestion of using integer is probably
a good one, and this wlil likely minimize the possibility of
unexpected code generation.

<< That particular bug took a while to track down >>

Yes, indeed bugs like this in Ada code are devilish hard
to find. And all too often people decide that their code
cannot be at fault because it worked once upon a time. We
have too often encountered situations where managers have
been sold on the fiction that because their code is in
Ada, it will be zero effort to port it to new platforms
or new compilers :-(

Robert Dewar
Ada Core Technologies


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.




^ permalink raw reply	[flat|nested] 12+ messages in thread

* Memory mapped registers (was Re: Caching & Annex C.6)
  1999-09-08  0:00       ` Robert Dewar
@ 1999-09-09  0:00         ` David Kristola
  1999-09-09  0:00           ` Robert Dewar
  0 siblings, 1 reply; 12+ messages in thread
From: David Kristola @ 1999-09-09  0:00 UTC (permalink / raw)


In article 1@nnrp1.deja.com, Robert Dewar <robert_dewar@my-deja.com> () writes:
>In article <7r4ted$e892@svlss.lmms.lmco.com>,
>  dkristol@see-my.sig wrote:
>> This eliminated
>> the compiler's optimization which inadvertently read and
>> wrote bytes on either side of the register.  Those bytes
>> happened to be parts of other registers, and the hardware
>> did not handle byte access properly.  That particular bug
>> took a while to track down.
>
>That is not an optimization, it is a perfectly reasonable
>and valid translation of the Ada code. It is always very
>risky, and very implementation dependent, to assume you
>know exactly what machine instructions the compiler will
>generate for a given construct.

A 32 bit record was located on a proper word boundary,
and the compiler generated (MIPS) instructions to read
4 bytes from two different words (LWL, LWR if i remember
the mnemonic correctly) so that it could save a shift
to get to the bit it was interested in (it shifted the
address instead).  It may not have been an optimization.
As far as i could tell, it was a less efficient way to
get the desired bit from and then back out to memory.

>If you need an exact load/store instruction, it is really
>much more appropriate to use an asm insertion to specify
>the exact instruction you need, rather than coax the
>compiler into generating the instruction you want. The
>latter is often highly non-portable, and can introduce
>insufficiently documented implementation dependencies
>in innocent looking code. Who would think that
>
>   A := 0;
>
>could be a highly target dependent piece of code?

   Memory_Mapped_Register := Convert(Register_Record);

The name and purpose of the package would give away
the fact that it is not portable code.  How many
serial I/O boards (made for our program's concept of
RS-422) are made equal?


>One of the worst cases I saw of this was the following,
>someone had:
>   Size : integer := 31;
>   ...
>   type x is array (0 .. Size) of Boolean;
>   pragma Pack (x);
>   for x use at bla bla;
>
>so far, so good, a typical memory mapped I/O specification.
>
>The code had things like
>
>   Status := x (13);
>
>This worked fine on compiler V, but blew up on GNAT. Why?
>Because on the machine in question there were both word
>and byte loads and stores, neither being particularly
>preferred.
>
> Compiler V did a word load and a bit mask.
> GNAT did a byte load and a bit mask
>
>But the hardware had been built only to recognize word loads,
>and it blew up at the hardware level for a byte load, delivering
>random data to the bus (wonderful eh?)

Been there, stepped through it in a debugger or watched it
on the DAS, scratched my head, but never got the T-shirt.

>Needless to say this was hard to find. The kludge put in to fix
>this was to make the size constant, in which case GNAT now knows
>that the variable in question is exactly 32 bits long, and
>happens to do a word load, but this is really a very brittle
>way of "fixing" this. Much better would be to issue the exact
>instruction required.

I suppose i could have come up with a generic to
read/write 32 bit registers and had the body explicitly
perform the correct assembly code, then instantiate it
for all of the different registers.  Would this be
portable from compiler to compiler?

>That being said, the suggestion of using integer is probably
>a good one, and this wlil likely minimize the possibility of
>unexpected code generation.

Integers are atomic, and of the proper size.  It did
work well with that compiler (probably "V").

><< That particular bug took a while to track down >>
>
>Yes, indeed bugs like this in Ada code are devilish hard
>to find. And all too often people decide that their code
>cannot be at fault because it worked once upon a time. We
>have too often encountered situations where managers have
>been sold on the fiction that because their code is in
>Ada, it will be zero effort to port it to new platforms
>or new compilers :-(

My apologies to Bruce, it was his hardware, and i did
blame him for a long time.  In the end, it was excellent
hardware.  I wish we were reusing it on this project,
it would solve one of my current dilemmas.

Porting code is usually not an issue.  There aren't too
many uses for the special software/hardware that gets
developed around here.

There is a growing awareness of the usefulness of reuse,
and an effort to actually start reusing software.  Only
it is a slow process.  If more hardware were reused,
there would be more call for software reuse.  :-(


--djk, keeper of arcane lore & trivial fluff
Home: David95037 at aol dot com
Spam: goto.hades@welovespam.com





^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Memory mapped registers (was Re: Caching & Annex C.6)
  1999-09-09  0:00         ` Memory mapped registers (was Re: Caching & Annex C.6) David Kristola
@ 1999-09-09  0:00           ` Robert Dewar
  1999-09-14  0:00             ` Memory mapped registers (was Re: Cachi David Kristola
  0 siblings, 1 reply; 12+ messages in thread
From: Robert Dewar @ 1999-09-09  0:00 UTC (permalink / raw)


In article <7r7ljl$sdi6@svlss.lmms.lmco.com>,
  dkristol@see-my.sig wrote:
> A 32 bit record was located on a proper word boundary,
> and the compiler generated (MIPS) instructions to read
> 4 bytes from two different words (LWL, LWR if i remember
> the mnemonic correctly) so that it could save a shift
> to get to the bit it was interested in (it shifted the
> address instead).  It may not have been an optimization.
> As far as i could tell, it was a less efficient way to
> get the desired bit from and then back out to memory.

The LWL/LWR sequence is used when the compiler does not know
that a word is located on a proper word boundary, and is
typically the most efficient sequence in this case. Now
the issue of *why* the compiler did not know is an interesting
one, but that's the point, you should not be worrying at this
level. In fact it sounds like this was not an optimization, but
a LACK of an optimization that caused you trouble.


> The name and purpose of the package would give away
> the fact that it is not portable code.  How many
> serial I/O boards (made for our program's concept of
> RS-422) are made equal?

Ah ha! But what if you switch to another compiler. The issue
is not porting to other targets, but other compilers. We have
seen issues like this come up all the time!

>
> Porting code is usually not an issue.  There aren't too
> many uses for the special software/hardware that gets
> developed around here.

I think an awful lot of code is developed under this
assumption, and then it turns out, for example, that
there is a decision to switch to Ada 95, and suddenly
you are in the porting business.

Remember, I did not say that it was wrong to write non-portable
code, that is often completely justified. What I said was that
non-portable code should be clearly identified.

Code that depends on the particular code generation behavior
of the compiler is particularly brittle, because even a new
version or minor update of a compiler can change the generated
code in what should be a harmless manner, but which may not
be if the code has made unwarranted assumptions.

Some of the early Linux kernel code made this mistake (and
depended on the exact sequence of code generated by gcc,
resulting in continued discussions over whether gcc was
doing the right thing -- in some cases, it was, but it
still broke the kernel). This is now all fixed nicely in
Linux. You should aim at fixing similar code you have in
your applications :-)


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.




^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Memory mapped registers (was Re: Cachi
  1999-09-09  0:00           ` Robert Dewar
@ 1999-09-14  0:00             ` David Kristola
  1999-09-14  0:00               ` Robert Dewar
  0 siblings, 1 reply; 12+ messages in thread
From: David Kristola @ 1999-09-14  0:00 UTC (permalink / raw)


In article 1@nnrp1.deja.com, Robert Dewar <robert_dewar@my-deja.com> () writes:
>In article <7r7ljl$sdi6@svlss.lmms.lmco.com>,
>  dkristol@see-my.sig wrote:
>> The name and purpose of the package would give away
>> the fact that it is not portable code.  How many
>> serial I/O boards (made for our program's concept of
>> RS-422) are made equal?
>
>Ah ha! But what if you switch to another compiler. The issue
>is not porting to other targets, but other compilers. We have
>seen issues like this come up all the time!

True.  Now the question becomes "how do we programmers
identify non-portable code?"  The record with a rep
clause carefully laying out the fields and placing it
at the correct address seemed quite portable.  It just
didn't work correctly.

>Remember, I did not say that it was wrong to write non-portable
>code, that is often completely justified. What I said was that
>non-portable code should be clearly identified.

I agree with this.

>Code that depends on the particular code generation behavior
>of the compiler is particularly brittle, because even a new
>version or minor update of a compiler can change the generated
>code in what should be a harmless manner, but which may not
>be if the code has made unwarranted assumptions.

There are assumptions and there are assumptions.
Someone once told me that they never make any
assumptions.  But i went for a ride with them
once, and they did not stop at green lights (they
assumed the cross traffic was stopping).

The problem is defining "unwarranted".

I still prefer the idea of mapping an
appropriately sized integer to the memory mapped
register then using unchecked conversion to turn
the data into a proper record for that register.
I think it is reasonable to assume that all
compilers will use the appropriate load and store
instructions under these circumstances.  This
should also prove to be more portable than machine
code insertion (which is implementation
dependent).  If i had a register that crossed
several memory cells, and they had to be
referenced in a specific order, then i would
resort to a low level solution, and not expect it
to be portable to a new compiler (and flag it as
such).

>Some of the early Linux kernel code made this mistake (and
>depended on the exact sequence of code generated by gcc,
>resulting in continued discussions over whether gcc was
>doing the right thing -- in some cases, it was, but it
>still broke the kernel). This is now all fixed nicely in
>Linux. You should aim at fixing similar code you have in
>your applications :-)

I always aim to improve my code.  Sometimes i
miss.  If someone can point out a better way of
doing something, then i will learn a new trick.
That is a good day.


--djk, keeper of arcane lore & trivial fluff
Home: David95037 at aol dot com
Spam: goto.hades@welovespam.com





^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Memory mapped registers (was Re: Cachi
  1999-09-14  0:00             ` Memory mapped registers (was Re: Cachi David Kristola
@ 1999-09-14  0:00               ` Robert Dewar
  1999-09-15  0:00                 ` David Kristola
  0 siblings, 1 reply; 12+ messages in thread
From: Robert Dewar @ 1999-09-14  0:00 UTC (permalink / raw)


In article <7rkkk6$iog2@svlss.lmms.lmco.com>,
  dkristol@see-my.sig wrote:
> True.  Now the question becomes "how do we programmers
> identify non-portable code?"  The record with a rep
> clause carefully laying out the fields and placing it
> at the correct address seemed quite portable.  It just
> didn't work correctly.

Seemed quite portable? What does that mean? That the syntax
was right, and the compiler did not reject it, and it worked?
But that's not good enough! You need to *know* what is and
what is not defined in the language, and the only way to know
this is to read the definition of the language, and really
know the definition well. This is a hard task for many
programmers, and is the most common failure that results
in non-portable code.

> >Remember, I did not say that it was wrong to write
non-portable
> >code, that is often completely justified. What I said was
that
> >non-portable code should be clearly identified.
>
> I agree with this.
>
> >Code that depends on the particular code generation behavior
> >of the compiler is particularly brittle, because even a new
> >version or minor update of a compiler can change the
generated
> >code in what should be a harmless manner, but which may not
> >be if the code has made unwarranted assumptions.
>
> There are assumptions and there are assumptions.
> Someone once told me that they never make any
> assumptions.  But i went for a ride with them
> once, and they did not stop at green lights (they
> assumed the cross traffic was stopping).
>
> The problem is defining "unwarranted".

Nope! There is no problem whatsoever in defining unwarranted.
The definition of the language tells you quite precisely what
you can and cannot count on, and any time you rely on behavior
that is described as one of the following

  unspecified
  erroneous
  implementation dependent
  implementation defined
  bounded error

you should document the fact, and similarly if you rely on
behavior of the compiler that is nowhere guaranteed in the RM,
e.g. performance requirements or, as in this case, specific
generated code sequences, you also need to carefully document
the non-portability.

> I still prefer the idea of mapping an
> appropriately sized integer to the memory mapped
> register then using unchecked conversion to turn
> the data into a proper record for that register.

Neither is portable

> I think it is reasonable to assume that all
> compilers will use the appropriate load and store
> instructions under these circumstances.

Why is this a reasonable assumption? If you need an
"appropriate" load/store instruction, then why not
write the instruction you need explicitly! For example
if you write:

   A := B;

and these are 32-bit integers, it is quite fine on some
machines to use a 32-bit floating load and store, to save
integer register pressure. Furthermore, a clever compiler
might be able to use a 64-bit floating load and get two
loads for the price of one!

> This
> should also prove to be more portable than machine
> code insertion (which is implementation
> dependent).

Well it is not portable, more portable means that you may
get away with not having to rewrite it for a given port,
but the huge danger, as apparently in this case, is that
the potential non-portability does not get flagged. By
using a machine code insertion, you definitely flag this
as something that needs looking at in a port.



Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.




^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Memory mapped registers (was Re: Cachi
  1999-09-14  0:00               ` Robert Dewar
@ 1999-09-15  0:00                 ` David Kristola
  0 siblings, 0 replies; 12+ messages in thread
From: David Kristola @ 1999-09-15  0:00 UTC (permalink / raw)


In article 1@nnrp1.deja.com, Robert Dewar <robert_dewar@my-deja.com> () writes:
>Well it is not portable, more portable means that you may
>get away with not having to rewrite it for a given port,
>but the huge danger, as apparently in this case, is that

The LWL/LWR & SWL/SWR problem was not a porting problem.
That code was original, and now sits on a tar tape in
a storage container locked in a room somewhere in building
151 (along with the hardware it ran on).  The world is
safe from that bit of code (the unchecked conversion to
a 32 bit integer, the code that generated the LWL/LWR
sequence was altered long ago).

The LWL/LWR part worked.  The SWL/SWR caused the hardware
to place bad data in an unintended register.  Even if
the memory at the address functioned in a byte addressable
way, memory outside the register would have been written.

>the potential non-portability does not get flagged. By
>using a machine code insertion, you definitely flag this
>as something that needs looking at in a port.

I shall use machine code insertions for this sort of
implementation in the future.  Thanks for pointing
out the potential problems.

Or, in other words: "Uncle!"  ;-)


--djk, keeper of arcane lore & trivial fluff
Home: David95037 at aol dot com
Spam: goto.hades@welovespam.com





^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~1999-09-15  0:00 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1999-09-03  0:00 Caching & Annex C.6 Simon Wright
1999-09-05  0:00 ` Robert Dewar
1999-09-05  0:00   ` Simon Wright
1999-09-07  0:00 ` David Kristola
1999-09-08  0:00   ` Robert Dewar
1999-09-08  0:00     ` David Kristola
1999-09-08  0:00       ` Robert Dewar
1999-09-09  0:00         ` Memory mapped registers (was Re: Caching & Annex C.6) David Kristola
1999-09-09  0:00           ` Robert Dewar
1999-09-14  0:00             ` Memory mapped registers (was Re: Cachi David Kristola
1999-09-14  0:00               ` Robert Dewar
1999-09-15  0:00                 ` David Kristola

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox