Talk:NS32000/Archives/2015

Instruction set (WIP)
The NS32000 series instructions follow a consistent pattern: The 2 main general-purpose operands are each specified by 5-bit fields, which specify the operand addressing mode and thus the presence of index and displacement bytes for each operand. The additional displacements or constants depend on instruction only.
 * 1 to 3 bytes of opcode, which may specify up to 1 register operand and 2 general operands
 * An optional index byte for general operand 1 (usually the source)
 * An optional index byte for general operand 2 (usually the destination)
 * Up to 2 displacements for general operand 1, or operand 1's immediate value
 * Up to 2 displacements for general operand 2 (or operand 2's immediate value if not a destination)
 * Up to 2 additional displacements or 8-bit immediate constants, depending on the instruction.

A very few "quick" instructions embed a 4-bit signed immediate operand value in the instruction itself.

Addressing is generally consistently little-endian, but constants in the instruction stream (displacements and immediate constants) are stored most significant byte first.

As mentioned above, the size of the displacement is encoded in the most significant bits of the first byte of the displacement itself:
 * If the msbit of the displacement is 0, one byte supplies a 7-bit signed displacement (−64–63)
 * If the msbits of the displacement are 10, two bytes supply a 14-bit signed displacement (−8192–8191)
 * If the msbits of the displacement are 11, four bytes supply a 30-bit signed displacement (−536870912–536870911)

Processor registers
There are 8 general purpose registers (R0 through R7) and 4 special-purpose address registers: The addressing modes below refer to these address registers as A0 through A3, respectively.
 * FP (Frame pointer)
 * SP (Stack pointer)
 * SB (Static base, for global variable access)
 * PC (Program counter)

Additional significant registers:
 * There are actually two stack pointers. Interrupts use the interrupt stack pointer SP0, while user-level code uses the user stack pointer SP1.  The choice depends on the PSR's S bit (referred to as PSR.S).
 * The 32-bit INTBASE register points to an array of 127 interrupt vectors. The first 11 entries are assigned by hardware to non-vectored interrupts, non-maskable interrupts, and 9 traps that can be caused by instruction execution.
 * The 16-bit Processor Status Register (PSR) contains 6 or 7 user flags in the low byte, and 4 system flags in the high byte.
 * The 16-bit module register (MOD) points to the curent module descriptor; this is explained in more detail below. It is often combined with the PSR into one 32-bit word.
 * The 4- or 8-bit write-only configuration (CFG) register enables support for additional processor features:
 * CFG.I: NS32202 interrupt controller is present; use vectored interrupts.
 * CFG.F: NS32x81 floating-point coprocessor is present; allow FP instructions
 * CFG.M: NS32x82 memory-management unit is present
 * CFG.C: Custom coprocessor is present; enable format 15 instructions
 * CFG.FF: (32332+ only) FPU supports faster 32-bit protocol
 * CFG.FM: (32332+ only) MMU supports faster 32-bit protocol
 * CFG.FC: (32332+ only) Custom coprocessor supports faster 32-bit protocol
 * CFG.P: (32332+ only) MMU has page size ≥4K; makes detecting virtual aliases faster — Preceding unsigned comment added by 71.41.210.146 (talk) 22:44, 15 January 2012 (UTC)

Processor Status Register
The user flags are set implicitly by various instructions. Compared to other microprocessors, flag setting is extremely parsimonious; most instructions, including logical, shift, and multiply/divide instructions, do not modify the flags at all. Add and subtract instructions set only C (carry) and F (overflow); they do not set Z. Compares (integer, floating-point, or string) set Z, N and L.  ABS, CHECK, string operations, and the bit operations set F.  Other than that, only the instructions that explicitly modify the PSR modify the flags.

PSR bits 0 through 7 are user flags:
 * PSR.C: A traditional carry flag.  This is a borrow flag when subtracting.  It is not set by comparisons.
 * PSR.T: A status flag that enables program tracing.
 * PSR.L: A "lower flag", set only for comparison operations. It is set if the second operand is less than the first when interpreted as unsigned integers, i.e. op2−op1 generates a borrow.  Most other microprocessors would use the C bit for this purpose.
 * (PSR bit 3 is unused)
 * PSR.V: In early NS32xxx processors, PSR bit 4 is unused. In later models (NS32532 and NS32GX32), this bit, called PSR.V, enables a trap on integer overflow.  Note that this is different from other processors' V flags.
 * PSR.F: A general-purpose condition flag. It is set as an overflow flag by addition and subtraction operations, and bit test instructions copy the target bit to this flag.  It is also set by the bounds-check instruction (to 1 if out of bounds), address validation instructions, and string instructions (to 1 if until/while condition is met).  There is a special instruction which can trap if this bit is set.
 * PSR.Z: A traditional zero flag, if a comparison result is equal. It is not set by arithmetic or logical operations.
 * PSR.N: While this is called a "negative flag", it is different from other processors' negative flags; it is set only by comparison operations and indicates that the second operand is less than the first when interpreted as signed integers; i.e. op2−op1 is negative. Unlike other processors, this depends on the true result of the subtraction, before it is truncated to the destination width, and thus is not corrupted by integer overflow.  Most other microprocessors would have conditional instructions that tested both N and V bits for this purpose.

PSR bits 8 through 15 are system flags, and may not be accessed in user mode:
 * PSR.U: User flag. If set, privileged instructions are forbidden.
 * PSR.S: Stack pointer select. Cleared by interrupt.  This selects which SP register is used.  Typically has same value as U.
 * PSR.P: Trace pending. The T flag is copied here once per instruction; it prevents repeated trace traps.
 * PSR.I: Interrupt enable. If clear, only NMI is accepted.
 * (PSR bits 12–15 are unused)

Modules and external references
The NS32000 series provides support for run-time linking of multiple independent "modules" of code. There is always a current module, identified by the 16-bit MOD register, which points to a 3-word module descriptor located somewhere in the first 64K of memory.

One of those descriptor words is the link base (LB), which points to a "link table" of 32-bit references to other modules. Each reference to an external object in another module is assigned a slot in the link table, and only the link tables need to be adjusted to link modules together.

Link table entries are either 32-bit data pointers, or external procedure descriptors consisting of a 16-bit module and a 16-bit entry point offset.

External data
To reference "external" data in another module, the addressing mode specifies two displacements. The first specifies an index into the link table, where a 32-bit data pointer is stored, and the second is the offset from the resultant data pointer. The final address is [LB + 4×disp1] + disp2 (which may also, like all addressing modes, have a scaled index added to it).

External procedures
When making procedure calls between modules, things are more intricate. The "call external procedure" (CXP) instruction specifies a single displacement into the link table, and the selected word (at 4×disp + LB) contains an "external procedure descriptor" consisting of a 16-bit target module and a 16-bit entry point offset.

After saving the original module and program counter on the stack, the MOD register is loaded with the target module and the three words of the descriptor it points to are used as follows:
 * The first word is loaded into the SB register, for accessing module-local data. (The previous SB value is not saved, but will be reloaded from the module descriptor when returning.)
 * The second word is used as the new link base (LB). (NS320xx processors do not have a dedicated LB register which caches this value, but load it from the descriptor each time it is needed.)
 * The third word is the program base (PB). This is added to the 16-bit offset from the link table to produce the final PC value that control transfers to.

When returning from an external procedure (using the RXP instruction), the PC and MOD are restored from the stack, and SB is restored from the module descriptor.

Interrupts
Interrupts also take the form of external procedure calls. Instead of using the link base and a software-specified index, the interrupt base register points to an array of procedure descriptors, and the index is provided by hardware depending on the type of interrupt. On interrupt, the appropriate descriptor is fetched and an external procedure call is performed.

The only other difference is that the PSR is saved on the stack in addition to the current module and program counter.

Although it is possible to modify the MOD and SB registers independently using the LPR instruction, this is unwise unless interrupts are disabled; like external procedure calls, interrupts do not save the SB register but restore its value from the descriptor as part of interrupt return. Thus, normally the SB register should only be updated as part of changing modules.

Comparison to x86 segments
While some aspects of this resemble 80x86 segmentation, in particular the use of a 16-bit selector which points to an in-memory descriptor that is loaded into registers when the selector changes, and the use of separate "near" and "far" subroutine call/return instructions, there are significant differences. In particular, descriptors are part of the user address space and cannot be used to enforce protection boundaries. Also, there is only one current module, not separate segments for code, data, etc.

Addressing modes
General purpose operands are specified by a 5-bit field:

The top-of-stack mode pops the data from the stack pointer when used as a source operand, and pushes it when used as a destination. When used as both a source and a destination, it is equivalent to (but shorter than) 0(SP).

The indexed mode specifies an additional offset to be added to a base addressing mode.

A following index byte specifies (in its low 3 bits) an index register Rn, and (in its high 5 bits) a base operand. The index register is multiplied by a scale factor of 1, 2, 4 or 8 (indicated by a size letter S of B, W, D, or Q respectively), and added to the address of the base operand. Immediate and indexed modes are illegal as the base operand. TOS mode uses the SP as a base register without modifying it.

In contexts where a memory address is required, including as the base operand for indexed addressing mode, and some instructions which are unable to operate on register operands, register direct modes are interpreted as register-indirect with zero displacement.

String instructions
The NS32000 includes an orthogonal series of memory-to-memory string operations. These use registers R0 to R4 for fixed purposes in a way that lets the instruction be interrupted partway and seamlessly resumed. Not all instructions use all the registers. String instructions come in byte, word, and long sizes.
 * R0: Limit count. This specifies the maximum number of bytes or words to copy, and is decremented as the operation proceeds.
 * R1: Source string. This points to the beginning of the source, and is updated as the operation proceeds.
 * R2: Destination string.
 * R3: Translation table pointer. For byte operations only, a "translated" variant can be used, where a source byte is looked up in the table pointed to be R3 before being used.
 * R4: Comparison value. String operations can be halted before R0 runs out by a byte or word in the source whose (translated) value matches this register.

Options are specified by a 4-bit field:

The mapping of bit 2 is not explained perfectly by the above table; it is set to cause matching with R4 to be a termination condition; the polarity of bit 3 controls whether the letter to use is W (if not set, repeat while match) or U (if set, repeat until match). If this happens, the PSR.F bit is set to 1, and responsible datum is not copied.

All string instructions set the PSR.F flag; it is set to 0 if the operation is terminated by the count in R0 running out, and 1 if the operation is terminated due to comparison with R4. If the W or U options are not specified, this is the only case which ever occurs.

Bit and bit-field instructions
Bits are addressed using a 32-bit "base" byte address plus a 32-bit bit offset. These are combined in a 35-bit bit address, which is consistently little-endian. (E.g. bit 11 is bit 3 of byte 1.)

The bit manipulation instructions (test, set, clear, and invert) copy the bit to the PSR.F flag before modifying it.

Bit fields add a length field, and can be accessed using "insert" and "extract" instructions to copy a general operand to a bit field and vice-versa, respectively. Extraction is unsigned; the field is zero-extended to fit the destination. In the general case, the bit offset is a register value, and the length is a constant displacement. If the offset and length are both small constants, there are "short" forms of these instructions which pack them both into an 8-bit immediate (5 bits of length−1, followed by 3 bits of offset).

Another bit-field instruction is "find first set", FFS. This updates the offset operand to the index of the first set bit in the field and clears PSR.F, or sets PSR.F=1 if the field is all zero.

Floating point
Floating point was performed by an external coprocessor: NS32081, NS32381, or a combination of the NS32580 controller and Weitek WTL 3164 FPU. The original '081 had 8 32-bit registers (F0 through F7), and even-numbered pairs were available for long (64-bit IEEE double) operands.

Later models provided 8 64-bit registers, L0 through L7, with the 32-bit registers aliased to the halves of the even-numbered L registers.

Instruction encoding
A trailing i represents an integer operand size letter: (B)yte, (W)ord or (D)oubleword. These are 8, 16 and 32 bits, and represented by the values 0, 1 and 3 in the size field, respectively. The value 2 is used to encode other instructions. A trailing f indicates a floating-point operand size letter, encoded using a 1-bit size field: (L)long (64-bit, size bit 0), or (F)loat (32-bit, size bit 1). Note that the terms "long" and "double" are swapped relative to the C language.

The most common instructions are 2 bytes long, and have the operand size in the least-significant bits of the first byte. The unused integer operand size encoding "10" is used for 1-byte instructions (whose lsbits are "010"), and 3-byte instructions (whose lsbits are "110"). 3-byte instructions encode the operand size in the lsbits of the second byte.

The opcode assignments are clearest if presented with the least significant bit (bit 0) first, and opcodes sorted as if lower-numbered bits were more significant, so the tables below lists them that way. Embedded values (such as register numbers) still have their most significant bits in higher-numbered bit positions. Also, binary numbers included in running text without explicit bit-number headers use the conventional msb-first ordering.

For the LPR and SPR instructions, the 4-bit k value specifies the processor register as: Values of 1–7, 11 and 12 are undefined. Note that changing SB or MOD this way is dangerous unless interrupts are disabled, as SB is not saved across interrupts, but rather restored from the descriptor pointed to by MOD.
 * 0: User stack pointer, SP1
 * 8: FP
 * 9: SP (current SP, based on PSR.S)
 * 10: SB
 * 13: PSR (only allowed when PSR.U=0)
 * 14: INTBASE (only allowed when PSR.U=0)
 * 15: MOD

''This is being worked on here until is ready for inclusion in the article. Main reference, see e.g. page 143 et seq. Detailed instruction definitions begin on p. 1259. Also 32532 data sheet and NS32381 data sheet.'' 71.41.210.146 (talk) 08:40, 25 April 2010 (UTC)