Rogério Reis


Err and err and err again, but less and less and less.


Assembly Language

Apoo has a set of general purpose registers (16 by default), a data memory area, a program memory area, a system stack and a program counter register.

All memory cells and registers can store integers of non limited size (python long integers).

Registers are named R0,R1,R2,R3,R4,R5,R6,R7,...

Memory Management

The size of the RAM is predefined (e.g. 1K) and divided into two areas: static memory and system stack. The static memory, begins at address 0 and it is allocated when a Apoo program is loaded. Static memory cells can be reserved in in two ways, using the following pseudo-instructions:

Meaning
Label:
mem
n
Reserves n memory addresses
Label:
.
const
const
n1
n2
Contents of memory address Label is n1, of Label+1 is n2. ni can be a character like 'c'.
Label:
equ
n
Allows a symbolic name for a number
Label:
string
"string
Allocates memory addresses and set them to the correspondent characters ASCII codes. The characters cannot be whitespaces: use \s for space, \t for tab and \n for newline.


Label is any string beginning with a letter and containing only letters and digits with the exception of legal register names. If exists, must begin in the first column of a line

NOTE: Every memory address referred, must have been reserved by one of the previous pseudo-instructions. This means that the instruction "load 3 R2", will cause an Out of Memory error, if at least "mem 3" or three const pseudo-instructions were not given... If a "equ" value is used as a memory address, that address must be already reserved or be a known memory-mapped instruction. The string argument must be quoted and is converted to a sequence of ascii codes ending with 0.

System Stack

The system stack occupies the rest of the RAM (growing for higher addresses). Since Apoo version 2.2 it can be used in an advanced way to implement activation records (see section 3.2). However in can be used in a simpler way to implement subroutines. We can only push a value to the Stack and pop a value from it (the one in the top of the Stack). It is used by the instructions jsr and rtn.

It can be manipulated by means of the push and pop instructions.

Versions prior to 2.2 uses the same syntax but diferent graphical interface for the visualization of the System Stack.

Instruction form

[Label:] Operation Operand1 Operand2
Label is any string of letters or digits; if exists, must begin in the first column of a line

Comments

A line beginning with # will be ignored by the parser; so it can be used to write comments of the program

Instruction Set
Command
Operand1
Operand2
Meaning
load
Mem
Ri
Loads the contents of memory address Mem into register Ri; Mem can be a label
loadn
Num
Ri
Loads the number Num into register Ri; Num can be a label
loadi
Ri
Rj
Loads the contents of memory which address is the contents of Ri into Rj (indirect load).
loado
Num
Ri
Loads the contents of memory address (Rf)+Num into register Ri, where Num ins a number.
store
Ri
Mem
Stores the contents of Ri at memory address Mem; Mem can be a label
storer
Ri
Rj
Stores the contents of Ri into Rj
storei
Ri
Rj
Stores the contents of Ri into at memory address, which is the contents of Rj.
storeo
Ri
Num
Stores the contents of register Ri at memory address (Rf)+Num, where Num is a number.
add
Ri
Rj
Adds the contents of register Ri to the contents of register Rj, and stores the result in Rj (Rj=Ri+Rj).
sub
Ri
Rj
Subtracts the contents of register Rj from the contents of register Ri, and stores the result in Rj (Rj=Ri-Rj).
mul
Ri
Rj
Multiplies the contents of register Rj by the contents of register Ri, and stores the result in Rj (Rj=Ri*Rj).
div
Ri
Rj
Divides the contents of register Rj by the contents of register Ri, and stores the result in Rj (Rj=Ri*Rj).
mod
Ri
Rj
Stores in Rj the rest of integer division of contents of register Ri by the contents of register Rj, and stores into Rj (Rj=Ri%Rj)
zero
Ri
The contents of Ri becomes 0 (Ri=0)
inc
Ri
Increments by 1 the contents of Ri
dec
Ri
Decrements by 1 the contents of Ri
jump
Addr
Jumps to instruction address Addr; Addr can be a Label
jzero
Ri
Addr
Jumps to instruction address Addr, if contents of Ri is zero; Addr can be a Label
jpos
Ri
Addr
Jumps to instruction address Addr, if contents of Ri is positive; Addr can be a Label
jneg
Ri
Addr
Jumps to instruction address Addr, if contents of Ri is negative; Addr can be a Label
jnzero
Ri
Addr
Jumps to instruction address Addr, if contents of Ri is different from zero; Addr can be a Label
jsr
Addr
Pushes the PC into the stack and jumps to instruction address Addr
rtn
Pops an address from the stack into the PC
push
Ri
Pushes the contents of Ri into the system stack
pop
Ri
Pops at element from the system stack into Ri
halt
Stops execution; Every program must have this instruction in order to end properly; otherwise an 'Out of Program' error will occur
Memory-mapped instructions

Apoo allows the configuration of a set of memory positions for special purposes. The memory values and its functionality are given as a parameter of the Apoo virtual machine. The default values allow the simulation of input/output:

Memory Position
Load
Store
50000
load 50000 Ri

Loads 0 in Ri
store Ri 50000

Writes the character which ascii code is Ri%256 in the Output Window (in graphical interface) or in stdout, in text mode.
50001
load 50001 Ri

Reads an integer and stores it in Ri
store Ri 50001

Writes the contents of Ri as an integer
50010
load 50010 Ri

Loads 0 in Ri
store Ri 50010

Writes a CR in the Output Window (in graphical interface) or in stdout, in text mode.
Manipulation of activation records in Apoo

This is an extension of the Apoo vpu for dealing with activation records. It is available as version 3.0.

There are two programmable registers to address the system stack: stack register and frame register. They correspond to the last two registers of a Apoo vpu configuration, Rn-1 and Rn-2, but are aliased to rs and rf, respectively. The stack register rs contains the address of the last stack memory cell (or -1 if no static memory is allocated). The instructions jsr, rtn, push and pop manipulates the stack in the usual way. Besides that, the contents of the stack register can be manipulated as any other register.

The frame register can be used for the implementation of local information (on the system stack). It contents should be the first stack address of the current activation record. Like the stack register it can be manipulated as any other register, but it is also used in two special instructions:
storeo and loado.

storeo Ri Num
stores the contents of register Ri at memory address (rf) + Num, where Num is an integer.
loadeo Num Ri
loads the contents of memory address (rf) + Num into register Ri, where Num is an integer.
In both instructions, if Num is non negative it should correspond to local memory and if it is negative, possibly corresponds to arguments of a subroutine call.

Here is an example of the use of these registers, for the implementation of subroutines with arguments (passed on the stack) and local memory.

n: const 5
loadn 4 r1
# an argument
push r1
zero r1
jsr test
pop r1
halt
test: push rf
#saves the current frame pointer
#current frame pointer
storer rs rf
loadn 6 r2
# reserves some local space
add r2 rs
# gets the argument
loado -2 r1
# only testing the rs
push r1
pop r1
#stores contents of r1 at rf+1
storeo r1 1
#loads the same value into r3
loado 1 r3
# restores stack before return
sub rs r2
storer r2 rs
# restores frame before return
pop rf
rtn


A more complete example is:

jsr main
halt

factorial: push rf
storer rs rf
loado -2 r3
loadn 0 r2
sub r3 r2
jnzero r2 L0
loadn 1 r2
storer r2 r0
pop rf
rtn
L0: loado -2 r4
loadn 1 r3
sub r4 r3
push r3
jsr factorial
loadn 1 r3
sub rs r3
storer r3 rs
storer r0 r3
loado -2 r2
mul r3 r2
storer r2 r0
pop rf
rtn
pop rf
rtn

main: push rf
storer rs rf
loadn 2 r2
add r2 rs
load 50001 r1
storeo r1 2
loado 2 r2
push r2
jsr factorial
loadn 1 r2
sub rs r2
storer r2 rs
storeo r0 1
loado 1 r2
store r2 50001
loadn 10 r2
store r2 50000
loadn 2 r2
sub rs r2
storer r2 rs
pop rf
rtn