User instructions
User instructions are CPU instructions that preserve separation between programs under all circumstances. A user program is a program that contains only user instructions. User instructions and user programs may also be called nonprivileged instructions and nonprivileged programs respectively.
Most Dauug|36 programs will be user programs, so a large fraction of Dauug|36 assembly programmers may not need to learn any privileged instructions. If you are new to this architecture, you may wish to contain your early study to user instructions.
The remainder of this page offers a high-level introduction to four distinct sets of Dauug|36 user instructions:
- ALU instructions
- branch instructions
- memory instructions
YIELD
The pages that descend from this page document the user instructions themselves.
ALU instructions
ALU instructions are those manipulate registers and flags via the arithmetic logic unit, or ALU, exclusively. These instructions don’t do I/O, don’t touch any data memory, don’t affect the instruction pointer, etc. They merely perform arithmetic or logic operations on 36-bit words.
There are many ways to categorize ALU instructions. One way is to place them into these three sets:
- instructions that read and write registers
- instructions that read, but do not write, registers
- instructions that write, but do not read, registers
The supermajority of ALU instructions both read and write registers. Dauug|36 has more than 100 such instructions. For example, the A
(add) instruction might read registers subtotal
and tax
, add them, and write the result to total
. In assembly language, this would be written as:
total = subtotal + tax
Aside. If names like tax
don’t sound like register names, consider that the architecture has 512 registers for every program that is running. You wouldn’t want to refer to them by numbers in your programs. Instead, you declare them with appropriate in Dauug|36 assembly language, and leave numbering them to the assembler.
A handful of instructions only read registers. These include CMP
(compare), which compares the magnitude of two registers and sets the Z(ero) and N(egative) flags based on their difference:
cmp assets - liabilities
A very few instructions write to a register without first reading from one. One example is IMP
(immediate positive), which loads a constant between 0 and 262,143 into a register:
node.weight = 500
This section’s examples used features of Dauug|36’s assembly language that may seem unusual:
- The mnemonic
A
isn’t written out. Instead, we write+
in the familiar manner. CMP
is written, but also includes a mandatory-
as a semantic reminder.- The mnemonic
IMP
isn’t written out. Instead,=
indicates a simple assignment.
Branch instructions
While Dauug|36 executes one instruction, it simultaneously fetches the next instruction to execute. Ordinarily, the next instruction’s address in code memory is one greater than the current instruction, allowing programs to run in sequential order as we expect.
Branch instructions are different, in that the next instruction may come from some other address. These instructions are:
JUMP
CALL
RETURN
REVERT
JUMP
comes in an unconditional form:
jump some_label
as well as ten forms that are contingent on flags, one of which is:
jump < it_was_negative
CALL
and RETURN
are unconditional. They behave in familiar ways:
call print_in_decimal (remainder of program) print_in_decimal: (print some number in decimal) return
REVERT
is the same as RETURN
, except that flags are restored to what they were at the corresponding CALL
. REVERT
allows subroutines to internally use flags without modifying their callers’ flags. Also, the operating system’s scheduler uses REVERT
to return to user programs without their flags disturbed by preemptive multitasking.
Memory instructions
Because Dauug|36 provides 512 registers to every running program, many programs can be written that do not require additional memory beyond these registers. But programs that use collections (strings, lists, etc.) generally require data memory. Memory instructions are the mechanism by which user programs employ their memory. In this example with two memory instructions, LD
(load) and STO
(store) increment whatever is at memory location 36:
counter = ld 36 counter = counter + 1 sto 36 = counter
Paged virtual memory ensures that Dauug|36’s nonprivileged memory instructions can only access memory that the program has been authorized to access. In other words, LD
and STO
, like all unprivileged instructions in the architecture, honor the page table.
YIELD
Dauug|36 has a user instruction called YIELD
that’s in a category by itself. It doesn’t involve any registers, memory, or branching. Its syntax is simply:
yield
YIELD
causes the Dauug|36 firmware to pause execution of the user program. Ordinarily this is because the program either is making a kernel request or is able to relinquish the CPU for a time.
Programming with YIELD
requires some advanced knowledge, because the CPU does not immediately switch programs. The Cooperative multitasking and Preemptive multitasking articles elaborate on this more specifically.