wiki:AccessingMemory
close Warning: Can't synchronize with repository "(default)" (/project/movitz/svn does not appear to be a Subversion repository.). Look in the Trac log for more information.

The canonical operator for accessing memory (as such) is memref:

  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>

For a second example, assume you have a cons-cell in the variable 'x'. Cons-cells are pointers to

two consecutive words, namely the car and the cdr of the cell, and such pointers are recongnized by

their having a low-tag of 1 (i.e. they are offset by 1 relative to the true memory location).

Therefore the following operation:

  (memref x -1 :index 0)

will return (car x), while

  (memref x -1 :index 1)

returns (cdr x). To the extent that (typep x 'list) is indeed true, the above operations are exactly

equivalent to the car and cdr operations. That is, they are GC safe and generally "well behaved".

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

differently:

  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

such.

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).

Last modified 15 years ago Last modified on 09/21/09 21:53:11