GOPHERSPACE.DE - P H O X Y
gophering on verisimilitudes.net
                           Experimentations with 33554432 and Meta-CHIP-8

The initial design and release of my MMC targeted at CHIP-8 are intertwined with my experimentations
regarding a pair of my machine code designs, both memory-to-memory, and both ultimately unnecessary.
The prior version of this article contained many subjunctive details and whatnot which I've removed.

The vague machine code 33554432 inspired me to create the MMC; it's a set of twenty-five bits acting
as switches, hence the name, and I recognized the queer design was obviously unsuited to assemblers.
My expectation, back in 2015, was this design would perhaps help facilitate self-modifying programs;
that first bit was a ``nothing'' bit which had such instructions ignored, enabling a loop to disable
its initialization code.  My basic idea was that each bit would signal an operation, and these would
be specially chosen to compose well; I regard this machine code as a failure with a pleasant result.

My 2017-05-07 article contains further thoughts regarding what I seek out with some machine designs.

My Meta-CHIP-8 underwent two revisions: one only described, and that which was actually implemented.
The purpose of Meta-CHIP-8 was to manipulate CHIP-8 programs in the context of my Meta-Machine Code.
So, I designed Meta-CHIP-8 to resemble CHIP-8 in form and function; I also wanted to experiment with
memory-to-memory machines, which led to some fine revelations for the model, yet failed in producing
an overall nice design.  I never designed any tool for writing Meta-CHIP-8, programming it manually.

The basic form of Meta-CHIP-8 was a uniform twenty-four bit or three octet instruction format, split
into octets or nibbles.  The first nibble was the command code; the following octet two-thirds of an
address, combined with the program counter to form a total address; and the latter half being either
a total address, or a second nibble as a subcommand code followed by a second octet partial-address.
This design naturally split memory into sixteen octet blocks of two hundred and fifty-six each.  The
machine wasn't unpleasant to program, and the blocks were reasonably large for programs and storage.

The program counter and various hooks into the MMC and whatnot were implemented by providing special
addresses in that final block of memory.  One idea of mine was having the penultimate pair of octets
hold the previous program address, and attempt to replace explicit subroutine support with a general
mechanism, but this didn't have the intended result, merely being bothersome and shifting the burden
to the called, in place of the caller.  Follows is the relevant memory layout of the ultimate block:

FE0  FE1  FE2 FE3  FE4  FE5     FE6    FE7
quit jump up  down save instate insert delete
FF0    FF2         FF3 FF4    FF5          FF6        FF7 FFA        FFB FFC     FFD FFE         FFF
escape calling address random deposit size calling hextet penultimate PC ultimate PC program counter

The FEX range was used for program termination by calling a system routine, with FE0 and FE1 serving
as argument spaces, FE2 and FE3 then serving as additional argument spaces, where necessary.  System
functionality, such as quitting, would be gated by a routine asking for confirmation before jumping.

Follows is a description of the special instructions, using a lone command code, an octet, and total
address.  These vary with how the address and octet are used, and so are akin to specialized axioms:

L - Local address formed by octet; A - Total address; P - Program space total address;
I - implicit destination, the final local octet

0 L <- A; Transfer the octet of the total address to the local address.
1 A <- L; Transfer the octet of the local address to the total address.
2 L <- A; L+1 <- A+1; Transfer the hextet of the total address to the local address.
3 A <- L; A+1 <- L+1; Transfer the hextet of the local address to the total address.
4 L <- P; Transfer the octet of the program space to the local address.
5 P <- L; Transfer the octet of the local address to the program space.
6 L <- P; L+1 <- P+1; Transfer the hextet of the program space to the local address.
7 P <- L; P+1 <- L+1; Transfer the hextet of the local address to the program space.

8 Disassemble the hextet beginning from L as a CHIP-8 instruction.  An XYYY begets a one followed by
  that command code and hextet containing the address; an XYZZ begets a two followed by that command
  code, an octet containing Y, and the ZZ octet; and an WXYZ begets a three followed by that command
  code, an octet containing X, an octet containing Y, and an octet containing Z; the output is to A.
9 Assemble the output of disassemble beginning from A, as a CHIP-8 instruction, beginning from L; if
  the first octet is zero, it represents Meta-CHIP-8 instructions by two nibbles, octet, and hextet.
A Interpret the octet as a count and show a string of count characters beginning from A.
B Interpret the octet as a limit and read in characters below, placing them from A; I is the length.
C Interpret the hextet beginning at L as a limit; read an integer, no larger, to deposit as octet or
  hextet from A, determined by the limit permitting this or not.  Place the name used at I, or zero,
  if no name was used; D is C starting in name entry.  If defaults are given, memory is undisturbed.
E This is the extended command code.
F Stop Meta-CHIP-8 processing.

I'm particularly pleased with the design of 8, 9, C, and D.  Designing a machine code so that it may
easily self-modify is crucial, in my eyes, and Meta-CHIP-8 used this to achieve indirect addressing.
The decision to have C and D leave memory undisturbed when the defaults are used automatically gives
a mechanism for providing default values, and almost stops the system from knowing if this was used.
The F entirely ignores its arguments, doing little, and the space can be treated as any other manner
of memory.  Follows is a description of the extended command codes; these are, mostly, more uniform:

1 - first local address; 2 - second local address

0 Sum the octets of 1 and 2, to 2; I is set to zero or one to indicate overflow.
1 Delta the octets of 1 and 2, to 2; I is set to zero or one to indicate underflow.
2 Multiply the octet of 1 by two, to 2; I is set to the prior MSB of the octet of 1.
3 Divide the octet of 1 by two, to 2; I is set to the prior LSB of the octet of 1.
4 Skip the following instruction if the octets of 1 and 2 are equal.
5 Skip the following instruction if the octets of 1 and 2 aren't equal.
6 Place the three-octet decimal representation of the octet of 1 beginning from 2.
7 Place the five-octet decimal representation of the hextet of 1 beginning from 2.
8 Logically AND the octets of 1 and 2, to 2.
9 Logically IOR the octets of 1 and 2, to 2.
A Logically XOR the octets of 1 and 2, to 2.

The B encompasses a variety of miscellaneous name manipulations, predicated by the high nibble of 1;
2 is a twenty-octet data: hextet name code; hextet value; octet label, size; and fifteen characters:

0 Populate the name data at 2 according to its name code.
1 Delete the name according to the name code.
2 Change the name by its identifier and update the name code field.
3 Create the name by its identifier and update the name code field.
4 Populate the name data at 2 according to the name identifier.
5 Populate the name data at 2 according to any label corresponding to the value.

Those ultimate four instructions also interact with the name system, and treat each local address as
also designating a hextet which holds a three-bit assocation and twelve-bit name code to manipulate:

N - first name hextet; M - second name hextet

C Fill the hextet of 2 with N.
D Fill the name tables corresponding to the address of the hextet of 1 with M.
E Have the hextet of 2 be the routine information for the address of the hextet of 1.
F Have the routine entry for the address of the hextet of 1 be the address of the hextet of 2.

This bizarre design was clearly harmed by its mimicking of CHIP-8; a prime advantage of some memory-
to-memory designs, using memory-movement instructions for multiple purposes, was lessened by needing
eight variations; using octets as the fundamental unit also harmed this.  It was a useful experience
for me, however; the design using total and local addresses is an interesting compromise to decrease
instruction size, and many advantages were still present; memory management was generally simple, by
treating the end of each block as the dumping ground for intermediate results.  My plan for ultimate
program counters to remove the need for routine mechanisms was misguided, as it requires any routine
to know where it's called anyway, in order to save it for later.  It was a mere valuable experiment.

I may later dedicate an article to documenting the large program I wrote in Meta-CHIP-8, on my whim.
.