The Dauug House Wright State University logo
Dauug|36 minicomputer documentation

Pseudo-instructions (privileged)

Opcode P/U Category Description
HALT priv pseudo halt
HIJACK priv pseudo hijack control decoder
XOOB priv pseudo executable out-of-band command

This section introduces three opcodes that have names, but aren’t precisely instructions.

HALT Halt

Syntax
halt
No registers used
No flags changed

The HALT instruction sets a control decoder bit that means for the CPU to stop running. Neither the netlist nor the physical machine, when one is built, do anything with this control decoder bit. In real life, HALT is a no-op.

The electrical simulation of Dauug|36 programmatically inserts a one-bit flip-flop that receives the HALT bit from the control decoder, and tweaks that flip-flop in a manner that causes the simulation to pause when a 1 is clocked in. This typically is done immediately following register writes in a regression test, so that the script can query the register for the last value written and ensure the value is as expected. Simulation either terminates at the end of the script, or resumes until the next HALT is “executed.”

HIJACK Hijack control decoder

No syntax
No registers used
No flags changed

HIJACK occupies a position in the opcode table for use as a template that is part of every other instruction.

The assembler does not recognize HIJACK as an instruction, but if it were to be assembled and executed, HIJACK would behave like a PCALL to the next line of code. In other words HIJACK would effectively do this:

    pcall next
next:

which is equivalent to doing this:

    call next
next:
    priv

This entire discussion is about preemptive multitasking, which is accomplished by “hijacking” the program decoder such that the instruction decoded does not match the instruction fetched. The program decoder is an 8192 × 72-bit memory assembled from two 36-wide SRAMs. It has 13 input bits and 72 output bits. Nine input bits are the opcode for the instruction to execute, allowing the architecture to have up to 512 instructions (of which HALT and HIJACK waste two slots). Every instruction has 4 clock cycles without exception, and input bits 0 and 1 to the control decoder indicate which clock cycle is to be decoded for the indicated opcode. The decoder RAMs are wired to use “burst mode,” where the opcode is only supplied for the first clock cycle of an instruction, and the RAMs internally increment their address to read control signals for the subsequent clock cycles. Burst mode is more than a convenience here, because there is contention at node 1 (see drawing on dissertation page 200) for data during the remaining clock cycles.

Input bits 11 and 12 to the decoder RAMs enable the control decoder to be taken over, or hijacked, by the firmware to switch from a user program to the operating system. To achieve this, every Dauug|36 instruction has four versions in the control decoder, so altering bits 11 and 12 can change which version is in control.

Input bits 11 and 12 are driven by a two-bit Gray code counter, so the count sequence is not 0, 1, 2, 3 but 0, 1, 3, 2. This isn’t important functionally, but makes the counter circuit a tiny bit simpler. The Gray code counter stays at 0 until the multitasking timer expires. The next three groups of four clock cycles (normally called instructions) progress the Gray code counter through 1, 3, 2 for a total of 12 clock cycles, after which the counter outputs 0 and continues to output 0 until the timer expires again. I’ve named these four steps in the Gray sequence quadrants for no particular reason. Here is what you’ll find in the control decoder for the four quadrants of every instructions:

Quadrant 0

Quadrant 0 contains each instruction in its original unmodified form. Ordinarily when an instruction is fetched for execution, it is the version in this quadrant that the control decoder will look up for its 72-bit output for each of the instructions’ four clock cycles.

Quadrant 1

Quadrant 1 does not follow Quadrant 0, but is substituted for it. Quadrant 1 is a tiny modification of each instruction. Ordinarily, a circuit called the instruction pointer incrementer adds one to the instruction pointer so that the next instruction can be fetched. We have to now add zero instead, because the instruction pointer always stays ahead by one to prefetch instructions, and we have to save the instruction pointer in its current unincremented form on the call stack so that when we return to this user program later, an instruction is not skipped.

So when the multitasking timer expires, an instruction is soon loaded with its Quadrant 1 version, which doesn’t increment the instruction pointer. Except for this tiny change, the instruction executes exactly as before.

Quadrant 3

Quadrant 3 directly follows Quadrant 1, and is a radical change from the instruction that is presented for execution. The CPU doesn’t actually know the instruction decoder has been hijacked, and the instruction pointer increment was skipped in quadrant 1, so what instruction is being decoded in Quadrant 3?

Exactly the same instruction as four clock cycles ago when we were in Quadrant 1. An instruction that we just finished executing has already been fetched a second time, is being decoded a second time, and is having its registers fetched a second time. But the control decoder signals that are stored in Quadrant 3—they are identical for all 512 instructions—are the control signals to implement the HIJACK instruction.

HIJACK, which exists 512 times but only in Quadrant 3, save the address of the instruction the user program needs to return to on the call stack. Quadrant 1 was so kind as to not increment it, because there is no electrical means in the netlist to recover had the instruction pointer been incremented. HIJACK also places the CPU in PRIV mode, meaning that further operations on the registers, page table, and call stack will affect the superuser instead of the (nonprivileged) user.

While the system remains in PRIV mode, the multitasking timer will be prevented from taking control of the system again.

Quadrant 2

Quadrant 2 directly follows Quadrant 3, and like Quadrant 3 produces the same control signals for all 512 instructions. What do these control signals do in Quadrant 2? REVERT. Even though the CPU fetched that same instruction yet a third time which we already executed in Quadrant 1, is now decoding that instruction a third time, and is now fetching the registers for that instruction a third time, we leave it executed just once, during Quadrant 1. HIJACK, and now REVERT, are executed in lieu of the second and third occasions.

Because we now have the superuser’s page table, stack, and registers, Quadrant 2’s REVERT pops the code address the superuser will continue from, alongside the superuser’s flags, from the top of the superuser’s call return stack. See NPCALL under Identity-modifying instructions for a refresher on how this information got to be on top of the superuser’s stack.

Quadrant 2 is the last in the control decoder hijack sequence, wherein the CPU has transitioned from running a user program to running the superuser’s code. After Quadrant 2, the REVERT is complete and the operating system has use of the CPU until it’s time for the next NPCALL.

XOOB Executable out-of-band command

No syntax
No registers used
No flags changed

XOOB (executable out-of-band command) is an opcode consisting of 9 one bits. It’s programmed in the firmware as if it’s a NOP (no operation), and is only classified as privileged because it’s placed above the lowest-numbered privileged opcode.

XOOB is not part of a program and is never written to code memory as an instruction. Instead, it serves as a marker within the Dauug|36 executable file format to structure the file’s contents.


Marc W. Abel
Computer Science and Engineering
College of Engineering and Computer Science
marc.abel@wright.edu
Without secure hardware, there is no secure software.
937-775-3016