# Mixed arithmetic-with-logic instructions

Opcode | P/U | Category | Description |

`HAM2` |
user | ALU: mixed | Hamming weight part 2 |

`NOLIST` |
user | ALU: mixed | `NOP` , but hidden in listings |

`NOP` |
user | ALU: mixed | no operation |

`STUN` |
user | ALU: mixed | stacked unary |

`UN.A` |
user | ALU: mixed | unary alpha |

`UN.B` |
user | ALU: mixed | unary beta |

`UN.G` |
user | ALU: mixed | unary gamma |

Mixed arithmetic-with-logic instructions are those where their operands and results represent neither all numeric values nor all non-numeric values. `NOP`

and `NOLIST`

are documented with this set, because they handle no data and therefore show no bias toward being solely for arithmetic or solely for logic.

`HAM2`

Hamming weight part 2

Syntax |

`c = a ham2 b` |

Register | Signedness |

All | ignored |

1 opcode only |

Flag | Set if and only if |

`N` |
never; flag is cleared |

`Z` |
all result bits are zero |

`T` |
flag does not change |

`R` |
flag does not change |

`HAM2`

evaluates the quartic polynomial:

c = b_0 * 2**0 + ( a_6 + b_1 ) * 2**1 + ( a_12 + a_7 + b_2 ) * 2**2 + ( a_13 + a_8 ) * 2**3 + a_14 * 2**4

where `r_i`

denotes the 2**`i`

bit of register `r`

. Each `r_i`

bit has either 0 or 1 as its value. The result of the polynomial evaluation is stored in `c`

. The maximum value this polynomial can produce is 49.

This crazy expression, when preceded by the `HAM1`

macro, counts the number of `1`

bits in a register. This count is called the **Hamming weight** or **population count**. Because the architecture uses 36-bit words, the Hamming weight will be in the range 0 through 36 inclusive. Use would look like:

unsigned x ; input unsigned ones ; number of 1 bits in x unsigned t ; temporary t = ham1 x ones = t ham2 t

The `POPC`

macro, which expands to `HAM1`

and `HAM2`

, is more readable—although it disguises the fact two instructions execute instead of one:

unsigned x ; input unsigned ones ; number of 1 bits in x t = popc x

Unfortunately, none of the macros (including `HAM1`

and `POPC`

) are implemented, but `POPC`

would ultimately expand to `STUN`

and `HAM2`

, neither of which are macros. So the way population count is presently regression tested looks liike this:

unsigned x ; input unsigned ones ; number of 1 bits in x unsigned t ; temporary t = x stun.c 141414141414`o ones = t ham2 t

`NOLIST`

No list

Syntax |

`nolist` |

No registers used |

1 opcode only |

No flags changed |

This instruction sits out the current CPU cycle without writing to any register or changing any flags. `NOLIST`

produces the same control decoder signals as and behaves identically to `NOP`

.

`NOP`

differs from `NOLIST`

for documentation and testing purposes. Unused segments of code memory are filled with `NOLIST`

to tell disassemblers not to spew thousands of lines of irrelevant material. In contrast, `NOP`

is used in proximity to other instructions, and disassemblers should display any `NOP`

s encountered.

`NOP`

No operation

Syntax |

`nop` |

No registers used |

1 opcode only |

No flags changed |

This instruction sits out the current CPU cycle without writing to any register or changing any flags. See also `NOLIST`

.

The `NOP`

writeup on page 399 of the dissertation is very outdated and should be disregarded.

`STUN`

Stacked unary

Syntax |

`c = a stun.a b` |

`c = a stun.b b` |

... |

`c = a stun.k b` |

Register | Signedness |

Left | varies and not well specified |

Right | varies and not well specified |

Destination | varies and not well specified |

11 opcodes at present |

*The STUN opcodes have yet to be standardized and are unstable as of 14 June 2023. Do not use them in production software!*

The `STUN`

opcodes represent “super-instructions” that employ the ALU’s alpha, beta, and gamma layers in combination to compute one of 64 unary functions. The dissertation describes 25 functions, leaving another 39 slots available for future use.

`STUN`

employs the left operand as the argument for the unary function, and the right operand as a 6-bit selector that specifies which of 64 functions is being applied. This selector must be replicated across all 6 subwords in order to reach all 18 RAMs of the ALU’s alpha, beta, and gamma layer, which is why the constant 141414141414`o appears in the above `HAM2`

code example.

`STUN`

can do some crazy tricks, such as:

- absolute value in 2 instructions
- limited-range absolute value in 1 instruction
- Hamming weight in 2 instructions
- linear feedback shift register in 1 instruction
- decrement bit-reversed word mod 2
^{36}in 1 instruction

The unary functions supplied by `STUN`

have specific, conflicting requirements with respect to some of the control decoder signals. This is why there are eleven opcodes, why this section is so incompletely written, why I’m not ready to even begin writing regression test cases, and why it’s not helpful to define any assembler macro semantics yet.

More information about `STUN`

is available in the dissertation at pages 137–138 and 161–170, as well as in `instruct.c`

and `unary.c`

in the firmware source.

`UN.a`

Simple unary, alpha layer

Syntax |

`c = a un.a b` |

Register | Signedness |

Left | ignored |

Right | ignored |

Dest. | ignored |

1 opcode only |

`UN.a`

splits left operand `a`

into 6 contiguous subwords of 6 bits each, and pairs them off with the corresponding subwords of the right operand `b`

. Each right operand selects one of 64 unary functions, each having 6 input and 6 output bits, to apply to its corresponding left operand. The results are stored in the corresponding subwords of `c`

. The operation is done in the alpha layer of the ALU only.

The `UN.a`

instruction is somewhat of a solution looking for a problem. You aren’t likely to use it in programs you write, nor would you typically find it in programs I write. A fuller description of `UN.a`

, along with a list of available functions, appears in the dissertation at pages 160–161.

The `UN.a`

, `UN.b`

, and `UN.g`

lookup tables are identical, so the `UN.a`

instruction will produce the same result as `UN.g`

despite employing different SRAMs to compute it.

`UN.b`

Simple unary, beta layer

Syntax |

`c = a un.b b` |

Register | Signedness |

Left | ignored |

Right | ignored |

Dest. | ignored |

1 opcode only |

`UN.b`

is analogous to `UN.a`

and `UN.c`

and uses the same lookup tables, except the bits from the left operand are transposed, and the bits to the destination are transposed. Drawings showing this transposition are available on pages 75 and 88 of the dissertation.

The following two code segments produce identical results for `c`

:

; segment 1 c = a un.b b ; computed in beta while electrically transposed ; segment 2 a' = 0 txor a ; transpose c' = a' un.a b ; computed in alpha using transposed value c = 0 txor c' ; un-transpose

The `UN.b`

instruction is somewhat of a solution looking for a problem. You aren’t likely to use it in programs you write, nor would you typically find it in programs I write. A fuller description of `UN.b`

, along with a list of available functions, appears in the dissertation at pages 160–161.

`UN.g`

Simple unary, gamma layer

Syntax |

`c = a un.g b` |

Register | Signedness |

Left | ignored |

Right | ignored |

Dest. | ignored |

1 opcode only |

`UN.g`

splits left operand `a`

into 6 contiguous subwords of 6 bits each, and pairs them off with the corresponding subwords of the right operand `b`

. Each right operand selects one of 64 unary functions, each having 6 input and 6 output bits, to apply to its corresponding left operand. The results are stored in the corresponding subwords of `c`

. The operation is done in the gamma layer of the ALU only.

The `UN.g`

instruction is somewhat of a solution looking for a problem. You aren’t likely to use it in programs you write, nor would you typically find it in programs I write. A fuller description of `UN.g`

, along with a list of available functions, appears in the dissertation at pages 160–161.

The `UN.a`

, `UN.b`

, and `UN.g`

lookup tables are identical, so the `UN.a`

instruction will produce the same result as `UN.g`

despite employing different SRAMs to compute it.