MAL assembly language statements are either instructions or directives. Instructions are usually MIPS machine instructions specifying program runtime actions. Some instructions are pseudoinstructions; they translate to a sequence of two or more MIPS instructions. Directives are instructions to the assembler, specifying an action to be taken during assembly. One important use of directives is declaring or reserving memory variables.
Instructions and directives both have the following form:
label operation operand_list # comment
The label should be a string of alphabetic and numeric characters, either upper or lower case. The assembler does distinguish between upper and lower case. When used as a line label, the label should be followed by a colon. When it appears in an operand, the colon should be omitted. When a label is not used, the line should begin with a space or tab character.
A label can appear on a line by itself, but this should only be used for instruction labels. The assembler cannot handle variable declarations properly if the label is on a different line.
| Directive | Operand Syntax | Meaning |
|---|---|---|
| .data | none | Start a data declaration section |
| .text | none | Start an instruction section |
| .byte | character [ : non-negative integer ] | Declare a character or byte variable |
| .word | integer [ : non-negative integer ] | Declare a C int variable |
| .float | real number [ : non-negative integer ] | Declare a C float variable |
| .double | real number [ : non-negative integer ] | Declare a C double variable |
| .asciiz | string | Declare a string variable |
| .space | non-negative integer | Reserve memory space |
Usually, a .data section only contains data declarations and
a .text section only contains machine instructions.
A MAL program can have multiple .data and .text
sections.
An assembler groups all of the .data sections together in
memory and groups all of the .text sections together in a
different place in memory.
The first operand for .byte, .word, or
.float specifies the initial value for the variable.
The second operand specifies the number of repetitions.
The second operand is optional.
The operand for .space specifies the number of bytes reserved.
The following symbols are used in the MAL Machine Instructions table below to indicate what is needed for a machine instruction operand. These symbols are sometimes subscripted to distinguish between two source operands or between source and destination operands.
| Operand symbol | Meaning |
|---|---|
| label | an instruction label |
| addr | a memory address (see next table) |
| const | a constant |
| R | a general purpose register |
| Rc | a general purpose register or a constant |
| F | a floating point register |
| Fc | a floating point register or a constant |
| C | a control register |
Constants must be integers except for float (.s suffix) or
double (.d suffix) instructions.
The following modes can be used for memory addresses.
| Mode | MAL Notation | Meaning |
|---|---|---|
| direct | label | Operand address is address assigned to label |
| register direct | (R) | Operand address is contents of register R |
| base displacement | const(R) | Operand address is contents of register R + const |
In this table, R must be a general purpose register and
const must be an integer constant.
The MIPS architecture has three sets of registers:
See MAL Register Usage Conventions for information on the use of registers.
Keep in mind the following points when using MAL machine instructions.
add for integers and
add.s for float numbers.
li, li.s and
li.d) are used to load registers with constant values.
In the table below, the subscript d indicates a destination
operand and subscripts s, s1, and s2
indicate source operands.
For the jr and jalr instructions, the subscript
targ indicates a register that contains the target address of
the jump.
For the jalr instruction the subscript save
indicates a register that receives the return address of the jump.
MAL has the following types of instructions:
| Load Instructions | ||
| Instruction | Operation | |
|---|---|---|
| la | Rd, label | load address |
| lb | Rd, addr | load byte sign extended |
| lbu | Rd, addr | load byte zero extended |
| lh | Rd, addr | load halfword sign extended |
| lhu | Rd, addr | load halfword zero extended |
| li | Rd, const | load immediate |
| li.d | Fd, const | load double immediate |
| li.s | Fd, const | load float immediate |
| lw | Rd, addr | load word |
| l.d | Fd, addr | load double |
| l.s | Fd, addr | load float |
| Store Instructions | ||
| Instruction | Operation | |
| sb | Rs, addr | store byte |
| sh | Rs, addr | store halfword |
| sw | Rs, addr | store word |
| s.d | Fs, addr | store double |
| s.s | Fs, addr | store float |
| Move and Convert Instructions | ||
| Instruction | Operation | |
| cvt.d.s | Fd, Fs | convert float to double |
| cvt.d.w | Fd, Rs | convert integer to double |
| cvt.s.d | Fd, Fs | convert double to float |
| cvt.s.w | Fd, Rs | convert integer to float |
| cvt.w.d | Rd, Fs | convert double to integer |
| cvt.w.s | Rd, Fs | convert float to integer |
| mfc0 | Rd, Cs | load from control register |
| mfc1 | Rd, Fs | load from floating point register |
| move | Rd, Rs | move integer data |
| move.d | Fd, Fs | move double |
| move.s | Fd, Fs | move float |
| mtc0 | Rs, Cd | store to control register |
| mtc1 | Rs, Fd | store to floating point register |
| Arithmetic Instructions | ||
| Instruction | Operation | |
| abs.d | Rd, Rs | absolute value double |
| abs.s | Rd, Rs | absolute value float |
| add | Rd, Rs1, Rcs2 | add int |
| add.d | Fd, Fs1, Fcs2 | add double |
| add.s | Fd, Fs1, Fcs2 | add float |
| div | Rd, Rs1, Rcs2 | divide int |
| div.d | Fd, Fs1, Fcs2 | divide double |
| div.s | Fd, Fs1, Fcs2 | divide float |
| mul | Rd, Rs1, Rcs2 | multiply int |
| mul.d | Fd, Fs1, Fcs2 | multiply double |
| mul.s | Fd, Fs1, Fcs2 | multiply float |
| neg | Rd, Rs | negate int (with overflow) |
| negu | Rd, Rs | negate int (without overflow) |
| neg.d | Fd, Fs | negate double |
| neg.s | Fd, Fs | negate float |
| rem | Rd, Rs1, Rcs2 | divide int (Rd = remainder) |
| sub | Rd, Rs1, Rcs2 | subtract int |
| sub.d | Fd, Fs1, Fcs2 | subtract double |
| sub.s | Fd, Fs1, Fcs2 | subtract float |
| Logic and Shift Instructions | ||
| Instruction | Operation | |
| and | Rd, Rs1, Rcs2 | bitwise and |
| nand | Rd, Rs1, Rcs2 | bitwise nand |
| nor | Rd, Rs1, Rcs2 | bitwise nor |
| not | Rd, Rs | bitwise not |
| or | Rd, Rs1, Rcs2 | bitwise or |
| rol | Rd, Rs1, Rcs2 | left rotate (Rcs2 is shift amount) |
| ror | Rd, Rs1, Rcs2 | right rotate (Rcs2 is shift amount) |
| sll | Rd, Rs1, Rcs2 | left shift (Rcs2 is shift amount) |
| sra | Rd, Rs1, Rcs2 | arithmetic (sign extended) right shift (Rcs2 is shift amount) |
| srl | Rd, Rs1, Rcs2 | logical (zero extended) right shift (Rcs2 is shift amount) |
| xor | Rd, Rs1, Rcs2 | bitwise exclusive or |
| Integer Compare Instructions | ||
| Instruction | Operation | |
| seq | Rd, Rs1, Rcs2 | set true if equal |
| sge | Rd, Rs1, Rcs2 | set true if greater or equal |
| sgeu | Rd, Rs1, Rcs2 | set true if greater or equal unsigned |
| sgt | Rd, Rs1, Rcs2 | set true if greater than |
| sgtu | Rd, Rs1, Rcs2 | set true if greater than unsigned |
| sle | Rd, Rs1, Rcs2 | set true if less or equal |
| sleu | Rd, Rs1, Rcs2 | set true if less or equal unsigned |
| slt | Rd, Rs1, Rcs2 | set true if less than |
| sltu | Rd, Rs1, Rcs2 | set true if less than unsigned |
| sne | Rd, Rs1, Rcs2 | set true if not equal |
| Floating Point Compare Instructions | ||
| Instruction | Operation | |
| c.eq.d | Fs1, Fs2 | set floating point coprocessor flag true if equal double |
| c.eq.s | Fs1, Fs2 | set floating point coprocessor flag true if equal float |
| c.ge.d | Fs1, Fs2 | set floating point coprocessor flag true if greater or equal double |
| c.ge.s | Fs1, Fs2 | set floating point coprocessor flag true if greater or equal float |
| c.gt.d | Fs1, Fs2 | set floating point coprocessor flag true if greater than double |
| c.gt.s | Fs1, Fs2 | set floating point coprocessor flag true if greater than float |
| c.le.d | Fs1, Fs2 | set floating point coprocessor flag true if less or equal double |
| c.le.s | Fs1, Fs2 | set floating point coprocessor flag true if less or equal float |
| c.lt.d | Fs1, Fs2 | set floating point coprocessor flag true if less than double |
| c.lt.s | Fs1, Fs2 | set floating point coprocessor flag true if less than float |
| c.ne.d | Fs1, Fs2 | set floating point coprocessor flag true if not equal double |
| c.ne.s | Fs1, Fs2 | set floating point coprocessor flag true if not equal float |
| Branch Instructions | ||
| Instruction | Operation | |
| b | label | unconditional branch |
| bc1t | label | branch if the floating point coprocessor flag is true |
| bc1f | label | branch if the floating point coprocessor flag is false |
| beq | Rs1, Rcs2, label | branch if equal |
| beqz | Rs, label | branch if equal 0 |
| ble | Rs1, Rcs2, label | branch if less than or equal |
| bleu | Rs1, Rcs2, label | branch if less than or equal unsigned |
| blez | Rs, label | branch if less than or equal 0 |
| blt | Rs1, Rcs2, label | branch if less than |
| bltu | Rs1, Rcs2, label | branch if less than unsigned |
| bltz | Rs, label | branch if less than 0 |
| bltzal | Rs, label | branch if less than 0 and link |
| bge | Rs1, Rcs2, label | branch if greater than or equal |
| bgeu | Rs1, Rcs2, label | branch if greater than or equal unsigned |
| bgez | Rs, label | branch if greater than or equal 0 |
| bgezal | Rs, label | branch if greater than or equal 0 and link |
| bgt | Rs1, Rcs2, label | branch if greater than |
| bgtu | Rs1, Rcs2, label | branch if greater than unsigned |
| bgtz | Rs, label | branch if greater than 0 |
| bne | Rs1, Rcs2, label | branch if not equal |
| bnez | Rs, label | branch if not equal 0 |
| Jump Instructions | ||
| Instruction | Operation | |
| j | addr | unconditional jump |
| jr | Rtarg | unconditional jump (return if Rtarg = $ra) |
| jal | addr | subprogram call |
| jalr | Rsave, Rtarg | subprogram call; first operand is optional (default $ra) |
| System Call Instruction | ||
| Instruction | Operation | |
| syscall | call on operating system services | |
The MIPS processor supports a large number of operating system calls with a
single syscall instruction.
This is accomplished by using the register $v0 to indicate the particular
operating system service that is needed.
Thus all system calls have at least the following code.
li $v0, system call code syscallAn additional instruction or two may be needed before the syscall instruction to set up parameters for the system call. These instructions will load registers with the required parameters. Some system calls will return a value in a register. The table below shows the system call codes, parameters, and return values for the MAL system calls.
| Service | Code | Parameters | Return Values |
|---|---|---|---|
| print_int | 1 | integer ($a0) | |
| print_float | 2 | float ($f12) | |
| print_double | 3 | double ($f12) | |
| print_string | 4 | string address ($a0) | |
| read_int | 5 | integer ($v0) | |
| read_float | 6 | float ($f0) | |
| read_double | 7 | double ($f0) | |
| read_string | 8 | buffer address ($a0), length ($a1) | |
| sbrk | 9 | number of bytes ($a0) | address of block ($v0) |
| exit | 10 |