Primer

This is a short description of some of the registers used while programming in saturn assembly.

Data pointers

D0: Instruction pointer.
D1: Stack pointer.

Working registers

A: Can be used freely.
B: Pointer to top of return stack.
C: Can be used freely.
D: Amount of free memory between return stack and stack.

Scratch registers

R0, R1, R2, R3, R4: Used to temporarily store data, addresses etc.

Others

P: Pointer used to point into C and for loops. I must add one thing about this register. Its value determines where loading instructions start their loading. For example, if P=15 then loading A or C will load that value into field S (see below for architecture). P must be 0 when exiting your program!
IN: Input, used in keyscanning.
OUT: Output, used to generate tones and in keyscanning.
ST: Status bits. The lower 12 can be freely used while the upper four are used by the operating system.
Return stack: An 8-level stack used to temporarily hold addresses. Note that you must never use more than 6 levels as the top 2 are used by the interrupt system.

Example usage

Your first program

When you start programming in ml you need to make sure you restore the rpl pointers when the program finishes. You can either save them at the beginning and restore them at the end. The most common entries to do this are:
=SAVPTR		save the pointers
=GETPTRLOOP	restore them and continue with rpl
You could also however, decide not to use B[A], D[A], D0, and D1 (or restore them yourself). Then you would exit similar to this (we save D1 to show an example):
	CD1EX		swap D1 and C[A]
	RSTK=C		save D1 on returnstack
	.
	.
	.
	C=RSTK		retrieve D1 from return stack
	D1=C		restore D1 from C[A]
* continue with rpl
	D0=D0+	5	point to next instruction
	A=DAT0	A	read it into A[A]
	PC=(A)		execute next instruction
You could also exit with a command of your choice:
	LC(5)	=UNCOERCE
	A=C	A
	PC=(A)
Also remember to ensure P=0 and cpu is in HEXMODE.

The working registers

The Arhitecture of A, B, C, and D
15
14
13
12
11
10
9
8
7
6
5
4
3
2
1
0
W
S
M
X
 
A
 
XS
B

A, B, C, and D are structured this way. A[A] means field A of A while D[S] means field S of D. C[P] specifies the nibble pointed to by P. I.e. if P=15 then C[P] is equal to C[S]. A=A+A WP doubles the values in register A from nibbles 0 to P.

Reading data

To point D0 at the screen for example, use the supported entry =D0->Row1. Now you can read from the screen and/or write to the screen: reading 5 nibbles:
	GOSBVL	=D0->Row1	point D0 to top-left corner of currently displayed grob
	C=DAT0	A		read 5 nibbles
writing 5 nibbles:
	GOSBVL	=D0->Row1
	LC(5)	#FFFFF		load C with 5*4 pixels (#Fh = #1111b)
	DAT0=C	A
Observe that by doing D0=D0+ 1 you advance the pointer in this case by four pixels, a nibble. Since the screen is 34 nibbles wide, you can move down one row by executing:
	D0=D0+	16
	D0=D0+	16
	D0=D0+	2
Say for example, that you want to turn on the pixel at coordinate { # 65d # 32d }, then you could go about it like this:

CODE	GOSBVL	=SAVPTR		save rpl pointers
	GOSBVL	=D0->Row1	point D0 to top-left corner of display
	LC(5)	34*32+16	32 rows down, 16*4 pixels to the right
	AD0EX			swap A[A] with D0 (actually you don't need to swap here, see with DB)
	A=A+C	A		add offset
	AD0EX			swap back
	LC(5)	#2		#2h = #0010b
	DAT0=C	1		write one nibble
* note: since data is written "backwards", the second pixel in the nibble will be lit: 0*00 (0-off, *-lit)
	GOVLNG	=GETPTRLOOP	restore rpl pointers and continue rpl
ENDCODE
Assemble it, put it on stack level 2 and run << CLLCD EVAL 7 FREEZE >>

Accessing the stack

Dropping an object:
	D1=D1+	5	advance stack pointer to next level
	D=D+1	A	increment available memory
Dropping is easy and can be done quite fast. Dropping several objects:
CODE
	P=	16-5	drop five objects
loop	D1=D1+	5	drop it
	D=D+1	A
	P=P+1		add one to the counter
	GONC	loop	loop until done
	D0=D0+	5
	A=DAT0	A
	PC=(A)
ENDCODE
I let P=11 and then count up to 16. When P=15 and I add once more, P wraps around to 0 and the carry flag is set, the loop is done.

Reading another pointer, D[A], amount of available addresses:

CODE
	GOSBVL	=SAVPTR		save pointers
	C=D	A		multiply available memory by five
	C=C+C	A
	C=C+C	A
	C=C+D	A
	CSRB.F	A		divide number by two
	R0=C.F	A		prepare to push number
	GOSBVL	=PUSH#		push it to the stack, restore pointers
	LC(5)	=UNCOERCE	exit, converting the "bint" to a float
	A=C	A
	PC=(A)
ENDCODE
Since an address is five nibbles we multiply by five, and we want the answer in bytes, thus we divide by two. CSRB.F A shifts register C field A right one bit, effectively dividing its contents by two.

The program counter (PC)

This counter contains the address of the current instruction being executed. The simple example here calculates the address of itself and puts itself on the stack. Remember the stack is only a pile of pointers, not the objects themself. See the glossary for help in understanding how objects are structured.
CODE
	A=PC		read the program counter into A[A]
	LC(5)	14	load C[A] with the amount to subtract
	A=A-C	A	A[A] now contains the prolog of the code object
	GOVLNG	=PUSHA	push it to the stack
ENDCODE
Example programs greatly appreciated!