# ACPI machine language

NOTE: This is a WIP

The ACPI tables [drv/acpi] describe their host in large part through its own
machine language called the AML. The machine that this langauge operates on
isn't a set of registers hooked to memory, no, it's a namespace.

That namespace is at the core of this language, it's what it produces and what
it modifies. It's also the main data structure provided by this unit.

## The namespace structure

The ACPI namespace is a tree of objects which can be of different types. There's
a finite number of types, each of which come with its own data structure.

The way we model these objects in Dusk is similar to how we model ASTs in
[comp/c] or in [comp/oberon], that is, we put them in [mem/cons].

An object is a cons where its car is an object ID and that ID determines the
structure of the associates cdr. Here are the IDs and structures:

00 int     (lo hi)
01 string  zstrptr
02 buffer  (lenobj (a u))
03 ref     (a u) a/u=range of namepath
04 package objs
05 name    (name obj)
06 mutex   (name synclvl)
07 scope   (ref objs) ref=0 mean root scope
08 device  (name objs)
09 thermz  (name objs)
0a pwrres  (name (objs (systemlvl resorder)))
0b oregion (name (space (offsetobj lengthobj)))
0c ofield  (name (oregion (flags (bitoff bitcnt))))
0d method  (name (flags (amladdr amllen))) amladdr=pointer to bytecode
0e bfield  (name (ref (mult (idxobj cnt)))) mult=idx and cnt multiplier

Note that this unit considers the source bytestream to be read-only and stable.
This means it will generate some pointers into this bytestream directly.

When the bytestream is interpreted, objects will be added to the namespace as
appropriate, most often in the current scope.

## Leaking the namespace

A typical ACPI namespace is bigger than the [mem/cons] GC pool. For this reason,
some objects added to the namespace are directly leaked. It can't be all of them
because the namespace is a very dynamic construct with circular references, but
all self-contained and static cons are leaked. This relieves some pressure on
the cons GC.

However, even with that leaking, the root namespace yielded by "getamlns" still
takes a lot of cons space. It shouldn't be held onto for long. You should do
whatever you need with it, mutation-wise, then either leak it entirely or drop
it so that the cons pool stays usable for other purposes.

## API

### Constants

\ OperationRegion spaces
enum SystemMemory SystemIO PCIConfig EmbeddedControl SMBus SystemCMOS
     PciBarTarget IPMI GPIO GenericSerialBus PPC PlatformRtMechanism

### Words

getamlns ( a u -- rootscope )
  Initialize a new root scope, then interpret AML code in range "a u", then
  yield the resulting NS, an object of the "scope" type.

.obj ( obj -- )
  Print "obj"'s representation recursively.

## Private API

### Words

findamlname# ( a -- a obj )
  TODO: this hasn't been implemented yet.

  Provided that "a" points to the beginning of AML code that is supposed to
  perform a namespace lookup, read that name and perform that lookup
  accordingly.

  That is, if "a" points to a straight name segment, perform that lookup in the
  current scope, then traverse the scope up until that segment is found. "a" is
  then increased by 4.

  When "a" is "\" or "^", the scope becomes root or parent (respectively) and
  scope traversal will not occur. Then, we increase "a" by one and recurse the
  logic.

  If, after a successful name segment find, a "." follows the name seg, increase
  "a" by one and recurse the find logic.

runaml1 ( a -- a obj-or-0 )
  Interpret the bytestream at "a" if this bytestream contains code that "create"
  an object. If it does, advance "a" so that it points right next to the
  interpreted bytestream and yield result object.

  This word only parses "simple" objects such as integers and string literals,
  object references, packages, etc. Running this never results in a modification
  of the current namespace.

  If "a" doesn't point to bytecode this word can understand, "a" is unchanged
  and "obj" is 0.

  Aborts if the bytestream can't be interpreted.

runaml1# ( a -- a obj )
  Run "runaml1" and abort with error on obj=0.

runaml[] ( a u -- ... n )
  Go through the byte stream in the input range and "run" it, that is, operate
  on the namespace according to AML specifications.

  We do this until the whole range is consumed.

  Yields a PS list of all objects that this bytecode adds to its current scope.

  Aborts if the bytecode can't be interpreted or goes outside its specified
  bounds.
