# Zahlen

Zahlen is a stack-based processor specification discovered by User:Orby during March of 2019 (and revisited during February of 2021). Zahlen is particularly suited toward solving numerical problems in a small amount of space. This page is a work in progress. Many operators are yet undocumented. Please contribute comments and ideas on the discussion page.

## Introduction

Zahlen is intended for use in code golf competitions involving numbers. Each Zahlen instruction is represented by an 8-bit code. This makes Zahlen instructions more compact, but also restricts the number of available instructions. The codes 0xA0 through 0xFF are reserved for future expansion.

## Types

Zahlen operates on two types: logicals and numericals. Logical values are matrices whose cells are 32-bit unsigned integers. Operations performed on logical values are performed bit-wise. Numerical values are matrices whose cells are IEEE 754 double precision floating point values. In this documentation, matrices are enclosed in brackets.

## Opcodes

What follows is a comprehensive list of opcodes.

### Unary operators

Each unary operator pops a value from the stack which we refer to here as A. The i,j-th cell of A is referred to as ai,j. The value pushed is dependent upon the type of A and the operator selected. Each operation is named after its effect on a numerical.

#### Count

Pneumonic: count

If A is not 1 x 1 or a1,1 is zero, then the result is undefined.

0x80 Result
Logical [ 1, 2, ..., a1,1 ] for 1 x 1 matrix A
Numerical [ 1, 2, ..., floor(a1,1) ] for 1 x 1 matrix A

#### Increment

Pneumonic: inc

0x81 Result
Logical [ ai,j + 1 ]
Numerical [ ai,j + 1 ]

#### Decrement

Pneumonic: dec

0x82 Result
Logical [ ai,j - 1 ]
Numerical [ ai,j - 1 ]

#### Negate

Pneumonic: neg

Alternate pneumonic: not

0x83 Result
Logical [ not ai,j ]
Set [ -ai,j ]

#### Cast

Pneumonic: cast

0x84 Result
Logical A as numerical (no precision lost)
Numerical A as logical (floor(ai,j))

#### Transpose

Pneumonic: trans

0x85 Result
Logical [ aj,i ]
Numerical [ aj,i ]

#### Sign

Pneumonic: sign

0x86 Result
Logical [ sign(ai,j) ]
Numerical [ sign(ai,j) ]

### Trigonometric functions

These operators all push numerical results.

#### Sine

Pneumonic: sin

0x87 Result
Logical [ ai,j << 1 ]
Numerical [ sin(ai,j) ]

#### Cosine

Pneumonic: cos

0x88 Result
Logical [ ai,j >> 1 ]
Numerical [ cos(ai,j) ]

### Binary operators

All binary operators in Zahlen pop two arguments from the stack and push the result. The first argument on the stack is represented as A and its type is provided in the first column of each table. The second argument on the stack is represented as B and its type is provided in the first row of each table. The operation performed depends upon the types of those arguments. Each operation is named after its effect on two numericals. If A is 1 x 1 and B is m x n, then A is expanded to m x n and filled with a1,1.

Alternate pneumonic: xor

0x8A Logical Numerical
Logical [ ai,j xor bi,j ] [ ai,j + bi,j ]
Numerical [ ai,j + bi,j ] [ ai,j + bi,j ]

#### Subtraction

Pneumonic: sub

0x8B Logical Numerical
Logical [ ai,j xor bi,j ] [ ai,j - bi,j ]
Numerical [ ai,j - bi,j ] [ ai,j - bi,j ]

#### Multiplication

Pneumonic: mul

0x8C Logical Number
Logical [ (ai,1 and b1,j) xor (ai,2 and b2,j) ... ] [ (ai,1 * b1,j) + (ai,2 * b2,j) ... ]
Numerical [ (ai,1 * b1,j) + (ai,2 * b2,j) ... ] [ (ai,1 * b1,j) + (ai,2 * b2,j) ... ]

#### Pointwise Multiplication

Pneumonic: pmul

Alternate pneumonic: and

0x8D Logical Number
Logical [ ai,j and b1,j ] [ ai,j * bi,j ]
Numerical [ ai,j * bi,j ] [ ai,j * bi,j ]

#### Pointwise Division

Pneumonic: pdiv

Alternate pneumonic: or

0x8E Logical Numerical
Logical [ ai,j or bi,j ] [ ai,j / bi,j ]
Numerical [ ai,j / bi,j ] [ ai,j / bi,j ]

#### Remainder

Pneumonic: mod

0x8F Logical Numerical
Logical [ ] [ ai,j % bi,j ]
Numerical [ ai,j % bi,j ] [ ai,j % bi,j ]

#### Power

Pneumonic: pow

Alternate pneumonic: <<

The notation << denotes left shift.

0x90 Logical Numerical
Logical [ ai,j << bi,j ] [ ai,jbi,j ]
Numerical [ ai,jbi,j ] [ ai,jbi,j ]

#### Logarithm

Pneumonic: log

Alternate pneumonic: >>

The notation >> denotes right shift.

0x91 Logical Numerical
Logical [ ai,j >> bi,j ] [ logai,j(bi,j) ]
Numerical [ logai,j(bi,j) ] [ logai,j(bi,j) ]

### Matrix manipulation

These operations are for decomposing and building matrices.

#### Car

Pneumonic: car

Notice this pushes two results: the first row of A and A with the first row removed.

00x92 Result
Logical [ a1 ], [ a2, a3, ... ]
Numerical [ a1 ], [ a2, a3, ... ]

#### Cons

Pneumonic: cons

This is the opposite of car. It takes two matrices and concatenates them row-wise. A must have the same number of columns as B.

0x93 Logical Numerical
Logical [ A, B ] [ A, B ]
Numerical [ A, B ] [ A, B ]

### Subroutines

TODO Think about passing a column vector of addresses to call for concurrent function calls.

#### Call

Pneumonic: call

Opcode: 0x94

Pop A from the stack. If A is 1 x 1, then call the subroutine at a1,1.

#### Return

Pneumonic: ret

Opcode: 0x95

Return from subroutine.

### Ternary operator

Pneumonic: if

Opcode: 0x96

Pops three arguments off the stack A, B, and C.

If A, B, and C are logical then the result is the logical [ (ai,j and bi,j) or (not ai,j and ci,j) ].

If A, B, or C are numerical, then the result is the numerical [ ai,j != 0 ? bi,j : ci,j ]

### Memory operators

#### Store

Pneumonic: st

If A is 1 x 1, then write B sequentially starting at a1,1. Otherwise the dimensions of A and B must match.

0x97 Result
Logical Write bi,j to address ai,j.
Numerical Write bi,j to address ai,j.

Pneumonic: ld

0x98 Result
Logical Push matrix whose i,j-th cell is the memory contents of address ai,j.
Numerical Push matrix whose i,j-th cell is the memory contents of address ai,j.

### Miscellaneous operators

The following operators manipulate the stack and control flow.

Encoding Pneumonic Description
0x99 swap Swap top two arguments on the stack.
0x9A drop Pop the stack,
0x9B dup Duplicate the element on top of the stack.
0x9C rot Pop A. If A is n x 1, then rotate the first a1,1 elements of the stack, then rotate the first a2,1 elements of the stack, etc.
0x9D jz Pop A. Pop B. If a is 1 x 1 and B does not contain any non-zero values, then set IP to a1,1.
0x9F X 128, ..., 65535 Push 16-bit immediate value to stack as 1 x 1 logical.
b0xxxxxxx 0, 1, ..., 127 Push 7-bit immediate value xxxxxxx to the stack as 1 x 1 logical.

## Examples

Assuming display is 256 x 256 and mapped to the first 65,536 memory addresses in the normal way.

### Reverse first n elements on stack

``` n count rot
```

3 bytes.

### AND pattern

``` 256                                         ; [ 256 ]
count dup                                   ; [ 1, ..., 256 ], [ 1, ..., 256 ] logical column vectors
trans mul                                   ; [ x and y ]
0 st                                        ; Write [ x and y ] to 0x00000000
```

9 bytes.

### Extract bits from logical

Suppose a 1 x 1 logical x is on the stack.

``` 32 count sign swap cast pmul cast       ; [ x, x, ..., x (32 times) ]
32 count dec cast 2 pow cast            ; [ 1, 2, 4, 8, ..., 2^31 ], [ x, x, ..., x (32 times) ]
and sign                                    ; [ x, x, x, ..., x ]
```

15 bytes.