A1

A1 is a saucy esoteric RISC architecture discovered by User:Orby in April of 2017.
==Purpose==
The purpose of A1 is to provide an minimal architecture that has reasonable code density. The
instruction set should be small, but programs should not be unnecessarily large. A1
is a RAM machine with eight registers and three commands: Push (PSH), Pop (POP) and
Subtract If Zero Flag Is Set (SUBZF). This lifts it out of the OISC category, but it
remains simple enough to be called minimal IMHO.
The bit width of each register is implementation defined, and thus so is the amount of RAM
that can be addressed. It is recommended to refer to n-bit A1 as A1xn (e.g. A1x32, A1x64, etc.)
The most commonly used A1 opcodes are only one or two bytes in size. This is in
contrast to the majority of OISCs. ByteByteJump for example, requires 12 bytes per
instruction to address the same amount of RAM. A1 does not require self-modifying code
to achieve TC, so in theory optimizing VMs are possible. This also makes it easier to
write A1 assembly code.
==Registers==
A1 has eight n-bit registers. The A, B, C, X, and Y registers are general purpose. The
IP register is the instruction pointer which is equal to the address of the next instruction 
to execute. The SP register is the stack pointer. The ZF register is the zero flag and is
used by the SUBZF instruction. All registers may be accessed directly or indirectly.
An rvalue is a 4-bit value that encodes a direct or indirect register reference. They
map in the following way
 $0 A $8 [A]
 $1 B $9 [B]
 $2 C $A [C]
 $3 X $B [X]
 $4 Y $C [Y]
 $5 ZF $D [ZF]
 $6 SP $E [SP]
 $7 IP $F [IP]
where [x] denotes a the value at the memory address pointed to by x.
==Instructions==
A1 supports five opcodes which each execute in a single clock cycle (x represents an rvalue):
 Hex Assembly Name
 00 imm8 PSH imm8 Push (8-bit immediate value)
 10 imm-n PSH imm-n Push (n-bit immediate value)
 2x PSH x Push (Register)
 3x POP x Pop
 40 SUBZF Subtract if ZF is set
All other opcodes produce undefined results.
===Push===
Push an immediate value or a register onto the stack. That is,
 SP := SP - n/8
 [SP] := x
The 8 bit immediate version sign extends the immediate value. ZF is unaffected.
===Pop===
Pop an immediate value directly to a register or to the address a register references.
That is, 
 x := [SP]
 SP := SP + n/8
ZF is unaffected.
===Subtract If Zero===
Pop two values off the stack. Subtract the first value from the second value. If
ZF is non-zero, then push the difference onto the stack and set ZF to the difference.
If ZF is zero, then push the second value onto the stack and leave ZF alone.
==Examples==
All examples assume ZF is non-zero and n = 32. Here is an infinite loop in 5 bytes
 push ip
 push 1
 subzf
 pop ip
Set A := A + B in 7 bytes
 psh a
 psh 0
 psh b
 subzf
 subzf
 pop a
Function calls are simple. Here is an example in 12 bytes
 
 psh Resume
 psh MyFunc
 pop ip
 Resume:
 ; More code here
 
 MyFunc:
 ; Do my function
 pop ip
 
Here is an example which counts backward from 100 (19 bytes)
 psh 100
 loop:
 
 ; Do stuff here
 
 ; Decrement
 psh 1
 subzf
 
 ; If zf != 0 then jump to loop, otherwise jump to end
 psh end-loop
 psh end
 subzf
 pop ip
 end:
==External resources==
* A1 Implementation a Verilog implementation of A1
==See also==
* Teriyaki an esoteric VDP to use in conjunction with A1
* OISC
* Subleq
* ByteByteJump
Category:Low-level 
Category:2017
Category:Implemented
Category:Stack-based
Category:Languages