[net.arch] Strange architecture proposal

radford@calgary.UUCP (Radford Neal) (02/12/85)

Any comments on the following idea?


Take a machine with bytes, words, longs, etc. - all of sizes which are
a power of two of some basic unit - and which requires such data to be
aligned, with the address of a unit of size 2**N being required to have
N low-order zero bits.

Such a machine presumably has instructions for handling the different
data units - e.g. MOVEB, MOVEW, MOVEL, etc. Let's say there are no
registers, so a MOVE instruction always requires two memory addresses
to be specified in some fashion.


Here's the idea: Get rid of the MOVEB, MOVEW, MOVEL, etc. instructions
and replace them with a single MOVE instruction, with the type of 
unit to be moved determined by the memory address given. Addresses
have a new format, as for instance:

      0 0 1 A8 A7 A6 A5 A4 A3 A2

This example specifies a long operand (four bytes) with address

      A8 A7 A6 A5 A4 A3 A2 0 0

In general, the size of an operand is 2**N, where N is the number of
leading zeros in its address. The "actual" address is the bits after
the highest-order one bit, padded with zeros to make it come out the
the right size. In this scheme, the address

      0 0 0 0 0 0 0 0 0 1

addresses all of memory as a single block (assuming the scheme has been
carried to this extreme).


Notice that this format requires only a single extra bit in addresses
to encode the size of the object pointed to. This is possible because
traditional addresses on aligned machines waste information space, as
evidenced by the existence of illegal addresses (e.g. odd word addresses).

Notice also that this scheme is different from a "tagged" architecture
in that the size is a property of the POINTER, not of the data. If you
want to start looking at your integer as a series of bytes, you need only
shift your pointer left a bit, you don't have to change what's stored in
memory.

In addition to getting rid of all the various forms of MOVE instruction,
this scheme also gets rid of all the conversion instructions - moving
from a byte address to a long address automatically zero-extends. At most
you need two instructions, MOVEU and MOVES, to allow you a choice of
zero-extend or sign-extend.

Also, there is no need for "stride adjustment" with statements such as

    int *p;
    p += 1;

Adding one to an address always gets you the next element, regardless
of the size of the data type pointed to.


Finally, this scheme allows one to write more general subroutines than
one can without it, e.g. something like:

    long max(a,n)
      anyinttype a[];
      int n;
    { long r; int i;
      r = a[0];
      for (i = 1; i<n; i++) if (a[i]>r) r = a[i];
      return;
    }

should compile to efficient code which will find the maximum of an array
of bytes, words, or longs.


I can see a few problems here myself. A minor one is figuring out what
to do with registers - a simple register number won't contain the 
size information. The register numbers could be changed in the same 
fashion as the memory addresses to encode the size, or the registers could
be treated specially, always using all their bits for instance.

Another problem is that the shifting required to get the "real" address
might slow down the processor too much. Any ideas on how much?

Finally, any programs which actually used the flexibility illustrated 
by the "max" function above would become hopelessly un-portable to a
standard architecture.

    Radford Neal
    The University of Calgary

dmmartindale@watcgl.UUCP (Dave Martindale) (02/13/85)

I think the idea of having addresses encode the data type is ultimately
unworkable, for the following reasons:

1) How do you handle different data types of the same size?  For example,
   the VAX "long" and "float" data types are the same size, but have
   different move instructions.  Why?  The floating point one may fault
   on certain bit patterns (undefined operand) while the integer one
   had better not.

2) The addressing scheme assumes that every object is a power of 2 bytes
   in size.  What do you do about structures?  If their size is rounded
   up to the next power of 2, you may waste almost half of your memory.
   If their size is not rounded, then you need to come up with some way
   to represent a pointer to an odd-sized object that is not aligned
   on a power-of-two boundary; your addressing scheme does not handle
   this.

3) All objects must be aligned on a "natural" boundary.  While I am
   willing to tolerate the wasted memory or address space that results
   from aligning a 4-byte object on a 4-byte boundary, and even the
   occasional movement of something up to a 512-byte or 2048-byte boundary
   because of hardware page sizes, I don't think anyone will tolerate
   the requirement that a 4Mb table be aligned on a 4Mb boundary.
   (If you think this is a ridiculous example, and that the scheme would
   never be used for large blocks, I agree, but the original article showed
   how the addressing scheme provided a natural method for referencing
   all of memory.)

dmr@grigg.UUCP (02/15/85)

Radford Neal's suggestion, in which memory addresses encode the
size of the addressed object, is a good one, but it isn't new.
So far as I know, David Wheeler, of Cambridge University, was
the first to suggest it several years ago.  I don't know if it
was ever published.  We learned of it when he was visiting
Bell Labs, and have since called it "the Wheeler device."

Most of Martindale's objections to the idea aren't important.
Different data types of the same size:  so long as you accept
that floating add is an operation different from fixed add, and
(if you like) that the same is true for move, the fact that different
data types may be the same size doesn't matter.

The plan doesn't contemplate extending the idea to big data objects,
just the usual byte-to-quadword range.  

It does indeed require that objects be aligned on a boundary divisible
by their size.  There has been debate about this, but I don't think
it is an onerous requirement.

Neal worries about registers.  I don't think he should.  It all works
out if you just make register references use their full width; that is,
the Wheeler device is a gadget that fiddles with data going between
the CPU and memory, and has nothing to do with registers.

It deserves to be tried.

The potential advantage is that you can use the redundancy provided
by requiring alignment of operands to reduce the number of bits needed
for the opcode and/or address specification, while still providing
orthogonality of references.  The disadvantage is more complicated
decoding and the need to be careful when moving pointers around.

	Dennis Ritchie

radford@calgary.UUCP (Radford Neal) (02/16/85)

> I think the idea of having addresses encode the data type is ultimately
> unworkable, for the following reasons:
> 
> 1) How do you handle different data types of the same size?  For example,
>    the VAX "long" and "float" data types are the same size, but have
>    different move instructions...
> 
> 2) The addressing scheme assumes that every object is a power of 2 bytes
>    in size.  What do you do about structures?  If their size is rounded
>    up to the next power of 2, you may waste almost half of your memory.
>    If their size is not rounded, then you need to come up with some way
>    to represent a pointer to an odd-sized object...
> 
> 3) All objects must be aligned on a "natural" boundary. ... I don't think 
>    anyone will tolerate the requirement that a 4Mb table be aligned on a
>    4Mb boundary...

These are certainly problems of a sort, but I don't think they render the
scheme unworkable. 

With regard to (1): The scheme I propose manages to encode the "type" using
only one bit. The cost of this is that actually only the length of the
datum, not things like int vs. float are encoded in the pointer, so you
don't get a full "object-oriented" architecture. Instead, you would still
need an "integer-add" and a "floating-point-add" instruction. Whether you
still need an "integer-move" and a "floating-point-move" is open to
debate (I don't like traps on moves myself), but that's another subject.

If you want you can devote eight bits (or some such) to type information
in a pointer and get rid of all type specificity in operation codes, but
it costs more than one bit of course.

As for (2): Although I wouldn't totally rule out rounding structure sizes
to a power of two, I'm not really advocating that radical a solution. You
can copy structures with a loop like lots of machines do. I'd probably
limit the extent of the scheme to whatever the largest data type of the
machine is (8 byte quad integers or whatever).

This way you also don't have to align your 4MB table...

     Radford Neal
     The University of Calgary

bcase@uiucdcs.UUCP (02/18/85)

I first saw the Wheeler Device described in the Bell technical report:
"A 32-bit processor design" by Steve Johnson.  The description given
there pointed out that there is some redundancy in address specification
which can be used for a small degree of error checking.

radford@calgary.UUCP (Radford Neal) (02/21/85)

> ... Perhaps it would be more convenient to put the
> size encoding bits on the right.  The automatic "stride adjustment"
> feature goes away, but addresses no longer have to be shifted before
> use, the effects of arithmetic overflow during address computation
> are less painful, and direct comparison of pointers to objects of
> different sizes makes a little more sense....

The effects of overflow would indeed be more "expected" (wrap-around to
the beginning of memory rather than total garblement into a different
kind of pointer). However I'm not sure you save by getting rid of the
shift. The format of a pointer to a long would in that scheme be something
like

    A8 A7 A6 A5 A4 A3 A2 1 0 0

A1 and A0 would still have to be converted to 0 0 rather than 1 0, which
might be as bothersome as a shift.

Comparisons of pointers to different types could be done by casting them
to a common type as described below.

> I think the main problem with encoding size in addresses is that it
> would be necessary to override encoded size too often...

A properly written C program will use casts for all changes of pointer
type. E.g.

    short *a;
    ...
    *(char*)a = 1;

The cast in this code would be a run-time operation (shift left by one).
In the other direction -

    char *b;
    ...
    *(short*)b = 1;

The code is not guaranteed to work unless the pointer is properly aligned.
The run-time code for the cast is a shift right by one. A special shift
operation could be used that trapped if a one bit was shifted out, thus
detecting an alignment error at the time of the cast rather than when
the pointer is used (possibly much later).

All this requires only one additional machine instruction to handle
type overrides, which doesn't seem excessive even if they are common,
which they shouldn't be in modern programs.

BTW: One advantage of the scheme I hadn't thought of before is that is
certainly guarantees that zero isn't a valid pointer... -:)

    Radford Neal
    The University of Calgary

dan@petrus.UUCP (08/06/85)

> 
> Any comments on the following idea?
> 
> 
> Take a machine with bytes, words, longs, etc. - all of sizes which are
> a power of two of some basic unit - and which requires such data to be
> aligned, with the address of a unit of size 2**N being required to have
> N low-order zero bits.
> 
	...
> 
> Here's the idea: Get rid of the MOVEB, MOVEW, MOVEL, etc. instructions
> and replace them with a single MOVE instruction, with the type of 
> unit to be moved determined by the memory address given. Addresses
> have a new format, as for instance:
> 
>       0 0 1 A8 A7 A6 A5 A4 A3 A2
> 
> This example specifies a long operand (four bytes) with address
> 
>       A8 A7 A6 A5 A4 A3 A2 0 0
> 
> In general, the size of an operand is 2**N, where N is the number of
> leading zeros in its address. The "actual" address is the bits after
> the highest-order one bit, padded with zeros to make it come out the
> the right size. In this scheme, the address
> 

This is a neat idea.  Perhaps it would be more convenient to put the
size encoding bits on the right.  The automatic "stride adjustment"
feature goes away, but addresses no longer have to be shifted before
use, the effects of arithmetic overflow during address computation
are less painful, and direct comparison of pointers to objects of
different sizes makes a little more sense.  Think how much easier it
would be to explain this address representation to a freshman computer
programming class.  An extra machine instruction could be provided for
pointer arithmetic with automatic "stride adjustment".

I think the main problem with encoding size in addresses is that it
would be necessary to override encoded size too often (I guess I don't
really know this -- hacking a C compiler to gather statistics is too
much work).  What kind of machine language would a C compiler generate
to access structure members?