Index

As this writing is a collection of my ideas that have not been written down in full before now, this page will be gradually updated and refined whenever I recall or conceive more and more of my ideas concerning the topic and feel the want. In particular, this article will necessarily become more detailed and perhaps changed in other ways as the program advances and the smaller interfaces solidify.

As this is the first entry of what is currently titled ``The Meta-Machine Code Targetted at MIPS'', along with being a large reason for the existence of this website, I find it reasonable that the title warrants explanation.

As described in another article, I intend to design an interactive machine code development environment, my Meta-Machine Code (MMC). This version will be targetted at MIPS machines, due to my already owning a Lemote Yeeloong, and is a Meta-Machine Code in which the target machine code is also the meta-machine code, that is MIPS will be used to target MIPS. There are some restrictions caused by alignment requirements that won't be worked around for convenience, but shouldn't be present in different targettings, and could be changed by anyone else customizing the system with the want. The intent is to have the system begin on OpenBSD 6.2, as this is the most convenient option for my Lemote Yeeloong, using the system call interface and others; later, it's intended that this infrastructure, the topic of this article, will be discarded for other infrastructure which permits booting into this MMC directly from the PMON2000 boot firmware of the Lemote Yeeloong.

The simplification of this infrastructure and seperating it from the idealized MMC was a great concern; the idealized version of this MMC is intended to be a twenty kilobyte program, with the first four kilobytes being the Meta-Machine Code itself and the remaining sixteen kilobytes being alloted for the meta-machine code routines and keyboard tables that compose the interface. The four kilobytes will mainly provide the meta-machine code routines with necessary services, such as showing output or disassembling an instruction, arrange for each meta-machine code routine to operate in a consistent environment, manage the names, and interact with the underlying environment to achieve this; that is, the Meta-Machine Code itself will collect input, reference the routine table, configure the registers according to the interface, and then give control to the corresponding meta-machine code routine, which will then use this interface along with the services to, as an example, assemble and then place an instruction in the correct location.

The specifics of this interface are still vague and incomplete, necessarily; a meta-machine code routine will know the location it was called for, will be able to interact with the services in a consistent fashion, will be able to communicate the length of the changes made. It was thought that, by default, a meta-machine code routine would be aborted when a question is not wanted to be answered, such as if the wrong routine is called, but would be able to change this at the flip of a bit; it was realized that this would be better served as a parameter to asking services, which removes a bit that need be worried about and that, perhaps, simply offering a different variation of the routine would be better. Regardless, this is necessarily something that is decided and changed as problems are noticed and as routines are written.

Now, to the OpenBSD infrastructure which comprises the other two parts, there will be a UNIX sh program which handles typical UNIXisms, such as command line arguments, and arranges for the machine code program to easily operate; this program will display help and version information, permit information already existing to be loaded, and arrange for the machine code program to take control with easy access to this information; the two observed limitations of this approach are that the loading of data already existing can only happen at the beginning of the program and that the saving of data can only be directed at the beginning of the program, as well, but is otherwise unhindered. The information will be made easily available by conforming to the intended internal structure of the machine code program, which may then read it in at the beginning. A UNIX program has access to three ``file descriptors'', ``standard input'', ``standard output'', and ``standard error''; the initial data will be dumped to standard input and standard error will be used to redirect output to be saved; standard output will be sent to the terminal to compose the interface. This choice removes the need for the open and close system calls and all of their unnecessary complications. Follows is the sh program, which may also be found here:

set -e
trap 'stty "${s:--g}" > /dev/null; rm -f "$i"' EXIT
i=$(mktemp '/tmp/mmc-input.XXXXXX')
o=$(mktemp '/tmp/mmc-output.XXXXXX')
case ${1:--h} in
-v|--version) printf 'Meta-Machine Code targetted at MIPS for OpenBSD 6.2\n'; exit ;;
-h|--help) printf 'mmc [[-h|--help][-v|--version]] save [data [metadata]]\n'; exit ;;
*) cat "${2:-/dev/zero}" > "$i"; truncate -s 20K "$i"
cat "${3:-/dev/zero}" >> "$i"; truncate -s 100K "$i" ;;
esac
s=$(stty -g); stty raw -echo
echo 'Resize the terminal to the desired dimensions and then press enter to continue.';read
cat "$i" - | mmc-mips-loader 2>| "$o" || true
clear; f="0"; n="0"; w=$(wc -c < "$o")
function c ()
{ if [ "$n" -ge "$w" ];
then { mv "$1.$(($f-1)).mips" "$1.mips"
mv "$1.$(($f-1)).mmc" "$1.mmc"
rm -f "$o"; return; };
else { dd if="$o" of="$1.$f.mips" skip="$n" bs=1024 count=20
dd if="$o" of="$1.$f.mmc" skip=$(($n+20)) bs=1024 count=80; }; fi
f=$(($f+1)); n=$(($n+10240)); c; }
if [ "$w" != 0 ]; then c; else { rm -f "$o"; exit; }; fi ||
printf '\nUnable to write output files; something is very wrong; find raw file at %s.\n' "$o"

The second part of the infrastructure will be a small machine code program written to: call the pledge system call to restrict what the program can do, as I find it amusing and am glad to only use the read, write, and exit system calls in the Meta-Machine Code here; to use the mmap system call to read in the Meta-Machine Code program into a suitably large buffer and so bypass any limitations on program self-modification; and to use the ioctl system call to obtain the terminal dimensions, writing the number of rows to a location for use by the program. This program is not yet written, but already, by description, is reasonably simple and straightforward.

Lastly, there will need be code in the Meta-Machine Code to access these three system calls; care was taken to minimize the size of this code; the read and write system calls can fail for any number of reasons and the best solution was seen to be a potentially infinite loop; this loop can be used for both of these system calls and careful arrangement of register loading permits multiple entry points for further minimization; it is unlikely that this loop will truly resemble anything nearing infinite. The exit system call is entirely trivial, consisting of two instructions, with its sole argument, the UNIX return value, using whatever is in the appropriate location at the time. This program fragment is not yet solidified in the sense that it's not yet committed as machine instructions, but rather a description of the routine; a handdrawn diagram using beautiful notation was used to write this and is intended to later be included as an image; follows is the routine in a more familiar notation:

  init Load number (100,000) into the count register.
Jump to reader.
file Load standard error into the appropriate register.
Load the number into the count register.
Jump to writer.
write Load the number into the count register.
Load standard output into the appropriate register.
writer Load the write system call number into the appropriate register.
Jump to sys.
read Load one into the count register.
reader Load standard input into the appropriate register.
Load the read system call number into the appropriate register.
sys Perform the system call.
Is the result in error? If so, jump to sys.
Does the result equal the count? If so, return.
Add the result to the address (already provided by caller).
Subtract the result from the count.
Jump to sys.