RfD: Memory Access Words

17 views
Skip to first unread message

Peter Knaggs

unread,
Feb 23, 2010, 10:50:26 PM2/23/10
to fort...@yahoogroups.com
RfD - Memory access
===================

Author
======

Federico de Ceballos
Universidad de Cantabria
federico...@unican.es

20100224 Revised reference implementation
20090923 Restored B@ and B!.
20090921 Forth200x review release.
20090902 Forth200x review update.
20090829 First writing according to the Proposals Process as
described in the Draft 200x Standard.


Problem
=======

ANS Standard Forth lacks a way of accessing memory elements of a fixed
width in a portable way. This is useful for sharing data between
applications in the same or different machines.

We assume that the data is byte-oriented and twos-complement.

We assume that the host is a twos-complement machine. To extend this
proposal to ones-complement machines is

a) an exercise for the reader
b) requires the addition of signed and unsigned store operations.


Solution
========

A new set of words is proposed, the MEMORY-ACCESS wordset, so that the
desired memory size can be selected.

Typical use
===========

CREATE DATA 1 L,
2 W,
3 B,

DATA DUP L@ . 4 BYTES + DUP W@ . 2 BYTES + B@ .

Remarks
=======

1. These words form the MEMORY ACCESS wordset. Words that only make
sense with a cell size smaller than 32 bit should go to the EXT
part.

2. The names follow the notation:

<unsigned> <size> <action> <endian>

where:

unsigned: U for unsigned (default)
S for signed
size: B for 8 bit byte
W for 16 bit word
L for 32 bit long-word
X for 64 bit extended-word
action: !, @ or , with the usual meaning
endian: BE for big-endian, LE for little-endian,
<null> for native order.

Systems with multiple address spaces, e.g. Harvard architectures
and cross-compilers often follow the <endian> description with a
<where> description, e.g.

where: C code space
D data space
R register space
T target address space in cross-compiler
J JTAG or debug link

3. The term 'native order' as been chosen as 'local order' might be
confused with some order related to local variables. The word
'host' is also used in the Berkeley Sockets API.

4. When operating on data larger than an address unit, memory
operations shall be capable of unaligned operation, e.g. when
fetching a 32 bit item from a non 32-bit aligned address, the
operation will succeed.

5. Systems shall not implement words requiring or returning items
larger than the cell size. It only causes portability issues
rather than solving them.

The rationale for these remarks is that data transfer standards exist
that are big-endian, e.g. TCP/IP, and little-endian, e.g. USB. This
forces us to make a clear distinction between big-endian, little-
endian and native data.

For cell addressed machines which use a cell larger than 8 bits, it is
assumed that the upper part of a cell is simply ignored. This
proposal makes no attempt to deal with packing of bytes for memory
efficiency. Providing that other operations such as TYPE produce the
expected result, the implementation may deal with packing of data as
it sees fit. However, the model of one byte per cell will always work
with least implementation complexity.

Proposal
========

18.2.aaaa B! "b-store" MEMORY-ACCESS
( x addr -- )

Store the 8 LSBs of x at addr.

18.2.aaab W! "w-store" MEMORY-ACCESS
( x addr -- )

Store the 16 LSBs of x at addr in native format irrespective of
alignment.

18.2.aaac W!BE "w-store-b-e" MEMORY-ACCESS
( x addr -- )

Store the 16 LSBs of x at addr in big-endian format irrespective of
alignment.

18.2.aaad W!LE "w-store-l-e" MEMORY-ACCESS
( x addr -- )

Store the 16 LSBs of x at addr in litle-endian format irrespective
of alignment.

18.2.aaae L! "l-store" MEMORY-ACCESS
( x addr -- )

Store the 32 LSBs of x at addr in native format irrespective of
alignment.

18.2.aaaf L!BE "l-store-b-e" MEMORY-ACCESS
( x addr -- )

Store the 32 LSBs of x at addr in big-endian format irrespective of
alignment.

18.2.aaag L!LE "l-store-l-e" MEMORY-ACCESS
( x addr -- )

Store the 32 LSBs of x at addr in little-endian format irrespective
of alignment.

18.2.aaah B@ "b-fetch" MEMORY-ACCESS
( addr -- x )

Fetch the 8 LSBs of x from addr. If the cell size is greater than
8 bits, the result is zero-extended.

18.2.aaai W@ "w-fetch" MEMORY-ACCESS
( addr -- x )

Fetch the 16 LSBs of x from addr in native format irrespective of
alignment. If the cell size is greater than 16 bits, the result is
zero-extended.

18.2.aaaj W@BE "w-fetch-b-e" MEMORY-ACCESS
( addr -- x )

Fetch the 16 LSBs of x from addr in big-endian format irrespective
of alignment. If the cell size is greater than 16 bits, the result
is zero-extended.

18.2.aaak W@LE "w-fetch-l-e" MEMORY-ACCESS
( x addr -- )

Fetch the 16 LSBs of x from addr in little-endian format irrespective
of alignment. If the cell size is greater than 16 bits, the result
is zero-extended.

18.2.aaal L@ "l-fetch" MEMORY-ACCESS
( addr -- x )

Fetch the 32 LSBs of x from addr in native format irrespective of
alignment. If the cell size is greater than 32 bits, the result is
zero-extended.

18.2.aaam L@BE "l-fetch-b-e" MEMORY-ACCESS
( addr -- x )

Fetch the 32 LSBs of x from addr in big-endian format irrespective
of alignment. If the cell size is greater than 32 bits, the result
is zero-extended.

18.2.aaan L@LE "l-fetch-l-e" MEMORY-ACCESS
( addr -- x )

Fetch the 32 LSBs of x at addr in little-endian format irrespective
of alignment. If the cell size is greater than 32 bits, the result
is zero-extended.

18.2.aaao W, "w-comma" MEMORY-ACCESS
( x -- )

Reserve 16 bits of data space and store the 16 LSBs of x in them in
native order irrespective of alignment.

18.2.aaap W,BE "w-comma-b-e" MEMORY-ACCESS
( x -- )

Reserve 16 bits of data space and store the 16 LSBs of x in them in
big-endian format irrespective of alignment.

18.2.aaaq W,LE "w-comma-l-e" MEMORY-ACCESS
( x -- )

Reserve 16 bits of data space and store the 16 LSBs of x in them in
little-endian format irrespective of alignment.

18.2.aaar L, "l-comma" MEMORY-ACCESS
( x -- )

Reserve 32 bits of data space and store the 32 LSBs of x in them in
native order irrespective of alignment.

18.2.aaas L,BE "l-comma-b-e" MEMORY-ACCESS
( x -- )

Reserve 32 bits of data space and store the 32 LSBs of x in them in
big-endian format irrespective of alignment.

18.2.aaat L,LE "l-comma-l-e" MEMORY-ACCESS
( x -- )

Reserve 32 bits of data space and store the 32 LSBs of x in them in
little-endian format irrespective of alignment.

18.2.aaau WALIGN "w-align" MEMORY-ACCESS
( -- )

If the data-space pointer is not 16-bit aligned, reserve enough
space to align it.

See: 3.3.3 Data space, 3.3.3.1 Address alignment.

18.2.aaav LALIGN "l-align" MEMORY-ACCESS
( -- )

If the data-space pointer is not 32-bit aligned, reserve enough
space to align it.

See: 3.3.3 Data space, 3.3.3.1 Address alignment.

18.2.aaaw WALIGNED "w-aligned" MEMORY-ACCESS
( addr1 -- addr2 )

Addr2 is the first 16-bit aligned address greater than or equal to
addr1.

See: 3.3.3.1 Address alignment, 18.2.aaau.

18.2.aaax LALIGNED "l-aligned" MEMORY-ACCESS
( addr1 -- addr2 )

Addr2 is the first 32-bit aligned address greater than or equal to
addr1.

See: 3.3.3.1 Address alignment, 18.2.aaav.

18.2.aaay BYTES "bytes" MEMORY-ACCESS
( n1 -- n2 )

N2 is the size in address units of 8 bit units.


Reference Implementation
========================

This implementation makes the assumption that it is working on a byte
addressed system and that a character is stored as a byte.

\ Assuming a Char is 8-bits - Not valid on some systems
: B! ( x addr -- ) $FF AND C! ;
: B@ ( addr -- x ) C@ $FF AND ;
: BYTES ( n1 -- n2 ) CHARS ;

\ Internal helper words (not part of the proposal)
: b@+ ( x1 addr1 -- x2 addr2 ) SWAP 8 LSHFIT OVER B@ + SWAP 1 BYTES + ;
: b!- ( x1 addr1 -- x2 addr2 ) 1 BYTES - 2DUP B! SWAP 8 RSHIFT SWAP ;

: l@- ( x1 addr1 -- x2 addr2 ) 1 BYTES - DUP B@ ROT 8 LSHIFT + SWAP ;
: l!+ ( x1 addr1 -- x2 addr2 ) 2DUP B! 1 BYTES + SWAP 8 RSHIFT SWAP ;

\ Big-endian Memory Access Words
: W@BE ( addr -- x ) 0 SWAP b@+ b@+ DROP ;
: L@BE ( addr -- x ) 0 SWAP b@+ b@+ b@+ b@+ DROP ;

: W!BE ( x addr -- ) 2 BYTES + b!- b!- 2DROP ;
: L!BE ( x addr -- ) 4 BYTES + b!- b!- b!- b!- 2DROP ;

: W,BE ( x -- ) HERE 2 BYTES ALLOT W!BE ;
: L,BE ( x -- ) HERE 4 BYTES ALLOT L!BE ;

\ Little-endian Memory Access Words
: W@LE ( addr -- x ) 0 SWAP 2 BYTES + l@- l@- DROP ;
: L@LE ( addr -- x ) 0 SWAP 4 BYTES + l@- l@- l@- l@- DROP ;

: W!LE ( x addr -- ) l!+ l+! 2DROP ;
: L!LE ( x addr -- ) l!+ l!+ l!+ l!+ 2DROP ;

: W,LE ( x -- ) HERE 2 BYTES ALLOT W!LE ;
: L,LE ( x -- ) HERE 4 BYTES ALLOT L!LE ;

\ Native Memory Access Words
$1234 PAD !
PAD B@ $12 = [IF]
\ Big Endian System
SYNONYM W@ W@BE
SYNONYM L@ L@BE
SYNONYM W! W!BE
SYNONYM L! W!BE
SYNONYM W, W,BE
SYNONYM L, L,BE
[ELSE]
\ Little Endian System
SYNONYM W@ W@LE
SYNONYM L@ L@LE
SYNONYM W! W!LE
SYNONYM L! W!LE
SYNONYM W, W,LE
SYNONYM L, L,LE
[THEN]

\ Alignment Words
: WALIGN ( -- ) HERE 1 AND ALLOT ;
: LALIGN ( -- ) 4 HERE 3 AND - 3 AND ALLOT ;

: WALIGNED ( addr1 -- addr2 ) 3 + -4 AND ;
: LALIGNED ( addr1 -- addr2 ) 1 + -2 AND ;

Tests
=====

TBD

Josh Grams

unread,
Feb 24, 2010, 8:06:34 AM2/24/10
to
Peter Knaggs wrote: <op.u8l4ycbnsu5d0p@david>

>
> 4. When operating on data larger than an address unit, memory
> operations shall be capable of unaligned operation, e.g. when
> fetching a 32 bit item from a non 32-bit aligned address, the
> operation will succeed.

Hrm. I can see the logic to this, but, it does mean that on some
platforms you have to use a much slower operation... I would prefer to
see the primitive operations provided.


> Reference Implementation
>========================

Wow, you're lazy. You clearly didn't even load this into a Forth
system, let alone test it at all.

> This implementation makes the assumption that it is working on a byte
> addressed system and that a character is stored as a byte.
>
> \ Assuming a Char is 8-bits - Not valid on some systems
>: B! ( x addr -- ) $FF AND C! ;

Mask the value to 8 bits, not the address.

>: B@ ( addr -- x ) C@ $FF AND ;
>: BYTES ( n1 -- n2 ) CHARS ;
>
> \ Internal helper words (not part of the proposal)
>: b@+ ( x1 addr1 -- x2 addr2 ) SWAP 8 LSHFIT OVER B@ + SWAP 1 BYTES + ;

LSHFIT?

>: b!- ( x1 addr1 -- x2 addr2 ) 1 BYTES - 2DUP B! SWAP 8 RSHIFT SWAP ;
>
>: l@- ( x1 addr1 -- x2 addr2 ) 1 BYTES - DUP B@ ROT 8 LSHIFT + SWAP ;
>: l!+ ( x1 addr1 -- x2 addr2 ) 2DUP B! 1 BYTES + SWAP 8 RSHIFT SWAP ;

I would have named these b@- and b!+ ('b' for byte, not 'b' and 'l' for
big and little endian). I know these are only helper words, but you
explained the naming convention above and here you are totally breaking
it.

> \ Big-endian Memory Access Words
>: W@BE ( addr -- x ) 0 SWAP b@+ b@+ DROP ;
>: L@BE ( addr -- x ) 0 SWAP b@+ b@+ b@+ b@+ DROP ;
>
>: W!BE ( x addr -- ) 2 BYTES + b!- b!- 2DROP ;
>: L!BE ( x addr -- ) 4 BYTES + b!- b!- b!- b!- 2DROP ;
>
>: W,BE ( x -- ) HERE 2 BYTES ALLOT W!BE ;
>: L,BE ( x -- ) HERE 4 BYTES ALLOT L!BE ;
>
> \ Little-endian Memory Access Words
>: W@LE ( addr -- x ) 0 SWAP 2 BYTES + l@- l@- DROP ;
>: L@LE ( addr -- x ) 0 SWAP 4 BYTES + l@- l@- l@- l@- DROP ;
>
>: W!LE ( x addr -- ) l!+ l+! 2DROP ;

l+! ?

Otherwise it seems to work: here are some basic tests I threw
together...

--Josh

HEX
T{ 12345678 PAD L!BE => }T
T{ 0 PAD 4 BYTES + L!BE => }T

T{ PAD L@BE => 12345678 }T
T{ PAD 1 BYTES + L@BE => 34567800 }T

T{ PAD W@BE => 1234 }T
T{ PAD 1 BYTES + W@BE => 3456 }T
T{ PAD 2 BYTES + W@BE => 5678 }T
T{ PAD 3 BYTES + W@BE => 7800 }T

T{ PAD B@ => 12 }T
T{ PAD 1 BYTES + B@ => 34 }T
T{ PAD 2 BYTES + B@ => 56 }T
T{ PAD 3 BYTES + B@ => 78 }T

T{ PAD L@LE => 78563412 }T
T{ PAD 1 BYTES + L@LE => 00785634 }T

T{ PAD W@LE => 3412
T{ PAD 1 BYTES + W@LE => 5634 }T
T{ PAD 2 BYTES + W@LE => 7856 }T
T{ PAD 3 BYTES + W@LE => 0078 }T

T{ 0 PAD L!BE FFFFFFFF PAD 1 BYTES + B! => }T
T{ PAD L@BE => 00FF0000 }T

T{ 0 PAD L!BE FFFFFFFF PAD 1 BYTES + W!BE => }T
T{ PAD L@BE => 00FFFF00 }T
T{ 12345678 PAD 1 BYTES + W!BE => }T
T{ PAD L@BE => 00567800 }T

T{ 0 PAD L!BE FFFFFFFF PAD 1 BYTES + L!BE => }T
T{ PAD L@BE PAD 4 BYTES + L@BE => 00FFFFFF FF000000 }T
T{ 12345678 PAD 1 BYTES + L!BE => }T
T{ PAD L@BE PAD 4 BYTES + L@BE => 00123456 78000000 }T

T{ 0 PAD L!LE FFFFFFFF PAD 1 BYTES + B! => }T
T{ PAD L@LE => 0000FF00 }T

T{ 0 PAD L!LE FFFFFFFF PAD 1 BYTES + W!LE => }T
T{ PAD L@LE => 00FFFF00 }T
T{ 12345678 PAD 1 BYTES + W!LE => }T
T{ PAD L@LE => 00567800 }T

T{ 0 PAD L!LE FFFFFFFF PAD 1 BYTES + L!LE => }T
T{ PAD L@LE PAD 4 BYTES + L@LE => FFFFFF00 000000FF }T
T{ 12345678 PAD 1 BYTES + L!LE => }T
T{ PAD L@LE PAD 4 BYTES + L@LE => 34567800 00000012 }T

Peter Knaggs

unread,
Feb 24, 2010, 1:19:40 PM2/24/10
to
On Wed, 24 Feb 2010 13:06:34 -0000, Josh Grams <jo...@qualdan.com> wrote:
>
> Wow, you're lazy. You clearly didn't even load this into a Forth
> system, let alone test it at all.

Actually I spent a hour or so testing it on a variety of systems.
Unfortunately, due to the access to the various systems the testing was
done by retyping code as file upload was not viable.

>> \ Assuming a Char is 8-bits - Not valid on some systems
>> : B! ( x addr -- ) $FF AND C! ;
>
> Mask the value to 8 bits, not the address.

Yes, this was just a brain fart. That's what you get for working on code
a 4am, this should of course be

: B! ( x addr -- ) SWAP $FF AND SWAP C! ;

>> \ Internal helper words (not part of the proposal)
>> : b@+ ( x1 addr1 -- x2 addr2 ) SWAP 8 LSHFIT OVER B@ + SWAP 1 BYTES + ;
>
> LSHFIT?

This one is simply a typo.

>
>> : b!- ( x1 addr1 -- x2 addr2 ) 1 BYTES - 2DUP B! SWAP 8 RSHIFT SWAP ;
>>
>> : l@- ( x1 addr1 -- x2 addr2 ) 1 BYTES - DUP B@ ROT 8 LSHIFT + SWAP ;
>> : l!+ ( x1 addr1 -- x2 addr2 ) 2DUP B! 1 BYTES + SWAP 8 RSHIFT SWAP ;
>
> I would have named these b@- and b!+ ('b' for byte, not 'b' and 'l' for
> big and little endian). I know these are only helper words, but you
> explained the naming convention above and here you are totally breaking
> it.

Reviewing it this morning, I came to the same conclusion.

>> : W!LE ( x addr -- ) l!+ l+! 2DROP ;
>
> l+! ?

Again a simple typo when copying the code into the email.

>> Tests
>> =====
>
> Otherwise it seems to work: here are some basic tests I threw
> together...

As can be seen from the above typos, I really could not bring myself to do
the test cases at 4am having just spent a hour or so testing the code. So
thank you for your addition, it makes a change for someone else to write
test cases.

--
Peter Knaggs

Peter Knaggs

unread,
Feb 24, 2010, 1:22:36 PM2/24/10
to
On Wed, 24 Feb 2010 13:06:34 -0000, Josh Grams <jo...@qualdan.com> wrote:
>
> Peter Knaggs wrote: <op.u8l4ycbnsu5d0p@david>
>>
>> 4. When operating on data larger than an address unit, memory
>> operations shall be capable of unaligned operation, e.g. when
>> fetching a 32 bit item from a non 32-bit aligned address, the
>> operation will succeed.
>
> Hrm. I can see the logic to this, but, it does mean that on some
> platforms you have to use a much slower operation... I would prefer to
> see the primitive operations provided.

Indeed, the idea is that x@, x! and x, should be provided in the native
form. The reference implementation does not do this as it is a portable
implementation.

--
Peter Knaggs

Marcel Hendrix

unread,
Feb 24, 2010, 2:08:17 PM2/24/10
to
"Peter Knaggs" <p...@bcs.org.uk> writes Re: RfD: Memory Access Words

> RfD - Memory access
> ===================

For the last couple of years iForth has been using the syntax below.
( B@ is hopefully self-explaining ).

These words have proved to be essential in porting 32bit code to 64bit.
The implementation cares about alignedness but not about endianness.
Signs are a problem that is addressed.

: (,) 0 ?DO DUP C, 8 RSHIFT LOOP DROP ; ( addr n -- )

: 16B, 2 (,) ; ( n -- )
: 16B! 2DUP C! SWAP 8 RSHIFT SWAP 1+ C! ; ( n addr -- )
: 16B@ C@+ SWAP C@ 8 LSHIFT OR ; ( addr -- u16bit )
: S16B@ B@ ; ( addr -- 16bit )
: 16B@+ C@+ >S C@+ 8 LSHIFT S> OR ; ( addr -- addr' 16bit )

: DWORDS 4 * ;
: DWORD+ 4 + ;
: DWORD- 4 - ;

64BIT?
[IF]

: DWORD[] DWORDS + ; ( addr1 ix -- addr2 )
: []DWORD SWAP DWORD[] ; ( ix addr1 -- addr2 )
: 32B, 4 (,) ; ( n -- ) \ normal , aligns
: 32B! 2DUP 16B! 2+ >R #16 RSHIFT R> 16B! ; ( n addr -- )
: 32B!+ TUCK 32B! 4 + ; ( n addr1 -- addr2 )
: 32B@ 16B@+ SWAP 16B@ #16 LSHIFT OR ; ( addr -- 32bit )
: 32B+! DUP 32B@ ROT + SWAP 32B! ; ( n addr -- )
: 32B@+ 16B@+ >R 16B@+ #16 LSHIFT R> OR ; ( addr -- addr' 32bit )
: S32B@+ CR ." S32B@+ should be code!" ; ( addr1 -- addr2 n )
: S32B@ S32B@+ NIP ; ( addr -- n )
: 32B2@ 32B@+ SWAP 32B@ SWAP ; ( addr -- lo hi )
: 32B2! 32B!+ 32B! ; ( lo hi addr -- )

[ELSE]

: DWORD[] CELL[] ; ( addr1 ix -- addr2 )
: []DWORD []CELL ; ( ix addr1 -- addr2 )
: 32B, 4 (,) ; ( n -- ) \ normal , aligns
: 32B! ! ; ( n addr -- )
: 32B!+ !+ ; ( n addr1 -- addr2 )
: 32B+! +! ; ( n addr -- )
: 32B@ @ ; ( addr -- 32bit )
: 32B@+ @+ ; ( addr -- addr' 32bit )
: S32B@+ @+ ; ( addr1 -- addr2 n )
: S32B@ @ ; ( addr -- n )
: 32B2@ 2@ ; ( addr -- lo hi )
: 32B2! 2! ; ( lo hi addr -- )

[THEN]

-marcel

Bernd Paysan

unread,
Feb 24, 2010, 4:52:56 PM2/24/10
to
Peter Knaggs wrote:

> \ Native Memory Access Words
> $1234 PAD !
> PAD B@ $12 = [IF]

4 am code, as well: Try

$1234 PAD W! PAD B@ $12 = [IF]

for big endian ($1234 PAD ! PAD B@ should give $12 on a 16 bit system,
and $00 for any other system). If you want to use !, check for little
endian, i.e.

$1234 PAD ! PAD B@ $34 = [IF] ( little endian)

--
Bernd Paysan
"If you want it done right, you have to do it yourself"
http://www.jwdt.com/~paysan/

Peter Knaggs

unread,
Feb 24, 2010, 6:33:29 PM2/24/10
to
On Wed, 24 Feb 2010 21:52:56 -0000, Bernd Paysan <bernd....@gmx.de>
wrote:
>
>> \ Native Memory Access Words
>> $1234 PAD !
>> PAD B@ $12 = [IF]
>
> 4 am code, as well: Try
>
> $1234 PAD W! PAD B@ $12 = [IF]
>
> for big endian ($1234 PAD ! PAD B@ should give $12 on a 16 bit system,
> and $00 for any other system).

I was wandering when someone would spot that. :)

--
Peter Knaggs

idknow

unread,
Feb 24, 2010, 11:49:59 PM2/24/10
to
On Feb 23, 10:50 pm, "Peter Knaggs" <p...@bcs.org.uk> wrote:
> RfD - Memory access
> ===================
>
> Author
> ======
>
> Federico de Ceballos
> Universidad de Cantabria
> federico.cebal...@unican.es
>
[snip]

So I've been reading this proposal and I'm finding that I can't digest
all the words that are being proposed.

It's memory: a vector of linear and sequential addresses of varying
but finite sizes.

It just seems so un-forthy to me. It's too verbose and quite nearly
approaches ridiculousness, if not actually arriving there.

I comprehend the need to properly handle an endian issue across CPUs
but that's as far as I can go. It seems more like an issue for
implementers rather than general Forth coders.

If I were implementing this, I could see writing code using either
lodsb, lodsd and stosb, stosd; or plain mov's on Intel and compatible
hardware. But to code these words in high-level Forth with all the
descending and ascending into and out of words just to get "the right
size" leaves me alittle ill.

Elizabeth D Rather

unread,
Feb 24, 2010, 11:55:08 PM2/24/10
to fort...@yahoogroups.com
Peter Knaggs wrote:
> RfD - Memory access
> ===================
...

> Problem
> =======
>
> ANS Standard Forth lacks a way of accessing memory elements of a fixed
> width in a portable way. This is useful for sharing data between
> applications in the same or different machines.
>
> We assume that the data is byte-oriented and twos-complement.
>
> We assume that the host is a twos-complement machine. To extend this
> proposal to ones-complement machines is
>
> a) an exercise for the reader
> b) requires the addition of signed and unsigned store operations.

Forth94 made strenuous efforts to avoid assuming 2's complement or
byte-orientation. Is this TC really ready to abandon this policy? If
so, there are a lot of other places that can be simplified. But think
about it seriously.

Do you, for example, want to render it impossible to run Standard Forth
on devices such as Intellasys/Green Arrays products? Or other
word-oriented devices, of which there are several in use?

...


> 2. The names follow the notation:
>
> <unsigned> <size> <action> <endian>
>
> where:
>
> unsigned: U for unsigned (default)
> S for signed
> size: B for 8 bit byte
> W for 16 bit word
> L for 32 bit long-word
> X for 64 bit extended-word
> action: !, @ or , with the usual meaning
> endian: BE for big-endian, LE for little-endian,
> <null> for native order.

I note that Open Firmware was able to avoid having to have special
operators for endian-ness, even though it worked on several big- and
little-endian systems. That seems an unnecessary complication to me.

Cheers,
Elizabeth

--
==================================================
Elizabeth D. Rather (US & Canada) 800-55-FORTH
FORTH Inc. +1 310.999.6784
5959 West Century Blvd. Suite 700
Los Angeles, CA 90045
http://www.forth.com

"Forth-based products and Services for real-time
applications since 1973."
==================================================

Bruce McFarling

unread,
Feb 25, 2010, 1:08:42 AM2/25/10
to
On Feb 24, 11:55 pm, Elizabeth D Rather <erat...@forth.com> wrote:
> Forth94 made strenuous efforts to avoid assuming 2's complement or
> byte-orientation.  Is this TC really ready to abandon this policy?  If
> so, there are a lot of other places that can be simplified.  But think
> about it seriously.

> Do you, for example, want to render it impossible to run Standard Forth
> on devices such as Intellasys/Green Arrays products?  Or other
> word-oriented devices, of which there are several in use?

And consider a 20bit cell, where two cells can pack five bytes, but
the only way to meet the requirement of being able to align on byte
boundaries is to create a synthetic nybble au, with cell aligned being
multiples of five rather than some power of two.

By contrast to that dash to meet the extension word count record:

BYTE-ALIGNED ( addr -- 8addr )
BYTE-ALIGN ( -- )

GET-BYTE ( 8addr u -- byte ) retrieve the u-th byte starting from the
byte-aligned address 8addr

PUT-BYTE ( byte 8addr u -- ) store byte at the u-th starting from the
byte-aligned address 8addr

UNPACK-BYTES ( 8addr c-addr u -- ) store u bytes packed into memory
starting at 8addr into the u chars starting at c-addr. The origin and
target may not be overlapping.

PACK-BYTES ( c-addr 8addr u -- ) store the u bytes stored in u chars
starting at c-addr packed into memory starting at 8addr. The origin
and target may not be overlapping.

BYTES ( u -- au bits ) sufficient number of address units to contain
given number of bytes, and bits of padding.

Would seem to allow synthesizing any byte-multiple operations required
and allow a choice between space and processor efficient operations on
standard external information defined in bytes.

Ref implementation for a byte-addressed, char=byte implementation:

: BYTE-ALIGN ; IMMEDIATE
: BYTE-ALIGNED ; IMMEDIATE
: PUT-BYTE ( byte 8addr u -- ) + C! ;
: GET-BYTE ( 8addr u -- byte ) + C@ ;
: UNPACK-BYTES ( 8addr c-addr u -- ) CMOVE ;
: PACK-BYTES ( c-addr 8addr u -- ) CMOVE ;
: BYTES ( u -- au bits ) 0 ;

Anton Ertl

unread,
Feb 25, 2010, 11:08:32 AM2/25/10
to
Elizabeth D Rather <era...@forth.com> writes:

>Peter Knaggs wrote:
>> We assume that the data is byte-oriented and twos-complement.
>>
>> We assume that the host is a twos-complement machine. To extend this
>> proposal to ones-complement machines is
>>
>> a) an exercise for the reader
>> b) requires the addition of signed and unsigned store operations.

I don't see that we would need them. I also don't see anything else
that's twos-complement-specific in this proposal. All the proposed
fetch operations zero-extend and are thus unsigned, so the
representation of signed numbers does not play a role here.

>Forth94 made strenuous efforts to avoid assuming 2's complement or
>byte-orientation. Is this TC really ready to abandon this policy?

I am totally ready to assume 2s-complement, for the following reasons:

1) It's universal practice in programs and systems.

2) 1s-complement and sign-magnitude hardware is obsolete, and will
probably never see a Forth system, much less a Forth-200x system.

3) Even though the Forth-94 TC may have made strenous efforts, I am
not convinced that they succeeded. It would certainly mean a lot of
restrictions on programs that no current Forth programmer would be
aware of. Hmm, some time ago I had some idea for a unconventional
implementation of a Forth system on mainstream hardware that would
allow people to test whether their programs rely on twos-complement or
not; unfortunately, I don't remember that idea right now and I don't
remember having it posted to c.l.f. I guess I will remember it again
in time.

About byte-orientation:

I am ready to assume that 1au >= 1 byte. Nybble-addressed machines
may exist, but will never see a standard Forth whether the standard
accomodates them or not. However, the standard and this proposal has
good solutions for that, the only problem is that nobody uses them.

However, word-addressed machines are relevant (Chuck Moore's chips,
DSPs, lots of other embedded systems), so we should accomodate them.
Maybe this is an extension that these systems would not be interested
in, then this extension can assume byte-addressed machines, but I
suspect that this is not the case.

Some people have tried to deal with bytes in word-addressed machines
by accessing parts of the words, but I believe that this is overly
complicated, and will not be used by programmers (except maybe those
who have that problem).

My idea how to deal with these issues is this: The main purpose of
these words (certainly the LE and BE variants) is to access data
structures that come from elsewhere or are sent elsewhere, e.g., with
READ-FILE or WRITE-FILE. So we need a byte-oriented file access mode,
that reads bytewise (i.e., 1 byte per au (or, to accomodate
nybble-addressed machines, 1 byte per n>=1 aus)). On word-addressed
machines the additional bits in each au go unused; yes, that is
somewhat wasteful, but it's a lot simpler than the alternatives.
Words like W@LE then take the bytes from two adjacent words and
construct a Forth cell that can then be stored in native form (i.e.,
one cell per au on word-addressed machines). For output the whole
thing happens in reverse.

The present proposal would be compatible with such an approach, so I
don't see it as specific to byte-addressed machines either. It even
accomodates nybble-addressed machines by proposing BYTES.

>If
>so, there are a lot of other places that can be simplified.

Such as what?

- anton
--
M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
New standard: http://www.forth200x.org/forth200x.html
EuroForth 2009: http://www.euroforth.org/ef09/

Bruce McFarling

unread,
Feb 25, 2010, 12:27:28 PM2/25/10
to
On Feb 25, 11:08 am, an...@mips.complang.tuwien.ac.at (Anton Ertl)
wrote:

> About byte-orientation:
> I am ready to assume that 1au >= 1 byte.  Nybble-addressed machines
> may exist, but will never see a standard Forth whether the standard
> accomodates them or not.  However, the standard and this proposal has
> good solutions for that, the only problem is that nobody uses them.

Of course, this proposal does assume that all addresses are byte
aligned, and from that follows an assumption that all cells are
composed of an even number of bytes.

> However, word-addressed machines are relevant (Chuck Moore's chips,
> DSPs, lots of other embedded systems), so we should accomodate them.

> Maybe this is an extension that these systems would not be interested
> in, then this extension can assume byte-addressed machines, but I
> suspect that this is not the case.

> Some people have tried to deal with bytes in word-addressed machines
> by accessing parts of the words, but I believe that this is overly
> complicated, and will not be used by programmers (except maybe those
> who have that problem).

When there is the problem, the solution is to pack bytes, and then
either deal with packed bytes directly, or unpack the bytes, work with
them, then repack them.

> My idea how to deal with these issues is this: The main purpose of
> these words (certainly the LE and BE variants) is to access data
> structures that come from elsewhere or are sent elsewhere, e.g., with
> READ-FILE or WRITE-FILE.

> So we need a byte-oriented file access mode,
> that reads bytewise (i.e., 1 byte per au (or, to accomodate
> nybble-addressed machines, 1 byte per n>=1 aus)).

There is a simpler byte-oriented file access mode for word addressed
machines, which is equally transparent to byte-addressed, pchar=byte
implementations, and which is compatible with both efficient means of
working with bytes on word addressed machines.

> On word-addressed
> machines the additional bits in each au go unused; yes, that is
> somewhat wasteful, but it's a lot simpler than the alternatives.

> Words like W@LE then take the bytes from two adjacent words and
> construct a Forth cell that can then be stored in native form (i.e.,
> one cell per au on word-addressed machines).  For output the whole
> thing happens in reverse.

Except W@LE won't do that. W@LE will not take bytes from two adjacent
cells and construct a forth cell that can then be stored in native
form.

So now *in addition to* W@LE, an entire *new set* must be defined.

And of course, a 16-bit implementation requires that W@LE and W@BE
returns a double rather than a cell, so there is a second set of DW@LE
and DW@BE for the over 16bit words.

> The present proposal would be compatible with such an approach

If only it would be.

> It even
> accomodates nybble-addressed machines by proposing BYTES.

How does BYTES work on a word addressed machine, again? Its cannot be
provided on a word-addressed machine. After arguing that au>=1byte can
be safely assumed, but word-addressed machines must be respected, you
point out that BYTES, which rules out word-addressed machines, would
work with nybble addressed implementations.

Nybble-addressed implementations inherit their support from the
support for CHARS bigger than 8bits and for CELLS of any width greater
than or equal to 16 bits.

This proposal does not support any CELLS that are not even multiples
of bytes or au's that are not bytes or smaller, so really byte and
nybble addressed machines are the *only* systems supported.

As a common set of definitions for memory operations on byte addressed
with 32bit or larger cells, its fine. The question is why such a large
set of words that fails to solve the problem it claims to set out to
solve should be in the standard.

Bruce McFarling

unread,
Feb 25, 2010, 3:55:21 PM2/25/10
to
On Feb 25, 12:27 pm, Bruce McFarling <agil...@netscape.net> wrote:
> And of course, a 16-bit implementation requires that W@LE and W@BE
> returns a double rather than a cell, so there is a second set of DW@LE
> and DW@BE for the over 16bit words.

That is, a 16 bit needs a double for "L" words and a quadruple for "X"
words.

Note that for a 20bit cell,

L, L, L,

by the definition stores 48 bits in the dictionary in sequence, which
the proposal offers no way to retrieve as 16 bit words. So the
proposal is broken for some Forth hardware even where the data fits a
cell.

Aleksej Saushev

unread,
Feb 25, 2010, 6:52:29 PM2/25/10
to
an...@mips.complang.tuwien.ac.at (Anton Ertl) writes:

> Elizabeth D Rather <era...@forth.com> writes:
>>Peter Knaggs wrote:
>>> We assume that the data is byte-oriented and twos-complement.
>>>
>>> We assume that the host is a twos-complement machine. To extend this
>>> proposal to ones-complement machines is
>>>
>>> a) an exercise for the reader
>>> b) requires the addition of signed and unsigned store operations.
>
> I don't see that we would need them. I also don't see anything else
> that's twos-complement-specific in this proposal. All the proposed
> fetch operations zero-extend and are thus unsigned, so the
> representation of signed numbers does not play a role here.
>
>>Forth94 made strenuous efforts to avoid assuming 2's complement or
>>byte-orientation. Is this TC really ready to abandon this policy?
>
> I am totally ready to assume 2s-complement, for the following reasons:
>
> 1) It's universal practice in programs and systems.
>
> 2) 1s-complement and sign-magnitude hardware is obsolete, and will
> probably never see a Forth system, much less a Forth-200x system.

This proves that you lack abstraction abilities,
and that forthers cannot catch up with 30 years of CS developments.
E.g. "Lambda the Ultimate" series.

This makes Forth impotent in some valuable application domains.

> About byte-orientation:
>
> I am ready to assume that 1au >= 1 byte.

Wrong assumption unless you mean that you use only octet-wide encodings.


--
HE CE3OH...

Aleksej Saushev

unread,
Feb 25, 2010, 7:01:32 PM2/25/10
to
"Peter Knaggs" <p...@bcs.org.uk> writes:

> Problem


>
> W for 16 bit word
> L for 32 bit long-word
> X for 64 bit extended-word

It is generally perceived almost everywhere, that "word" on 32-bit hardware
denotes 32 bit memory unit. That's why those stupids from ISO put into
the standard int8_t, int16_t, int32_t, int64_t and corresponding unsigned
types rather than insisting that "long int" is always 32 bits wide.

If Forth goes against well-established practice, this definitly is Problem.


--
HE CE3OH...

Elizabeth D Rather

unread,
Feb 25, 2010, 7:15:52 PM2/25/10
to

The nomenclature above has been well-established practice in Forth ever
since 32-bit processors came out in the early 80's. Many of the
operators in the proposal have been in Open Firmware since 1986.

Bruce McFarling

unread,
Feb 25, 2010, 8:01:32 PM2/25/10
to
On Feb 25, 7:15 pm, Elizabeth D Rather <erat...@forth.com> wrote:
> The nomenclature above has been well-established practice in Forth ever
> since 32-bit processors came out in the early 80's.  Many of the
> operators in the proposal have been in Open Firmware since 1986.

In an Open Firmware implementation ... AFAIU, Open Firmware itself
avoids sepcifying big-endian / little-endian access/store instructions
by letting the implementation grab a whole (32 bit?) cell in whatever
way it wants to and then allows splitting it. If you know that you
have cross-endian data, SWAP fixes to native endian.

@ lwsplit swap wljoin
... would flip 16-bit words in a 32-bit longword

@ wbsplit swap wbjoin
... would flip bytes in a 16-bit word

@ lwsplit swap >r wbsplit swap r> wbsplit swap bljoin
... would reverse bytes in a 32-bit longword

At an implementation or model level, these words make sense for an
implementation or model restricted to byte-addressed, 8*(2^x) wide
cell processors. Filewords in binary mode already provide data in raw
external format, when its to or from another application on the same
system, use the native format, when its external, the endian words do
the conversion of the external format if required and are otherwise
just native sized fetch and store.

Since these will often be sequences, it seems like it would be more
efficient to perform the conversion on the fly while bringing the data
in from the file or network packet or wherever and again while writing
the data out to the file or network packet or wherever ...

IMPORT-LITTLENDIAN ( a-addr1 a-addr2 u1 u2 -- )
IMPORT-BIGENDIAN ( a-addr1 a-addr2 u1 u2 -- )
EXPORT-LITTLENDIAN ( a-addr1 a-addr2 u1 u2 -- )
EXPORT-BIGENDIAN ( a-addr1 a-addr2 u1 u2 -- )

... where u1 is the number of *bytes* to be moved and u2 is byte width
of the data that may require conversion ...

... where on a little-endian, byte-addressed system:

: IMPORT-LITTLENDIAN ( a-addr1 a-addr2 u1 u2 ) DROP MOVE ;
: EXPORT-LITTLENDIAN ( a-addr1 a-addr2 u1 u2 ) DROP MOVE ;

Anton Ertl

unread,
Feb 26, 2010, 4:56:10 AM2/26/10
to
Aleksej Saushev <as...@inbox.ru> writes:
>It is generally perceived almost everywhere, that "word" on 32-bit hardware
>denotes 32 bit memory unit.

Almost everywhere. The insignificant exceptions are the VAX, the
80386, the 68000 and their insignificant descentants, e.g., the
Pentium and Athlon lines.

Thomas Pornin

unread,
Feb 26, 2010, 8:41:50 AM2/26/10
to
According to Aleksej Saushev <as...@inbox.ru>:

> rather than insisting that "long int" is always 32 bits wide.

Except that "long int" is 64 bits wide on some system, including the
PC on which I am writing these words. And also on all 64-bit systems
which run a kind of Unix, including (as far as I know) MacOS X. The
main exception is 64-bit Windows, because making 'unsigned long' a
64-bit type would have broken an awful lot of Win32 source code (Win32
API have long used the size-explicit 'DWORD' macro instead of a more
type-aware 'size_t').


--Thomas Pornin

Bruce McFarling

unread,
Feb 26, 2010, 2:06:24 PM2/26/10
to
On Feb 23, 10:50 pm, "Peter Knaggs" <p...@bcs.org.uk> wrote:
> RfD - Memory access
> ===================

> Problem


> =======
>
> ANS Standard Forth lacks a way of accessing memory elements of a fixed
> width in a portable way.  This is useful for sharing data between
> applications in the same or different machines.

If this proposal it adopted in the current form, it will still lack a


way of accessing memory elements of a fixed width in a portable way.

I have remarked on an alternative approach which would come closer to
allowing accessing memory elements of a fixed width in a portable way.

Here, I will point out *extensions* and *amendments* of the current
proposal which will allow it to come closer to its objective.


> We assume that the data is byte-oriented and twos-complement.

The first assumption is not properly an assumption: it is more
properly part of the objection statement.

"ANS Standard Forth lacks a way of accessing byte oriented memory


elements of a fixed width in a portable way. This is useful for
sharing data between applications in the same or different machines."

The second assumption is not, it turns out, actually *committed*, but
is only made by *omission*.

For a data interchange wordset, when there is a conversion to be made,
it can be made in either the producer or consumer. Given the
preponderance of two's complement Forth systems, we can include a
conversion two and from two's complement signed numeric format to the
native signed numeric format, which in the context of a two's
complement system is simple an immediate no-op.

: >TWOS-SIGNED ( n -- twos-complement-n )
: TWOS-SIGNED> ( twos-complement-n -- n )

Next is size of operand. All the operations are defined for arbitrary
stack cells, all of them are defined in terms of the bits of the
arbitrary stack cell, and none of them are optional.

The assumption that is made is that the bitwidth of the address unit
is an integral factor of 8. So 8, 4, 2, and 1 bit wide au's are
permitted, but not 16, 20, or 32.

For internal communications between different applications (either or
both of which may be portable cross-platform applications) ... one of
the two objectives to support, blocks of memory may be transferred in
some system or implementation dependent way. So portable transfer of
defined-width data between applications on the same system requires an
ability to *navigate* a sequence of data elements of known type.

Even if we allow for an "open" lattice with unused spacing bits
between data, BYTES does not suffice for this.

( #16int ) 2 BYTES ( aus ) ... only works on byte and nybble addressed
machines. On any cell-addressed machine, "WORDS" cannot be defined
based on "BYTES".

But "WORDS" especially, but also LONG and EXTENDED-LONG or XLONG are
terrible words for potential clashes.

16INT>SIZE ( u -- au )
32INT>SIZE ( u -- au )
64INT>SIZE ( u -- au )

... and now a lattice of defined width numeric values, possibly with
arbitrary bit padding, possibly requiring numeric representation
conversion, can be navigated.

Finally, L@ and L! extends beyond the defined minimum cell size in
Forth-94. "It is an ambiguous condition if the number of bits to be
stored or fetched is greater than the number of bits in the largest
unsigned integer."

This last removes *all* numeric representation and cell size
constraints. A 16-bit system is *permitted* to implement L@ and L! as:

: L@ 2@ ;
: L! 2! ;

... and a 20bit cell addressed system with 16bit chars (and C@ C!
simply assuming characters to be properly in bounds) is *permitted* to
implement L@ and L! as:

256 256 * 1- CONSTANT 16mask
: L@ ( l-addr -- lsw msw ) COUNT 16mask AND >R @ 16mask AND R> ;
: L! ( lsw msw l-addr -- ) 2! ;

Bruce McFarling

unread,
Feb 26, 2010, 2:49:18 PM2/26/10
to
Finally, there is no modifications proposed to the FILE and BLOCK
words, which are the two defined ways of storing and retrieving
collections of values.

As defined, Forth-94 FILE and BLOCK words returns a grid of CHARs.
Therefore, it is necessary to be able to retrieve defined-width data
packed into a grid of CHARs, and to pack defined-width data into a
grid of CHARS.

The problem, in other words, is to move information in a grid of
arbitrary width values into the open lattice that is provided by the
prior extensions/amendments, and back again.

Given the permitted layouts of the open lattice, distinct "B", "W",
"L" and "X" words are required (as in the proposal, I will leave the
"X" words to be protected by the notation specification at the
beginning).

"bit" is a value indicating that a portion of the data in the first
char has been retrieved. When "bit" is 0, this indicates that the
value begins on the character boundary. On char=byte systems, "bit" is
always 0.

BGET ( c-addr1 b-addr u1 bit1 -- c-addr2 bit2 ) store the u bytes
packed into the characters beginning at c-addr into the memory storage
locations starting at b-addr. c-addr2 is the address of the first
character address not retrieved. Bit1 indicates what portion of the
character at c-addr1 has already been accessed, and bit2 indicates
what portion of the character at c-addr2 has already been accessed.

BPUT ( b-addr c-addr1 u1 bit1 -- c-addr2 bit2 ) store the u bytes
starting at b-addr into the characters beginning at c-addr1. c-addr2
is the address of the first character address that is not yet filled
with data. Bit1 indicates what portion of the character at c-addr1 has
already been accessed, and bit2 indicates what portion of the
character at c-addr2 has already been accessed.

And similarly for WGET, WPUT, LGET, LPUT, XGET, and XPUT.

Note that CMOVE works perfectly adequately to move an unused portion
to the beginning of the buffer after writing the completely filled
character or before filling the balance with FILE operations. This is
part of the rationale for placing the partial indicator on top of the
stack, so that it can be readily stored out of the way during such
operations. The rest of the rationale is so that byte-addressed,
char=byte systems can define:

: BPUT ( b-addr c-addr u1 bit1 -- c-addr2 bit2 ) DROP 2DUP + >R MOVE
R> 0 ;
: BGET BPUT ;

and etc.

Bruce McFarling

unread,
Feb 26, 2010, 2:53:50 PM2/26/10
to

If this objection is allowed to stand, then the proposal will be
forced to make a change such as the following:

\{quote
W for 16 bit integer
L for 32 bit integer
X for 64 bit integer
\}

Clearly this is a fundamental, perhaps insuperable, problem.


Albert van der Horst

unread,
Feb 27, 2010, 5:47:24 AM2/27/10
to
In article <8feebd41-a90f-4d9a...@t23g2000yqt.googlegroups.com>,
Bruce McFarling <agi...@netscape.net> wrote:

>On Feb 25, 7:01=A0pm, Aleksej Saushev <a...@inbox.ru> wrote:
>> "Peter Knaggs" <p...@bcs.org.uk> writes:
>> > Problem
>>
>> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 W for 16 bit word
>> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 L for 32 bit long-word
>> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 X for 64 bit extended-word
>
>> It is generally perceived almost everywhere, that "word" on 32-bit hardwa=

>re
>> denotes 32 bit memory unit. That's why those stupids from ISO put into
>> the standard int8_t, int16_t, int32_t, int64_t and corresponding unsigned
>> types rather than insisting that "long int" is always 32 bits wide.
>
>> If Forth goes against well-established practice, this definitly is Proble=

>m.
>
>If this objection is allowed to stand, then the proposal will be
>forced to make a change such as the following:
>
>\{quote
> W for 16 bit integer
> L for 32 bit integer
> X for 64 bit integer
>\}

With the XCHAR proposal
Q for 64 bit
may be better.
(This has some established practice too.)


>
>Clearly this is a fundamental, perhaps insuperable, problem.

??

Groetjes Albert

--
--
Albert van der Horst, UTRECHT,THE NETHERLANDS
Economic growth -- being exponential -- ultimately falters.
albert@spe&ar&c.xs4all.nl &=n http://home.hccnet.nl/a.w.m.van.der.horst

Bruce McFarling

unread,
Feb 27, 2010, 12:15:00 PM2/27/10
to
Reading the proposal in light of the three choices to be made reveals
that a critical element of the proposal is partly obscured by
phrasing, with the specification partly implicit:

Choice 1:

1.1 Provide a new file access method that assures that bytes are
returned aligned on address boundaries
1.2 Be able to access bytes packed into arbitrary address boundaries

Choice 2:

2.1 Store multi-byte values in the least significant bit of cells in
memory
2.2 Store multi-byte values in successive address-aligned bytes

Choice 3:

3.1 Convert endianess in block move
3.2 Convert endianess in fetch and store

The proposal as written appears to indicate choice 2.1 in the fetch
and retrieve word definitions, but digging into the discussion in the
preliminary discussion makes clear that it is actually choice 2.2 that
is intended, without actually being spelled out in the proposal. This
simplifies choice (1), since only (1.1) is compatible with this
specification. The problem with reliance on BIN is obscured by the
fact that it only affects the minority of implementations that do not
have use the byte=char model.

This is the last paragraph of discussion before the proposal itself:

> For cell addressed machines which use a cell larger than 8 bits, it is
> assumed that the upper part of a cell is simply ignored. This
> proposal makes no attempt to deal with packing of bytes for memory
> efficiency. Providing that other operations such as TYPE produce the
> expected result, the implementation may deal with packing of data as
> it sees fit. However, the model of one byte per cell will always work
> with least implementation complexity.

Here "cell larger than 8 bits" is clearly a mis-statement, since
Forth-94
cells are always larger than 8 bits. What is intended is *address
units*
larger than eight bits. And for that, it is beside the point whether
the
machine is cell addressed or not ... a 16-bit addressed machine may
well be implemented with 32-bit cells and 16-bit UTF-16 characters,
and
will be a "char addressed" machine, but still require a standard
wordset
for source code sharing with byte-addressed implementations.

Indeed, such an implementation *needs* this proposal more than one
with
an 8bit extended character set, since getting end orientation wrong
breaks
UTF-16.

The implication of this is that the proposal definitions are
incomplete.
For the proposal to work, all operations on multi-byte values *must*
store and access to successive address-aligned bytes.

This is, indeed, *implied*, but not stated, by the following remark:


> 4. When operating on data larger than an address unit, memory
> operations shall be capable of unaligned operation, e.g. when
> fetching a 32 bit item from a non 32-bit aligned address, the
> operation will succeed.

This can be reliable assured if the fetch and store are defined to
operate
on successive address-aligned byte locations.

Note that this means that file access MUST be provided that returns
data
into file buffers with address-aligned bytes, and so a new fam needs
to
be defined to allow this requirement to be specified.

As before, sign-extending and sign-clipping can be provided for that
also
eliminates the portability barrier between two's complement and other
Forth-94 compatible numeric representations.

Also note that all words on values larger than 16bit integers should
be in MEMORY-ACCESS EXT, since under the advice of the proposer, these
should not be provided wherever they do not fit in a cell.

On Feb 23, 10:50 pm, "Peter Knaggs" <p...@bcs.org.uk> wrote:

> RfD - Memory access
> ===================
>
> Author
> ======
>
> Federico de Ceballos
> Universidad de Cantabria

> federico.cebal...@unican.es

All memory access operations in this wordset are defined on one or
more successive address-aligned bytes. In MEMORY-ACCESS, wherever it
says "store" and "fetch", the following applies:

(1) It is assumed that bytes do not require address alignment
(2) For address units larger than 8 bits, each address unit contains
one byte stored in the eight least significant bits. Additional bits
shall be ignored by these fetch operations, and should be set to zero
by these store operations.
(3) For address units smaller than 8 bits, end orientation of a byte
stored in successive address units is implementation dependent.

Operations on values larger than the implementation dependent cell-
size is an ambiguous condition. Any implementation with a cell smaller
than 32 bits *should* return true and the size of one address unit in
bits in response to the ADDRESS-UNIT-BITS environmental query.

> 18.2.aaaa B!                                 "b-store" MEMORY-ACCESS
>    ( x addr -- )
>
>    Store the 8 LSBs of x at addr.
>
> 18.2.aaab W!                                 "w-store" MEMORY-ACCESS
>    ( x addr -- )
>
>    Store the 16 LSBs of x at addr in native format irrespective of
>    alignment.
>
> 18.2.aaac W!BE                           "w-store-b-e" MEMORY-ACCESS
>    ( x addr -- )
>
>    Store the 16 LSBs of x at addr in big-endian format irrespective of
>    alignment.
>
> 18.2.aaad W!LE                           "w-store-l-e" MEMORY-ACCESS
>    ( x addr -- )
>
>    Store the 16 LSBs of x at addr in litle-endian format irrespective
>    of alignment.
>
18.2.aaae L!                                 "l-store" MEMORY-ACCESS

EXT


>    ( x addr -- )
>
>    Store the 32 LSBs of x at addr in native format irrespective of
>    alignment.
>
18.2.aaaf L!BE                           "l-store-b-e" MEMORY-ACCESS

EXT


>    ( x addr -- )
>
>    Store the 32 LSBs of x at addr in big-endian format irrespective of
>    alignment.
>
18.2.aaag L!LE                           "l-store-l-e" MEMORY-ACCESS

EXT


>    ( x addr -- )
>
>    Store the 32 LSBs of x at addr in little-endian format irrespective
>    of alignment.
>
> 18.2.aaah B@                                 "b-fetch" MEMORY-ACCESS
>    ( addr -- x )
>
>    Fetch the 8 LSBs of x from addr.  If the cell size is greater than
>    8 bits, the result is zero-extended.
>
> 18.2.aaai W@                                 "w-fetch" MEMORY-ACCESS
>    ( addr -- x )
>
>    Fetch the 16 LSBs of x from addr in native format irrespective of
>    alignment.  If the cell size is greater than 16 bits, the result is
>    zero-extended.
>
> 18.2.aaaj W@BE                           "w-fetch-b-e" MEMORY-ACCESS
>    ( addr -- x )
>
>    Fetch the 16 LSBs of x from addr in big-endian format irrespective
>    of alignment.  If the cell size is greater than 16 bits, the result
>    is zero-extended.
>
> 18.2.aaak W@LE                           "w-fetch-l-e" MEMORY-ACCESS
>    ( x addr -- )
>
>    Fetch the 16 LSBs of x from addr in little-endian format irrespective
>    of alignment.  If the cell size is greater than 16 bits, the result
>    is zero-extended.
>
18.2.aaal L@                                 "l-fetch" MEMORY-ACCESS

EXT


>    ( addr -- x )
>
>    Fetch the 32 LSBs of x from addr in native format irrespective of
>    alignment. If the cell size is greater than 32 bits, the result is
>    zero-extended.
>
18.2.aaam L@BE                           "l-fetch-b-e" MEMORY-ACCESS

EXT


>    ( addr -- x )
>
>    Fetch the 32 LSBs of x from addr in big-endian format irrespective
>    of alignment. If the cell size is greater than 32 bits, the result
>    is zero-extended.
>
18.2.aaan L@LE                           "l-fetch-l-e" MEMORY-ACCESS

EXT


>    ( addr -- x )
>
>    Fetch the 32 LSBs of x at addr in little-endian format irrespective
>    of alignment. If the cell size is greater than 32 bits, the result
>    is zero-extended.
>
> 18.2.aaao W,                                 "w-comma" MEMORY-ACCESS
>    ( x -- )
>
>    Reserve 16 bits of data space and store the 16 LSBs of x in them in
>    native order irrespective of alignment.
>
> 18.2.aaap W,BE                           "w-comma-b-e" MEMORY-ACCESS
>    ( x -- )
>
>    Reserve 16 bits of data space and store the 16 LSBs of x in them in
>    big-endian format irrespective of alignment.
>
> 18.2.aaaq W,LE                           "w-comma-l-e" MEMORY-ACCESS
>    ( x -- )
>
>    Reserve 16 bits of data space and store the 16 LSBs of x in them in
>    little-endian format irrespective of alignment.
>
18.2.aaar L,                                 "l-comma" MEMORY-ACCESS

EXT


>    ( x -- )
>
>    Reserve 32 bits of data space and store the 32 LSBs of x in them in
>    native order irrespective of alignment.
>
18.2.aaas L,BE                           "l-comma-b-e" MEMORY-ACCESS

EXT


>    ( x -- )
>
>    Reserve 32 bits of data space and store the 32 LSBs of x in them in
>    big-endian format irrespective of alignment.
>
18.2.aaat L,LE                           "l-comma-l-e" MEMORY-ACCESS

EXT


>    ( x -- )
>
>    Reserve 32 bits of data space and store the 32 LSBs of x in them in
>    little-endian format irrespective of alignment.
>
> 18.2.aaau WALIGN                             "w-align" MEMORY-ACCESS
>    ( -- )
>
>    If the data-space pointer is not 16-bit aligned, reserve enough
>    space to align it.
>
> See: 3.3.3 Data space, 3.3.3.1 Address alignment.
>
18.2.aaav LALIGN                             "l-align" MEMORY-ACCESS

EXT


>    ( -- )
>
>    If the data-space pointer is not 32-bit aligned, reserve enough
>    space to align it.
>
> See: 3.3.3 Data space, 3.3.3.1 Address alignment.
>
> 18.2.aaaw WALIGNED                         "w-aligned" MEMORY-ACCESS
>    ( addr1 -- addr2 )
>
>    Addr2 is the first 16-bit aligned address greater than or equal to
>    addr1.
>
> See: 3.3.3.1 Address alignment, 18.2.aaau.
>
18.2.aaax LALIGNED                         "l-aligned" MEMORY-ACCESS

EXT


>    ( addr1 -- addr2 )
>
>    Addr2 is the first 32-bit aligned address greater than or equal to
>    addr1.
>
> See: 3.3.3.1 Address alignment, 18.2.aaav.
>
> 18.2.aaay BYTES                                "bytes" MEMORY-ACCESS
>    ( n1 -- n2 )
>
>    N2 is the size in address units of 8 bit units.

18.2.aaaz OCTET "octet" MEMORY-ACCESS
EXT
( fam1 -- fam2 )

Modify fam1 to return fam2, which selects a file access mode under
which FILE operations are byte-oriented. All values are treated as a
sequence of bytes on successive address boundaries, and all character
counts are treated as counts of bytes.

18.2.aaba W>SIGN "w-to-sign" MEMORY-
ACCESS EXT
( x -- n )

The two's complement 16bit integer in the 16 lsb of x is converted to
a signed integer.

18.2.aaba SIGN>W "w-to-sign" MEMORY-
ACCESS EXT
( n -- x )

The signed integer n is converted to a two's complement 16bit integer
in the 16 lsb of x, with any more significant bits as 0.

18.2.aaca L>SIGN "w-to-sign" MEMORY-
ACCESS EXT
( x -- n )

The two's complement 32bit integer in the 32 lsb of x is converted to
a signed integer.

18.2.aada SIGN>L "w-to-sign" MEMORY-
ACCESS EXT
( n -- x )

The signed integer n is converted to a two's complement 32bit integer
in the 32 lsb of x, with any more significant bits as 0.

====================

for the reference implementation for byte-addressed systems,

: OCTET ( fam1 -- fam2 ) ; IMMEDIATE

I'm sure someone has two's complement sign extension code somewhere.

Bernd Paysan

unread,
Feb 27, 2010, 6:06:26 AM2/27/10
to
Elizabeth D Rather wrote:

> Aleksej Saushev wrote:
>> "Peter Knaggs" <p...@bcs.org.uk> writes:
>>
>>> Problem
>>>
>>> W for 16 bit word
>>> L for 32 bit long-word
>>> X for 64 bit extended-word
>>
>> It is generally perceived almost everywhere, that "word" on 32-bit
>> hardware denotes 32 bit memory unit. That's why those stupids from
>> ISO put into the standard int8_t, int16_t, int32_t, int64_t and
>> corresponding unsigned types rather than insisting that "long int" is
>> always 32 bits wide.
>>
>> If Forth goes against well-established practice, this definitly is
>> Problem.
>
> The nomenclature above has been well-established practice in Forth
> ever
> since 32-bit processors came out in the early 80's. Many of the
> operators in the proposal have been in Open Firmware since 1986.

Knuth uses "wyde" as backronym for "W" (16 bit "word"). For 32 and 64
bits, he uses tetra and octa, though.

L@/L! and X@/X! being single cell won't work on 16 bit systems (and 32
bit systems for X@/X!), but that's how it's commonly used. If anything,
L2@ or X4@ could be used (number indicates how many items on the stack
you'll get, on a 32 bit system : L2@ L@ 0 ; is the right definition).

With OF typically using le-w@ and be-l!, I suggest this syntax should be
used.

Stephen Pelc

unread,
Feb 27, 2010, 5:39:50 PM2/27/10
to
On Fri, 26 Feb 2010 11:06:24 -0800 (PST), Bruce McFarling
<agi...@netscape.net> wrote:

>Finally, L@ and L! extends beyond the defined minimum cell size in
>Forth-94. "It is an ambiguous condition if the number of bits to be
>stored or fetched is greater than the number of bits in the largest
>unsigned integer."

It is stated that systems should not provide words that handle data
beyond the cell size. This was done to avoid the portability issues
that lead to defining L@ as 2@ with incompatible stack effects on 16
and 32 bit systems.

Stephen


--
Stephen Pelc, steph...@mpeforth.com
MicroProcessor Engineering Ltd - More Real, Less Time
133 Hill Lane, Southampton SO15 5AF, England
tel: +44 (0)23 8063 1441, fax: +44 (0)23 8033 9691
web: http://www.mpeforth.com - free VFX Forth downloads

Stephen Pelc

unread,
Feb 27, 2010, 5:35:03 PM2/27/10
to
On Wed, 24 Feb 2010 18:55:08 -1000, Elizabeth D Rather
<era...@forth.com> wrote:

>Forth94 made strenuous efforts to avoid assuming 2's complement or
>byte-orientation. Is this TC really ready to abandon this policy? If
>so, there are a lot of other places that can be simplified. But think
>about it seriously.

What ones complement machines are current today?

>Do you, for example, want to render it impossible to run Standard Forth
>on devices such as Intellasys/Green Arrays products? Or other
>word-oriented devices, of which there are several in use?

There's nothing in this proposal that cannot be implemented on the
C18 core used by IntellaSys/GreenArrays. The prelude states that
that systems must not implement words dealing with data items larger
than the cell size.

>I note that Open Firmware was able to avoid having to have special

>operators for endian-ness, even though it worked on several big- and
>little-endian systems. That seems an unnecessary complication to me.

Again, consider having USB and TCP/IP on the same system. USB has
little-endian data and TCP/IP has big-endian. Apart from every PC,
we have plenty of clients who use both on the same embedded system.

Bruce McFarling

unread,
Feb 27, 2010, 6:33:30 PM2/27/10
to
On Feb 27, 5:35 pm, stephen...@mpeforth.com (Stephen Pelc) wrote:
> There's nothing in this proposal that cannot be implemented on the
> C18 core used by IntellaSys/GreenArrays. The prelude states that
> that systems must not implement words dealing with data items larger
> than the cell size.

If the proposal would specify the implication of the prelude that
defined-width, multi-byte values be stored in a sequence of bytes
aligned on address boundaries, that would make it more feasible to
implement the proposal on the C18 core.

I don't see the purpose served by preserving the rights of what seems
to be an empty set of bit-addressed and nybble-addressed
implementations. If the wordset assumes that the address-unit is eight
bits or greater, then "BYTES" can be dispensed with ... all byte
address arithmetic would be in address units, with memory access words
skipping the extra bits when the address unit is greater than eight
bits wide.

Bruce McFarling

unread,
Feb 27, 2010, 7:09:07 PM2/27/10
to
On Feb 27, 5:39 pm, stephen...@mpeforth.com (Stephen Pelc) wrote:
> It is stated that systems should not provide words that handle data
> beyond the cell size.

And then it includes the words in the base wordset, so that any
implementation providing the implementation has to provide the words.
Talk about a double-bind.

> This was done to avoid the portability issues that lead to defining
> L@ as 2@ with incompatible stack effects on 16 and 32 bit systems.

This violates the stack effect in any event, so it explicitly ruled
out by the specification. A fetch "(addr -- x x)" has to be given a
different name. That would be something for a support file for a
source library providing an alternative implementation of a capability
for a small cell system, not something for standardizing at the
language level.

However, after locating those words in MEMORY-WORDS EXT to *permit*
implementations with 16-bit or 20-bit cell sizes to implement the base
wordset with byte and short-word operators ... then if it is desired
to provide redundancy in the text of the proposal for extra security,
that's fine:

"An implementation *shall not* implement a word in this wordset that
operates on a value larger than the implementation cell-size. Any
implementation that supports this wordset with a cell smaller than 32

Elizabeth D Rather

unread,
Feb 28, 2010, 7:08:56 PM2/28/10
to
Stephen Pelc wrote:
> On Wed, 24 Feb 2010 18:55:08 -1000, Elizabeth D Rather
> <era...@forth.com> wrote:
>
>> Forth94 made strenuous efforts to avoid assuming 2's complement or
>> byte-orientation. Is this TC really ready to abandon this policy? If
>> so, there are a lot of other places that can be simplified. But think
>> about it seriously.
>
> What ones complement machines are current today?

Don't know of any, but there are a lot of people around more familiar
with the outer reaches of current architectures than I. At the time
Forth94 was in development a number of members of the TC had relatively
recent experience with one's complement and sign-magnitude
architectures, including me. I think Greg Bailey had a working one's
complement computer in his lab, although he readily acknowledged it was
obsolete. Another member was *currently* working with some
nibble-addressed processors.

I am not necessarily advocating retaining support for architectures that
really are in the technology dustbin, but I'm also leery of abandoning
architectures that are just not mainstream, at least without serious
thought and discussion.

>> Do you, for example, want to render it impossible to run Standard Forth
>> on devices such as Intellasys/Green Arrays products? Or other
>> word-oriented devices, of which there are several in use?
>
> There's nothing in this proposal that cannot be implemented on the
> C18 core used by IntellaSys/GreenArrays. The prelude states that
> that systems must not implement words dealing with data items larger
> than the cell size.

Well, insofar as there are definitely a number of devices around for
which 1 AU > 1 byte, and that does present a challenge. IMO it's worth
keeping that possibility in mind and making sure whatever you adopt is
implementable on such devices, although doing so may well involve
stretching a bit.

It is reasonable (and often necessary) for an implementor of a system or
an application to say, "My target market is machines with *these*
specific features." A standard, on the other hand, really needs to be
as ecumenical as reasonably possible.

Bruce McFarling

unread,
Feb 28, 2010, 8:11:49 PM2/28/10
to
On Feb 28, 7:08 pm, Elizabeth D Rather <erat...@forth.com> wrote:
> Well, insofar as there are definitely a number of devices around for
> which 1 AU > 1 byte, and that does present a challenge.  IMO it's worth
> keeping that possibility in mind and making sure whatever you adopt is
> implementable on such devices, although doing so may well involve
> stretching a bit.

Especially since the response is to repeat, up through the discussion
prefacing the proposal, a "probably computationally efficient" (though
not memory space efficient) means of coping with address units wider
than bytes.

The fix only appears in the preface in a slightly garbled and indirect
way, yet is not hard to include in the proposal. Roughly:

> Proposal
> ========

All memory access operations in this wordset are defined on one or
more successive address-aligned bytes. In MEMORY-ACCESS, wherever it
says "store" and "fetch", the following applies:

(1) Bytes shall not require address alignment
(2) For address units larger than 8 bits, each address unit refers to


one byte stored in the eight least significant bits. Additional bits
shall be ignored by these fetch operations, and should be set to zero
by these store operations.

(3) For address units smaller than 8 bits, end orientation of portions


of a byte stored in successive address units is implementation
dependent.

Where a value is larger than a single cell, the words associated with
that value can not and *shall not* be provided. Any implementation
with a cell smaller than 32 bits that provides this wordset *should*


return true and the size of one address unit in bits in response to
the ADDRESS-UNIT-BITS environmental query.

> 18.2.aaaa B! "b-store" MEMORY-ACCESS


> ( x addr -- )

> Store the 8 LSBs of x at addr.

> 18.2.aaab W! "w-store" MEMORY-ACCESS
> ( x addr -- )

> Store the 16 LSBs of x at addr in native format irrespective of
> alignment.

... etc.

Bruce McFarling

unread,
Mar 1, 2010, 11:48:02 AM3/1/10
to

Since a face to face meeting is coming up where time is set aside for
working on Forth 200x business ... after including specific language
in the proposal to reflect the seeming intent of the original proposer
for address units greater than 8bits, these above could be introduced
in a distinct RfD.

Reply all
Reply to author
Forward
0 new messages