From: eepjm@wombat.newcastle.edu.au (Peter Moylan)
Subject: Re: Generic stack implementation
Organization: University of Newcastle, AUSTRALIA
Date: Tue, 15 Dec 1992 23:47:28 GMT

I wrote:

> TopSpeed Modula-2 won't let you do arithmetic on addresses.  And a
> good thing, too, in my opinion.  Address arithmetic is one of the
> most non-portable things you can do, and I'm a little shocked to
> see an example of it in a textbook.

Randy Bush wrote:
 
> Hmmm.  As one of M2's stated design goals was to be able to write the entire
> operating system in M2.  Hence, one wants to write storage [de]allocators,
> device drivers for devices that use multiple addresses, ...
> 
> So, the issue is what is a reasonable zero-cost safety to put around the
> mechanism so it is not accidentally misused?

As someone who has written an OS in M2, I think I have a good answer
to this.  To handle those _very rare_ occasions where doing funny things
with addresses is necessary, I've written a module MemoryModel which
does things like
 - define a type PhysicalAddress (which is a LONGCARD in my current
   implementation, but could be other things on other machines);
 - add a CARDINAL to an address, producing another address where
   possible;
 - subtract a CARDINAL from an address, producing another address where
   possible;
 - convert a virtual address to a physical address;
 - convert a physical address to a virtual address, if possible.
and so on.  The "if possible" conditions here refer to the fact that
an error condition should be raised for things like running off the
end of a segment in a segmented architecture, comparing addresses in
different segments, etc.

The implementation I've done is for the 80x86 variety of processor,
and is of course very machine-dependent; but I was careful to set up
the definition module so that the caller did not have to know things
like whether memory was segmented.

The idea here was that it should be very unusual to import from
MemoryModel, so that uses of it stand out.  (From memory, I think
my software imports from MemoryModel in only three places: in the
storage allocator, in the module which sets up DMA transfers, and
in the screen I/O module (which, for the IBM-PC type of machine, needs
some initialisation code which works out what sort of screen adaptor
is present and from that works out where the memory-mapped screen
segment is).  Furthermore, I make sure that I don't use address
arithmetic anywhere else.

I know that Wirth's original idea was that uses of SYSTEM should be
rare, so that importation of SYSTEM should act as a marker that
something suspect is being done; but IMO this has failed because:
 (a) there are some non-portable features which were (accidentally?)
     left out of SYSTEM - e.g. address arithmetic, type BITSET,
     type casting - so that it's possible to write non-portable code
     without ever importing from SYSTEM.  This is especially evident
     among programmers who learnt C before learning Modula-2.
 (b) SYSTEM is too big, and contains some things that don't belong
     there.  Every man and his dog ends up importing from SYSTEM,
     so that uses of SYSTEM no longer stand out as being something
     unusual.

The solution, I believe, is to break up SYSTEM into a set of smaller
low-level modules, to give the reader of a source listing a better
idea of what low-level features are being used.  (Many M2 implementations
already do this to a limited extent.  For example, it's become common
to put TRANSFER/IOTRANSFER in a module other than SYSTEM.  This is a
good example of something which didn't belong in SYSTEM in the first
place.)  The low-level features of Modula-2 are certainly worth
keeping (otherwise you drive people like me towards C and possible
suicide), but their uses need to be flagged in a more visible way.

One obvious approach, by the way, is to have a compiler option to
generate warning messages for things which might be non-portable
- e.g. type-casting.  Strangely, I've never seen a M2 compiler
which does this.  The TopSpeed compiler, which is good in many other
ways, is especially bad in this respect; one gets the impression that
the people who wrote the compiler didn't understand the difference
between type-casting and assignment compatibility, and/or thought
they were writing a C compiler.

-- 
Peter Moylan                      eepjm@wombat.newcastle.edu.au