Dakotah Lambert

dakotahlambert@acm.org

Assistant Professor of Computer Science at Lake Forest College

aster(5)

Name

aster - assembly language for the URSA architecture

Description

An assembly language program consists of a series of statements, one per line. A symbol is a name. Valid symbols consist of one or more characters that are uppercase or lowercase alphabetic symbols (A–Z or a–z), digits (0–9), or the dot (.), underscore (_), or dollar sign ($), where the first character is neither a digit nor a dollar sign. A statement comes in one of the following forms:

symbol = value
A symbol binding assigns the given value to the named symbol. Such a binding is permanent; the value cannot later be changed.
symbol:
A label assigns the current location to the given symbol. Such a binding is permanent; the value cannot later be changed.
[symbol:] directive
The optional symbol specifies a label (see above). A directive is a command to the assembler itself; see the section directives below. A label is not accepted for .macro, .endm, .if, .else, or .endif.
[symbol:] instruction
The optional symbol specifies a label (see above). An instruction is a human-readable name for a unit of machine code. The assembler converts the instruction into its corresponding machine code and places the result in the output file.

A semicolon (;) begins a comment; the remainder of the line is human-readable text that is not interpreted by the assembler. Blank lines are ignored.

The URSA architecture has sixteen 32-bit general purpose registers, numbered r0 through r15. Registers r10 through r15 have hexadecimal aliases ra through rf. Certain registers have conventional uses and have alternate names to reflect these uses: register r11 is the temporary register known as rT, register r12 is the frame pointer known as fp, register r13 is the stack pointer known as sp, register r14 is the return pointer known as rp, and register r15 is the program counter known as pc. Additionally, there is one special-purpose register: the status register known as sr. Each of these names is case-insensitive. Register names are reserved; labels and symbols cannot use these names.

Value Expressions

A value expression consists of numbers, symbols, and operations and is used anywhere a value is required. Value expressions are internally calculated at 64-bit precision, to detect some range errors. An absolute expression is a value expression that the assembler can evaluate as a concrete numerical value using the information that it has already processed.

Numbers can be supplied in decimal (no prefix, digits 0–9), hexadecimal (0x prefix, digits 0–9 and a–f, case-insensitive), or binary (0b prefix, digits 0 and 1) format and evaluate to their numerical value. They may contain spaces for grouping. A character or escape sequence in single-quotes, like 'A', evaluates to its ASCII value. Symbols are specified by name and evaluate to their final address. The special symbol “.” refers to the current location in the current segment.

Unary operations apply first: negation (-value), bitwise complement (~value), and application of functions. The following functions are available.

defined(symbol)
Evaluates to one if the symbol has already been defined by a label or symbol binding statement, otherwise to zero.
g0(value), g1(value), g2(value), g3(value)
Only for the sset instruction (see instructions below). Returns the given value unchanged, with a flag indicating which group of 8 bits should be used in the instruction: bits 0–7 for g0, bits 8–15 for g1, bits 16–23 for g2, and bits 24–31 for g3.
isreg(argument)
Returns one if the supplied argument is a register, or zero otherwise. This can be useful in macros.
len(argument)
Returns the length of the given argument, which must be a quoted string.
regnum(argument)
If the supplied argument is a register, returns its canonical number from 0–15. It is an error to supply an argument that is not a register.
value(value)
Returns the given value unchanged. For use with macro parameters, which cannot otherwise be used in expressions.

Binary operators are as follows, listed in order of decreasing precedence. Within a given level, chains of operators act left to right. Comparisons cannot be chained. They return either one (true) or zero (false).

  1. Multiplication and Division
    • value * value (multiplication)
    • value / value (division, rounded toward zero)
    • value % value (remainder)
  2. Addition and Subtraction
    • value + value (addition)
    • value - value (subtraction)
  3. Shifting
    • value << value (left shift)
    • value >> value (right shift)
  4. Multiplication-Like Bitwise Parallel Logic
    • value & value (AND)
  5. Addition-Like Bitwise Parallel Logic
    • value | value (OR, inclusive)
    • value ^ value (XOR, exclusive)
  6. Comparisons
    • value < value (less than)
    • value <= value (less than or equal to)
    • value = value (equal to)
    • value <> value (not equal to)
    • value >= value (greater than or equal to)
    • value > value (greater than)

Directives

This section lists assembler directives alphabetically.

.ascii "string"
Directly emit the specified string at the current location. Characters are stored in order with the first character having the lowest address, and the last character having the highest address. This string is not implicitly null-terminated.
.asciz "string"
Directly emit the specified string at the current location, followed by a zero byte. Characters are stored in order with the first character having the lowest address, and the last character having the highest address. The following zero byte ensures that the string is null-terminated.
.byte value [, value]…
Directly emit the specified values, in order, at the current location. Each may be a signed byte, ranging from −128 through +127, or an unsigned byte, ranging from 0 through 255.
.data
Enter the data memory segment. Subsequent statements and directives will be directed to data memory, until the segment is changed again.
.else
If the associated .if directive’s test passed, then skip to its .endif directive. Otherwise, continue processing the following statements as normal. It is an error to use .else outside of .if structure.
.endif
Finalize the conditional processing started by an .if directive. It is an error to use .endif without a corresponding .if directive.
.endm
Finalize the macro definition started by a .macro directive. It is an error to use .endm without a corresponding .macro directive.
.error ["string"]
Abort processing with an error message. If the optional string is given, it is used as the message.
.function
When the next label is reached or when the next symbol is bound, whichever comes first, mark the associated content as a function in the output file. This is mainly useful for external tools.
.global symbol
Mark the given symbol as a global symbol in the output file if it is defined. This allows other object files to see its value when linked with this output file, as by the starlink(1) static link editor.
.hword value [, value]…
Directly emit the specified values, in order, at the current location in little-endian order. Each may be a signed 16-bit halfword, ranging from −32,768 through +32,767, or an unsigned 16-bit halfword, ranging from 0 through 65,535.
.if value
An absolute expression is required for the value. Test whether it is nonzero. If it is nonzero, then continue processing the following statements as normal. Otherwise, skip to the associated .else directive if there is one, or to the associated .endif directive if not. It is an error to use .if without a corresponding .endif directive.
.include "file"
Read the specified file and process its contents in place of this directive. If the file does not exist in the directory where aster(1) was run, the directories specified in the search path by any -I options are searched in turn until a file with the given name is found. If it cannot be found in any of the searched directories, then processing terminates with an error message.
.macro symbol
Define a new pseudoinstruction with the given symbol as its name. The definition consists of all following statements until the corresponding .endm directive, which must appear later in the program. The new instruction can take as many parameters as desired; they are accessible as #1, #2, and so on within the body of the definition. They can appear as an argument in any argument list; to use them in expressions, use the value function.
.object
When the next label is reached or when the next symbol is bound, whichever comes first, mark the associated content as a data object in the output file. This is mainly useful for external tools.
.p2align alignment
Emit bytes with value zero until at a location in the current segment whose address has trailing zero bits numbering at least the specified alignment. In other words, ensure that the next statement has a multiple of 2alignment as its location. Valid values for alignment are 0 through 12, inclusive. The alignment must be an absolute expression.
.size symbol, value
Set the size of the given symbol to the given value in the output file. The symbol must have already been defined, either by a label or by a symbol binding, and the given value must be an absolute expression. This is mainly useful for external tools.
.text
Enter the instruction memory segment. Until the segment is changed again, subsequent statements and directives are directed to instruction memory.
.warning ["string"]
Report a warning, but continue processing. If the optional string is supplied, it is used as the warning message.
.word value [, value]…
Directly emit the specified values, in order, at the current location in little-endian order. Each may be a signed 32-bit word, with value ranging from −2,147,483,648 through +2,147,483,647, or an unsigned word, from 0 through 4,294,967,296.

Instructions

This section describes the instruction set of the URSA architecture in terms of its assembly language.

Conditions

Some instructions, namely movcond and bcond, are conditionally executed based on the state of the flags in the status register. The four flags are carry (C), overflow (V), negative (N), and zero (Z). Generally, C means that the result is incorrect under an unsigned interpretation, V means that the result is incorrect under a signed interpretation, N means that the sign bit of the result is set, and Z means that all bits of the result are clear.

A common application is to inspect the state of the flags after executing an instruction like “sub register, operand”, so many condition codes are named for how the register compares to the operand in such a context. In the conditional instructions bcond and movcond, the cond field may be omitted, in which case the instruction executes unconditionally, or it may be f, in which case the instruction never executes, or it may be any of the following.

cc: Carry is clear [synonym hs]
!C
cs: Carry is set [synonym lo]
C
eq: Equal [synonym z]
Z
ge: Signed greater than or equal to
!(N xor V)
gt: Signed greater than
!((N xor V) or Z)
hi: Unsigned greater than (“higher”)
!C and !Z
hs: Unsigned greater than or equal to (“higher or same”) [synonym cc]
!C
le: Signed less than or equal to
(N xor V) or Z
lo: Unsigned less than (“lower”) [synonym cs]
C
ls: Unsigned less than or equal to (“lower or same”)
C or Z
lt: Signed less than
N xor V
mi: Negative (“minus”)
N
ne: Not equal [synonym nz]
!Z
nz: Nonzero [synonym ne]
!Z
pl: Nonnegative (“plus”)
!N
vc: Overflow is clear
!V
vs: Overflow is set
V
z: Zero [synonym eq]
Z

Instruction Overview

Instructions can be divided into the following groups. Aside from the special case of “mov sr, register”, which directly manipulates the status register, only the first group affects condition flags.

Flag-Affecting Arithmetic and Logic
addsclrslsrssubs
adxsiorsrlcssbxs
andslslsrrcsxors
asrs
Flag-Preserving Arithmetic and Logic
addasrlslsbx
adxclrlsrxor
andiorsub
Memory Interaction
ldldbstostob
Non-Memory Value Assignment
movcondsset
Control Flow
bcond

Instruction Reference

This section contains an alphabetical listing of URSA instructions. Each instruction begins with a synopsis of its syntax, which is followed by the full name of the instruction, a description of its effects, and finally a brief description of how it affects the flags in the status register. The carry (C), overflow (V), negative (N), and zero (Z) flags are given in the order CVNZ, and the effect is given by a single character:

0
The flag is always cleared.
The flag is unchanged.
C, V, N, Z
The flag is set according to the operation result.

In the following descriptions, a “shifted nibble” is a value that can be written as a hexadecimal number using only one nonzero character after the 0x prefix, such as 0x0f000000 or 0x00000400, but not, say, 0x0f000400, as that contains two nonzero characters. When “register” is used unqualified, it refers to one of the sixteen general-purpose registers.

add[s] register, value
“ADD”
Add the given value to the contents of the given register and store the result back into the given register. The value must be a register or a shifted nibble.
add – – – – / adds C V N Z
adx[s] register, value
“ADD EXTENDED”
Add the given value and the contents of the carry flag to the contents of the given register and store the result back into the given register. The value must be a register or a shifted nibble.
adx – – – – / adxs C V N Z
and[s] register, value
“BITWISE PARALLEL LOGICAL AND”
For each bit position, compute the logical AND of the associated bit in the given value with the associated bit in the given register and store the result back into the given register. This clears any bits that are cleared in the value. The value must be a register or a shifted nibble.
and – – – – / ands 0 0 N Z
asr[s] register, value
“ARITHMETIC SHIFT RIGHT”
Shift the contents of the given register to the right as many times as indicated by the given value, which must be a register or a number between 0 and 31, inclusive. The register is treated as a signed value: if the sign bit was originally set, then it is set after the operation completes as well. This is equivalent to dividing by two that number of times, rounding toward minus infinity. The carry flag of the result is set if any set bit is shifted out.
asr – – – – / asrs C 0 N Z
bcond symbol
“(CONDITIONAL BRANCH)”
If the given condition cond is satisfied, transfer program execution to the named symbol, which must evaluate to a location within instruction memory. That is, it must be defined by a label in the .text segment of this file or that of another file that will be linked with the resulting object.
– – – –
clr[s] register, value
“CLEAR BITS”
For each bit set in the given value, clear the bit in the corresponding position of the given register. This computes the bitwise parallel logical AND of the given register and the complement of the given value. This value must be either a register or a shifted nibble.
clr – – – – / clrs 0 0 N Z
ior[s] register, value
“BITWISE PARALLEL LOGICAL OR”
For each bit position, compute the logical inclusive-OR of the associated bit in the given value with the associated bit in the given register and store the result back into the given register. This sets any bits that are set in the value. The value must be a register or a shifted nibble.
ior – – – – / iors 0 0 N Z
ld register, [register[, value]]
“LOAD WORD”
Fetch the 32-bit word from the memory address specified by adding the given value to the contents of the second register, and place the result into the first register. The offset value must be a multiple of four between 0 and 28, inclusive. If not specified, zero is used. The final computed address must also be a multiple of four.
– – – –
ldb register, [register[, value]]
“LOAD BYTE”
Fetch the signed 8-bit byte from the memory address specified by adding the given value to the contents of the second register, and place the result into the first register. The result is sign-extended to fill the entire 32-bit destination register. The offset value must be between 0 and 7, inclusive. If not specified, zero is used.
– – – –
lsl[s] register, value
“LOGICAL SHIFT LEFT”
Shift the contents of the given register to the left as many times as indicated by the given value, which must be a register or a number between 0 and 31, inclusive. The low bits shifted in are filled with zero. The register is treated as an unsigned value. This is equivalent to multiplying by two that number of times. The carry flag of the result is set if any set bit is shifted out.
lsl – – – – / lsls C 0 N Z
lsr[s] register, value
“LOGICAL SHIFT RIGHT”
Shift the contents of the given register to the right as many times as indicated by the given value, which must be a register or a number between 0 and 31, inclusive. The high bits shifted in are filled with zero. The register is treated as an unsigned value: if the shift amount is nonzero, then the sign bit is unset in the result. This is equivalent to dividing by two that number of times, rounding down. The carry flag of the result is set if any set bit is shifted out.
lsr – – – – / lsrs C 0 N Z
movcond register, register
“MOVE”
Copy the value from the second, source register into the first, destination register, if the given condition cond is satisfied. Otherwise, do nothing. Either the source or the destination (but not both) may be the status register sr; in this case, the condition cond must be omitted and the instruction executes unconditionally.
– – – –
rlcs register
“ROTATE LEFT THROUGH CARRY”
Shift the bits of the given register one position upward. The most-significant bit that is shifted out is placed into the carry flag, and the original carry flag is shifted into the newly open least-significant position.
C 0 N Z
rrcs register
“ROTATE RIGHT THROUGH CARRY”
Shift the bits of the given register one position downward. The least-significant bit that is shifted out is placed into the carry flag, and the original carry flag is shifted into the newly open most-significant position.
C 0 N Z
sbx[s] register, value
“SUBTRACT EXTENDED”
Subtract the given value and the contents of the carry (“borrow”) flag from the contents of the given register and store the result back into the given register. The value must be a register or a shifted nibble.
sbx – – – – / sbxs C V N Z
sset register, value
“SHIFT AND SET”
Shift bits 0–23 of the given register up to positions 8–31 and fill the newly open least-significant byte with the given value. This value must be a number from 0 through 255, inclusive. To specify larger numbers, or negative signed values, use the g0, g1, g2, and g3 functions, which extract specific bit ranges to fit this criterion.
– – – –
sto [register[, value]], register
“STORE WORD”
Store the 32-bit contents of the second register into the memory address specified by adding the given value to the contents of the first register. The offset value must be a multiple of four between 0 and 28, inclusive. If not supplied, zero is used. The final computed address must also be a multiple of four.
– – – –
stob [register[, value]], register
“STORE BYTE”
Store the least-significant 8-bit byte of the second register into the memory address specified by adding the given value to the contents of the first register. The offset value must be between 0 and 7, inclusive. No other bytes in memory are affected.
– – – –
sub[s] register, value
“SUBTRACT”
Subtract the given value from the contents of the given register and store the result back into the given register. The value must be a register or a shifted nibble.
sub – – – – / subs C V N Z
xor[s] register, value
“BITWISE PARALLEL LOGICAL XOR”
For each bit position, compute the logical exclusive-OR of the associated bit in the given value with the associated bit in the given register and store the result back into the given register. This toggles any bits that are set in the value. The value must be a register or a shifted nibble.
xor – – – – / xors 0 0 N Z

Examples

Compute into register r0 the sum of the natural numbers from 1 through 256, inclusive (resulting in 0x8080).

.text
.p2align 1
.global main
.function
main:
    xor  r0, r0
    sset r1, g3(input)
    sset r1, g2(input)
    sset r1, g1(input)
    sset r1, g0(input)
    ld   r1, [r1]
main.loop:
    add  r0, r1
    subs r1, 1
    bnz  main.loop
.size main, . - main
    b    .
.data
.p2align 2
.object
input: .word 0x100
.size input, . - input

See Also

aster(1), starlink(1)