Subj : BAJA OpCode suggestion
To   : Digital Man
From : Angus Netfoot
Date : Thu Dec 16 1999 11:56 am

RE: BAJA OpCode suggestion
BY: Digital Man to Angus Netfoot on Thu Dec 16 1999 01:00 pm

> > I'd like to suggest the introduction of a new BAJA opcode.  I don't know
> > you would call it, but in effect it would allow run-time modification of
> > BAJA code-space in a way similar to the POKE opcode known to BASIC progra
>
> Do you have a suggested syntax? Classic poke functions take an address and
> value, but how would the programmer know what address to poke? Perhaps an
> offset from the start of the current module's image? An absolute address wo
> probably be pretty useless.

I've been thinking about it some more.

The idea is to allow the programmer to generate code on-the-fly for immediate
execution without the overhead of writing a .BIN file to disk and then
executing it.  I figure that means either a POKE of some sort allowing the
code space to be changed, or an EXEC_STR that allows a sequence of BAJA/SBBS
instructions in string to be executed.  I'm not sure which one is the most
suitable there are probably good reasons for and against both.

If we could do this, we could look at BAJA operation codes as low-level
building blocks, and construct higher-level operations out of them.  These
higher-level operations would only need to be known to the BAJA compiler,
which would translate any high-level concept into the lower-level codes that
SBBS can understand and interpret.

If you are going to POKE stuff into the current code-space you probably need
to say WHAT to poke, WHERE to poke it, and HOW MUCH of it to poke.  You might
want to poke the least significant 1, 2 or 4 bytes of an integer (or integer
constant?) or maybe the first 18 bytes of a string (string constant?).  You
would want to poke relative to your own position, or absolute to the code-
space (POKER / POKEA maybe? or with a flag?).  So maybe something like:

   POKE <location> <value> <size> <flags>

<flags> might select RELATIVE or ABSOLUTE location, or even something weird
like RELATIVE_TO_ABSOLUTE_LABEL so you could POKE at Label+2 or something.
You might introduce a Pseudo-Label meaning "Here" so you could poke to $+6
or whatever.

With <size> defaulted to 4 and <flags> defaulted to maybe RELATIVE then the
last two would disappear in a lot of cases and the last one in almost all
cases, so the normal usage would be:

   POKE <location> <value>

As an alternative to the POKE idea, there is EXEC_STR as in something like:

   EXEC_STR <string to execute> <start offset> <flags>

The <flags> parameter could allow you to select whether to execute in the
current scope or it's own local scopeperhaps?  And default to the current
scope. The <start offset> would default to zero mostly, I suppose, but would
allow you to jump into the code-string somewhere in the middle.

This looks like it could be good.  EXEC_STR would allow you to construct
essentially mini-routines of a few dozen instructions in a string, without
worrying about where each part of each instructions was to be poked to.  But
there are probably lots of worrysome complications.  Recursive EXEC_STR
operations embedded in a string that you are already EXEC_STR-ing?
Performing loops and other branch-type operations within the string being
EXEC_STR-ed?  Needs thought.

> Might as well through a peek function in there too, eh? :-)

Couldn't hurt, although no immediate use comes to mind...  Are you thinking of
anything specific?

> To make it even more useful, pre-allocated data blocks (in the module code
> space, so they could be peeked/poked) would be nice.

I'm not sure I get what you are aiming at.

> Probably could use a WORD and DWORD variant of peek/poke too.

I think that you _do_ need to allow for variable length POKE operations, like
poking a single or two-byte op-code or a 4-byte operand CRC32 "address".  I
rather like the idea of being able to poke arbitrary strings of bytes so that
you could construct a sequence of instructions using a single SPRINTF or
something (or even read a string from disk), POKE the entire thing in one go,
and then CALL it, GOTO it, or fall through into it.

Hmmm.  Some other instructions might be useful to support this, like a way to
declare a block of space with a label on it maybe?  Oh, this is what you meant
earlier by pre-allocated data blocks.  Yes.  Good plan.

   #Hello World the HARD way
   SPRINTF Some_Str "\x51Hello, World!"    # x51 = PRINT
   POKE PokeHere Some_Str 13
   :PokeHere
       DEF_BYTES 13

sort of thing.

> That could really open up possiblities to the enterprising programmer.

Actually, it's sorta scary!  :)  Suppose we had the POKE op-code and we agreed
on a notational equivilence for array syntax.  Example, suppose we agreed that

   ADD MyArray[Dest] YourArray[Source]

is only a notational shorthand for

   ADD MyArray.32 YourArray.Wednesday

assuming that Dest = 32 and Source = "Wednesday".  Then we could do something
like:

   INT SAddr                               # we need these
   STR IAddr1 IAddr2

   SPRINTF SAddr "MyArray.%ld" Dest        # compute CRC\Address of Dest
   STRUPR SAddr
   CRC32 Iaddr1 Saddr

   SPRINTF SAddr "YourArray.%s" Source     # compute CRC\Address of Source
   STRUPR SAddr
   CRC32 IAddr2 Saddr

   POKE Modify+2 IAddr1                    # Modify code-space Dest
   POKE Modify+6 IAddr2                    # Modify code-space Source

   :Modify
       ADD Dummy Dummy                     # This is modified by the POKE

We have just added two array elements together, computing the elements at run-
time and we have used numeric and non-numeric indexes to boot.  And the only
new instruction introduced is the POKE itself.

Or instead of poke, you could do

   SPRINTF CodeStr "\x7F\x38%ld%ld" IAddr1 IAddr2      # neat!
   EXEC_STR CodeStr

The coding looks awful, but it could be simplified by a few new support
operations.  Maybe something similar to an SPRINTF that combined it's
arguments in some standard way, did a strupr() on the entire thing and
computed the CRC all in one operation.  But this is only icing, because
you could simply change BAJA.EXE to read

   ADD MyArray[Dest] YourArray[Source]

and generate the necessary long-hand code invisibly, "behind the scenes" as
it were.  Or you could leave the BAJA compiler alone and let programmers
develop their own pre-processor.

To declare an array,

   INT Array[10..16]  Yours[RED, GREEN, BLUE]   X[1..3][A, B, C]

could be a notational convenience meaning

   INT Array.10 Array.11 Array.12 Array.13 Array.14 Array.15 Array.16
   INT Yours.RED Yours.GREEN Yours.BLUE
   INT X.1.A X.1.B X.1.C X.2.A X.2.B X.2.C X.3.A X.3.B X.3.C

And either left to the programmer to hand-translate or handled by some sort of
preprocessor or by BAJA.EXE itself.

You could do multiple indexes (multi-dimensional arrays) by a similar process
where the "address" of the element could be computed by:

   SPRINTF SAddr "Array.%ld.%ld.%ld" X Y Z     # three dimentions

And structs/records could be done in some similar fashion.

I have not worked out the details, but you could probably do a computed CALL
or GOTO if you poked the destination part of a regular CALL or GOTO.

I think there is a lot of potential here with the addition of a POKE or maybe
EXEC_STR opcode, and possibly (but not necessarily) a couple other opcodes to
simplify generation of CRC32 "addresses" of variables.  The nice thing is, once
these building-block op-codes are in, people can come up with clever ways to
use them _afterwards_, without the SBBS executable having to be changed.  Only
the BAJA compiler or a pre-processor would need to be updated to handle the
new ideas, whatever they were, or the programmer could hand-translate at a
pinch.

Enough talk from me.  What do you think?

---
� Synchronet � telnet://talamasca-bbs.com   http://www.talamasca-bbs.com