# syscall in the Playground

[Courses](https://asm-editor.specy.app/learn/courses.md) › [MIPS assembly](https://asm-editor.specy.app/learn/courses/mips.md) › Talking to the outside world

Web page: https://asm-editor.specy.app/learn/courses/mips/talking-to-the-outside-world/syscall

> Use the Playground's MIPS syscall services to print and read values, preserve returned results and end a program.

Overview of this topic: [Assembly basics](https://asm-editor.specy.app/learn/courses/assembly-basics/talking-to-the-outside-world/system-calls-and-traps.md)

The same topic in: [M68K](https://asm-editor.specy.app/learn/courses/m68k/talking-to-the-outside-world/trap-15-and-its-tasks.md), [RISC-V](https://asm-editor.specy.app/learn/courses/risc-v/talking-to-the-outside-world/ecall.md), [Z80](https://asm-editor.specy.app/learn/courses/z80/talking-to-the-outside-world/ports-in-and-out.md), [x86-64](https://asm-editor.specy.app/learn/courses/x86/talking-to-the-outside-world/syscall-and-the-linux-abi.md)

Until now, a program's result has stayed in a register or in memory. To show text in the console,
read what someone types or end a run, a program asks the Playground to perform a **service**. The
instruction that makes the request is `syscall`.

## Choose a service, then call it

In this Playground, we write `syscall` with no operands. Each request follows the same pattern:

1. put the service number in `$v0`;
2. put the service's inputs in the registers listed for that service;
3. execute `syscall`.

These five services are enough for the examples and exercises on this page:

| service | action                         | input             | result |
| ------: | ------------------------------ | ----------------- | ------ |
|       1 | print a signed integer         | value in `$a0`    | —      |
|       4 | print a zero-terminated string | address in `$a0`  | —      |
|       5 | read an integer                | —                 | `$v0`  |
|      10 | end the program                | —                 | —      |
|      11 | print one character            | low byte of `$a0` | —      |

The registers are part of the Playground's contract for each service. Other services use different
registers. Floating-point services, for example, use `$f12` for an input and `$f0` for a result.

In the MIPS architecture, `syscall` deliberately raises a **synchronous exception**: an event caused
by the instruction being executed. The Playground handles that event by performing the selected
service and then lets the program continue. The later **Exceptions and Coprocessor 0** lecture
explains the exception mechanism; the service convention is all you need here.

## Printing and exiting

```mips
.data
message: .asciiz "Hello, world!\n"

.text
.globl main
main:
    li $v0, 4               # service 4: print a zero-terminated string
    la $a0, message
    syscall

    li $v0, 1               # service 1: print a signed integer
    li $a0, 42
    syscall

    li $v0, 11              # service 11: print one character
    li $a0, '\n'
    syscall

    li $v0, 10              # service 10: end the program
    syscall
```

The console shows:

```text
Hello, world!
42
```

Service 4 starts at the address in `$a0` and prints bytes until it reaches a zero byte. That is why
the example uses `.asciiz`: the final `z` means the assembler adds the zero terminator. Service 1
interprets the 32 bits in `$a0` as a signed integer, so the same service also prints negative
numbers correctly.

Printing does not add a line break. The `\n` in the string prints the first newline, and service 11
prints the second one from the character literal `'\n'`. Every example on this page finishes by
selecting service 10 and executing `syscall`.

## Reading an integer

Service 5 waits for a decimal integer and returns it in `$v0`:

```mips
.data
prompt: .asciiz "Give me a number: "
answer: .asciiz "\nTwice that is "

.text
.globl main
main:
    li $v0, 4
    la $a0, prompt
    syscall

    li $v0, 5               # $v0 contains 5 before the call
    syscall                 # the result replaces that 5 in $v0
    move $t0, $v0           # preserve the result before choosing another service

    li $v0, 4
    la $a0, answer
    syscall

    add $a0, $t0, $t0
    li $v0, 1
    syscall

    li $v0, 10
    syscall
```

*Testcase for the program above (JSON):*

```json
{
    "input": ["21"],
    "expectedOutput": "Give me a number: \nTwice that is 42"
}
```

Press Run, type a number in the console and press Enter. The program pauses at service 5 until the
input arrives, then continues from the instruction after `syscall`.

Notice what happened to `$v0`: it held the service number 5 before `syscall`, and the read service
replaced it with the integer that was entered. Any service result replaces the previous value in its
result register. Playground services preserve all other general-purpose and floating-point
registers; a service with a documented memory result can still change that memory. Move a register
result somewhere safe before loading another service number into `$v0`.

## Making sound

Services 31 and 33 play a musical note. Both take the same four inputs:

- `$a0` chooses the **pitch**, or how high or low the note sounds. Use a number from 0 to 127.
  The example starts at 60, a note called middle C. Adding 1 moves to the next higher note;
  subtracting 1 moves to the next lower note. Each of these small steps is called a **semitone**.
- `$a1` gives the **duration** in milliseconds. For example, 300 lasts three tenths of a second,
  and 1000 lasts one second.
- `$a2` chooses the **instrument**, using a number from 0 to 127 in the General MIDI instrument
  list. The example uses 0 for an acoustic grand piano; try changing this number to hear other
  instrument sounds.
- `$a3` sets the **volume**, from 0 to 127. Larger values are louder; the example uses 100.

Service 33 waits for the note to end before running the next instruction. Service 31 continues
without waiting. If you use service 31 again while a previous note is still sounding, the notes
overlap.

```mips
.text
.globl main
main:
    li $a1, 300             # each note lasts 300 milliseconds
    li $a2, 0               # instrument 0, the acoustic grand piano
    li $a3, 100             # volume 100

    li $v0, 33              # service 33: play a note, then wait for it to end
    li $a0, 60              # middle C
    syscall
    li $a0, 64              # E
    syscall
    li $a0, 67              # G
    syscall

    li $v0, 31              # service 31: play a note and go on at once
    li $a1, 1000
    li $a0, 60              # C, E and G again, together: a chord
    syscall
    li $a0, 64
    syscall
    li $a0, 67
    syscall

    li $v0, 10
    syscall
```

The first three calls use service 33 to play the notes C, E and G one after another. The next
three calls use service 31 to start those same notes within a few instructions of each other.
They sound together as a **chord** and finish their one-second duration even though the program
has already ended.

Neither sound service changes a register, so `$v0` and the other arguments keep their values
between calls. That is why the example sets the instrument and volume only once. If a pitch,
instrument or volume is outside 0 to 127, the service uses middle C, the piano or volume 100,
respectively.

Once a program has made a sound, a **Sound** button in the execution dock turns sound off and on.
Testcases run silently, and service 33 finishes immediately without a real delay. The testcase
still counts the note's duration as elapsed program time.

### Waveforms on the Synth

Services 31 and 33 play recorded instrument sounds. The editor also has a **Synth**: a sound chip
like the ones inside 1980s game consoles and home computers, which the program controls directly.

The Synth's controls are **device registers**: each has a memory address, and storing a value
there changes a sound setting. The example puts the base address `0xffff0100` in the CPU register
`$s0`, then uses `sh` and `sb` with offsets from that address to reach the device registers.

The Synth has eight **channels**, each playing one sound at a time. The example uses channel 0
and these controls:

- the halfword at offset `0` is the **frequency** in Hz (hertz), how many times a second the sound
  repeats. Middle C, named by pitch number 60 in the previous example, is about 262 Hz here.
- the byte at `0x11` chooses the **waveform**, the shape that repeats: 0 is a pulse, 1 a triangle,
  2 a sawtooth, 3 a sine and 4 noise.
- the byte at `0x12` sets the overall volume, from 0 to 127. Larger values are louder.
- the byte at `0x13` sets the **sustain**, the level held while the sound continues, from 0 to 127.
  Sustain 127 keeps the sound at the chosen volume; lower values reduce that level further.
- the byte at `0x10` holds the **gate**: storing 1 starts a note, and storing 0 ends it.

The example sets volume 100 and sustain 127 so the tone holds at volume 100 until the gate goes
off. To leave time to hear each pitch, it uses service 32: put 32 in `$v0`, the wait in milliseconds
in `$a0`, then execute `syscall`. The stores control the sound, and the service supplies the pauses.

```mips
.text
.globl main
main:
    li $s0, 0xffff0100     # base address of Synth channel 0
    li $t0, 1
    sb $t0, 0x11($s0)     # waveform 1: a triangle
    li $t0, 100
    sb $t0, 0x12($s0)     # volume 100
    li $t0, 127
    sb $t0, 0x13($s0)     # sustain 127: hold at the chosen volume

    li $t0, 262            # middle C, in Hz
    sh $t0, 0($s0)
    li $t0, 1
    sb $t0, 0x10($s0)     # gate on: the note starts
    li $v0, 32             # service 32: wait
    li $a0, 400            # for 400 milliseconds
    syscall

    li $t0, 330            # E: change pitch while the gate stays on
    sh $t0, 0($s0)
    syscall                 # wait again: $v0 and $a0 still ask for it
    li $t0, 392            # G
    sh $t0, 0($s0)
    syscall

    sb $zero, 0x10($s0)   # gate off: the note ends
    li $v0, 10
    syscall
```

The gate stays on while the frequency changes from 262 to 330 to 392 Hz. You hear C, E and G as
one continuing tone that changes pitch, with 400 milliseconds at each pitch. Change the waveform
number at `0x11` to hear how the shape changes the sound.

The Synth is an extension of this editor; MARS does not provide these device controls. The
[Synth chapter](https://asm-editor.specy.app/documentation/mips/synth.md) of the Documentation has more controls and examples.

## More Playground services

You do not need to memorize this reference. Use it to find the registers for a service before you
write the request.

### Console output

| service | action                 | input             | formatting                                |
| ------: | ---------------------- | ----------------- | ----------------------------------------- |
|       1 | signed decimal integer | `$a0`             | no padding                                |
|       2 | float                  | `$f12`            |                                           |
|       3 | double                 | `$f12` / `$f13`   | the pair holds one 64-bit value           |
|       4 | string                 | address in `$a0`  | stops at the zero byte                    |
|      11 | character              | low byte of `$a0` |                                           |
|      34 | hexadecimal integer    | `$a0`             | `0x` followed by eight hexadecimal digits |
|      35 | binary integer         | `$a0`             | exactly 32 binary digits                  |
|      36 | unsigned decimal       | `$a0`             | ordinary decimal digits, with no padding  |

Services 1 and 36 can print the same bits differently. If `$a0` contains `-1`, service 1 prints
`-1`, while service 36 treats those bits as an unsigned value and prints `4294967295`.

### Console input

| service | action         | input                                         | result        |
| ------: | -------------- | --------------------------------------------- | ------------- |
|       5 | read integer   | —                                             | `$v0`         |
|       6 | read float     | —                                             | `$f0`         |
|       7 | read double    | —                                             | `$f0` / `$f1` |
|       8 | read string    | buffer address in `$a0`, buffer size in `$a1` | memory        |
|      12 | read character | —                                             | `$v0`         |

For service 8, the size in `$a1` includes the final zero byte. A buffer of size `n` therefore holds
at most `n - 1` input characters. When the entered line and its newline fit within that limit, the
service stores the newline and then the zero terminator. If they do not fit, it stores as much of the
line as fits, followed by the terminator. With size 1 it writes only the terminator; with a size less
than 1 it writes nothing.

### Program control, time and less common services

- Service 10 ends the run. Service 17 also ends it and takes an exit code in `$a0`.
- Service 30 returns elapsed Playground program time in milliseconds, with the low 32 bits in `$a0`
  and the high 32 bits in `$a1`. Service 32 takes milliseconds in `$a0` and waits before the next
  instruction. The Playground stays responsive, and the service avoids a busy-wait loop that would
  repeatedly spend the program's instruction budget. In a testcase, the clock starts at zero and
  service 32 advances it immediately without a real delay.
- Services 31 and 33 play a note, as shown above.
- Service 9 allocates bytes from the heap and returns their address in `$v0`. Under the Playground's
  default memory layout, that heap begins at `0x10040000`; a different memory layout can place it
  elsewhere.
- Services 13–16 open, read, write and close only the files shown in the editor's file explorer.
- Services 41–44 take a generator ID in `$a0`. Service 41 replaces `$a0` with a signed integer;
  service 42 replaces it with an integer in the range `0 <= value < $a1`, so `$a1` must be positive.
  Service 43 returns a float in `$f0`, and service 44 returns a double in `$f0` / `$f1`. This
  Playground does not provide service 40 for setting a seed.
- Services 50–59 provide dialog-style input and output through the Playground interface.

Other service numbers are unsupported and end the run with an error. The
[MIPS syscall documentation page](https://asm-editor.specy.app/documentation/mips/syscall.md) lists the full register contract for
each supported service.

Some devices use **memory-mapped I/O** instead: the program loads and stores at special memory
addresses. That is a different interface from placing a service number in `$v0` and executing
`syscall`.

## Two output services

Print exactly `The answer is 42`, with no newline or other text. Use two output syscalls—one for the
string and one for the number—then use the exit syscall.

*Exercise: the code to start from, checked by the testcase after it:*

```mips
.data
message: .asciiz "The answer is "

.text
.globl main
main:
    # your code here
```

*Testcase for the program above (JSON):*

```json
{
    "expectedOutput": "The answer is 42"
}
```

<details>
<summary>Show solution</summary>

*Solution:*

```mips
.data
message: .asciiz "The answer is "

.text
.globl main
main:
    li $v0, 4
    la $a0, message
    syscall

    li $v0, 1
    li $a0, 42
    syscall

    li $v0, 10
    syscall
```

</details>

## Read, square and print twice

Read two integers. Print the square of the first, one space, and the square of the second, with
nothing else in the output. Assume both squares fit in a signed 32-bit value. The supplied inputs
check a positive number and a negative number.

*Exercise: the code to start from, checked by the testcase after it:*

```mips
.text
.globl main
main:
    # your code here
```

*Testcase for the program above (JSON):*

```json
{
    "input": ["9", "-4"],
    "expectedOutput": "81 16"
}
```

<details>
<summary>Show solution</summary>

*Solution:*

```mips
.text
.globl main
main:
    li $v0, 5
    syscall
    move $t0, $v0

    li $v0, 5
    syscall
    move $t1, $v0

    mul $a0, $t0, $t0
    li $v0, 1
    syscall

    li $v0, 11
    li $a0, ' '
    syscall

    mul $a0, $t1, $t1
    li $v0, 1
    syscall

    li $v0, 10
    syscall
```

*Testcase for the program above (JSON):*

```json
{
    "input": ["9", "-4"],
    "expectedOutput": "81 16"
}
```

</details>

## Instructions in this Lecture

- MIPS: [`li`](https://asm-editor.specy.app/documentation/mips/instruction/li.md), [`la`](https://asm-editor.specy.app/documentation/mips/instruction/la.md), [`syscall`](https://asm-editor.specy.app/documentation/mips/instruction/syscall.md), [`move`](https://asm-editor.specy.app/documentation/mips/instruction/move.md), [`add`](https://asm-editor.specy.app/documentation/mips/instruction/add.md), [`sb`](https://asm-editor.specy.app/documentation/mips/instruction/sb.md), [`sh`](https://asm-editor.specy.app/documentation/mips/instruction/sh.md), [`mul`](https://asm-editor.specy.app/documentation/mips/instruction/mul.md)

Previous: [Floating point and Coprocessor 1](https://asm-editor.specy.app/learn/courses/mips/think-in-assembly/floating-point-and-coprocessor-1.md)

Next: [The bitmap display and keyboard registers](https://asm-editor.specy.app/learn/courses/mips/talking-to-the-outside-world/the-bitmap-display-and-the-keyboard.md)
