[movitz-devel] Re: Writing directly to memory

Frode Vatvedt Fjeld ffjeld at common-lisp.net
Wed Jan 3 10:14:19 UTC 2007

M Bealby writes:

>> [..] Anyone able to give me any hints?

Pascal Bourguignon <pjb at informatimago.com> writes:

> If you want to write to the memory, you don't want to write to an
> io-port!  Use normal memory accesses.  For example, using (setf
> muerte::memrange)

Right, the I/O and memory address spaces are accessed differently.
The canonical operator for accessing memory (as such) is memref (which
memrange currently boils down to, if you look at its source).

  defun memref (object offset
                &key (index 0) (type :lisp) localp (endian :host))

The object is any lisp-value whose 32-bit-pattern is taken as the base
address, to which the integer offset is added. Finally, the integer
index is multiplied with the byte-size of the type, and added to get
the final address.

For example, the lisp value 100 (a positive fixnum) is represented by
the bit-pattern #x00000400, which means that e.g.

  (memref 100 6 :index 1 :type :unsigned-byte16)

is compiled into something like this pseudo-assembly:

  movw (#x408) <destination>

A variant of memref is memref-int, which computes the address a bit

  defun memref-int (address
                    &key (offset 0) (index 0) (type :unsigned-byte32)
                         (physicalp t))

Here, the address is provided explicitly as an integer, to which the
integer offset and the index multiplied by the type's size is
added. memref-int tends to be more appropriate for accessing hardware
devices, while memref is more of a primitive for the lisp system as

I'll describe the remaining arguments which are (more or less) common
to the two operators. The type argument determines how the memory is
read and interpreted. To read a value of type :lisp, you have to know
very well what you are doing, because otherwise you can easily end up
with an illegal lisp value. For hardware programming, you typically
want :unsigned-byte32, 16, or 8. Some other types supported but less
useful are :character (which is 8-bit and rather ill-specified in
terms of character-sets, which is true of Movitz in general), and
:location which takes a 32-bit value and strips the lower two bits,
leaving a fixnum lisp-value.

The localp argument is to do with some GC-related protocols that are
not really finalized. Just leave it at its default is safe.

The endian argument determines the endianess of unsigned-byteXX bytes.

The physicalp argument, finally, is important. Set this to true if the
address is to be interpreted as a physical address, as seen on the
memory bus and by hardware peripheral devices. Movitz currently sets
up the CPU such that the default memory space is shifted one MB or so
from the physical address space (using segmentation). This leaves most
of the "interesting" hardware memory space unavailable, unless you
have :physicalp t (which is the default for memref-int).

Anyways, the following should be approximately what the OP wants:

  (memref-int #xa0000 :index foo :type :unsigned-byte16)

Hm.. I suppose a wiki would be nice for information such as this.

> Also, it imay be possible to map an array to a given memory address,
> so you can access these bytes directly with svref or aref.

This is unfortunately not currently possible. Christophe Rhodes' work
on extensible sequences might be worth looking at in this context,

Frode Vatvedt Fjeld

More information about the movitz-devel mailing list