Sub-pages
$DFF030

Serial Port Overview

The Amiga includes a standard RS232 serial port managed by a UART (Universal Asynchronous Receiver/Transmitter) built into the Paula custom chip. The port supports full-duplex communication — data can be transmitted and received simultaneously over separate signal lines.

The RS232 connector carries two categories of signals:

  1. Data signals — TXD (transmit data) and RXD (receive data), which carry the actual serial bitstream.
  2. Handshake signals — CTS, RTS, DSR, DTR, etc., which are managed through the CIA chips and were covered in the CIA documentation.

All serial data transfer takes place over the TXD and RXD lines. When connecting two devices, TXD on one device is wired to RXD on the other and vice versa (null-modem / crossover wiring).

RS232 Data Format

Since only a single wire carries data in each direction, bytes must be serialized bit-by-bit. Because RS232 has no separate clock signal, both sender and receiver must agree on the bit timing — the baud rate, which specifies the number of bits transferred per second. Common baud rates are 300, 1200, 2400, 4800, and 9600.

Each byte is framed as follows:

  1. Start bit — a transition from the idle (high) state to low, signaling the beginning of a byte.
  2. Data bits — transmitted LSB first, in 8-bit or 9-bit format.
  3. Stop bit(s) — one or two high bits marking the end of the byte.

The receiver detects the start of each byte by the high-to-low transition between the stop bit of the previous byte and the start bit of the new one.

$DFF030

UART Registers

The UART in Paula uses three registers for serial data transfer, plus one bit in the ADKCON register for break control.

Serial Port Registers
$DFF030SERDAT — Serial transmit data (write only)
$DFF018SERDATR — Serial receive data + status (read only)
$DFF032SERPER — Serial period / baud rate (write only)
$DFF09EADKCON — Bit 11 (UARTBRK): force TXD low (write only)

SERDATR — Receive Data and Status ($DFF018, read)

This register contains both the received data byte and status flags for the UART.

Bit Name Function
15OVRUNOverrun — shift register full before buffer was read
14RBFReceive Buffer Full — data ready to read
13TBETransmit Buffer Empty — ready for next byte
12TSRETransmit Shift Register Empty — transmission complete
11RXDCurrent level of the RXD signal line
10Unused
9STPStop bit
8STP/DB8Stop bit (8-bit mode) or data bit 8 (9-bit mode)
7DB7Received data bit 7
6DB6Received data bit 6
5DB5Received data bit 5
4DB4Received data bit 4
3DB3Received data bit 3
2DB2Received data bit 2
1DB1Received data bit 1
0DB0Received data bit 0

SERPER — Period Register ($DFF032, write)

Bit Name Function
15LONGSet to 1 for 9-bit receive mode
14–0RATE15-bit period value determining baud rate
$DFF030

Receiving Data

Serial reception proceeds in two stages, using a shift register and a data buffer.

Stage 1: Shift Register

Incoming bits on the RXD pin are clocked into a shift register at the rate determined by SERPER. The start bit triggers the process: the UART samples RXD at the center of each bit period to reconstruct a parallel data word.

Stage 2: Data Buffer

When the shift register is full (all data bits plus stop bit received), its contents are transferred to the receive buffer — the data bits in SERDATR. The shift register is then immediately free to begin receiving the next byte.

Data Format

The data width depends on the LONG bit in SERPER:

  • LONG = 0 (8-bit mode): Bits 7–0 of SERDATR contain the 8 data bits. Bit 8 holds the stop bit. Bit 9 holds the second stop bit (if present).
  • LONG = 1 (9-bit mode): Bits 8–0 contain 9 data bits. Bit 9 holds the stop bit.

Status Flags

RBF (Receive Buffer Full) is set to 1 when a complete data word is transferred from the shift register to the buffer. This flag also exists as bit 11 in INTREQ/INTEN, generating an interrupt. After reading the data, software must clear RBF by writing to INTREQ:

    move.w #$0800,$DFF09C      ; clear RBF in INTREQ (and SERDATR)

Overrun Detection

If the receive buffer is not read before the shift register fills again, an overrun occurs. The OVRUN bit in SERDATR is set to 1, indicating that data has been lost. When RBF is finally cleared, the shift register contents are transferred to the buffer and OVRUN is reset. RBF then goes high again immediately, since the buffer now contains the (late) data from the shift register.

To avoid overruns, always read SERDATR and clear RBF promptly — ideally in an RBF interrupt handler.

$DFF030

Transmitting Data

Serial transmission also uses a two-stage pipeline: a data buffer (SERDAT) and an output shift register.

Writing Data

The transmit data format in SERDAT depends on the desired word length and number of stop bits. The data bits occupy the lower portion of the register, followed immediately by one or two stop bits (set to 1). All higher bits must be 0.

8-bit data, 2 stop bits:

Bit 15–10 9–8 7–0
Value0 0 0 0 0 01 1 (stop bits)D7–D0 (data)

8-bit data, 1 stop bit:

Bit 15–9 8 7–0
Value0 0 0 0 0 0 01 (stop bit)D7–D0 (data)

9-bit data, 1 stop bit:

Bit 15–10 9 8–0
Value0 0 0 0 0 01 (stop bit)D8–D0 (data)

Note that the LONG bit in SERPER only affects reception. The transmit format is determined entirely by the value written to SERDAT.

Transmit Status Flags

TBE (Transmit Buffer Empty) is set to 1 when the data in SERDAT has been transferred to the output shift register. The buffer is then ready for the next word. TBE is also bit 0 in INTREQ/INTEN. Like RBF, it must be cleared via INTREQ after servicing.

TSRE (Transmit Shift Register Empty) is set to 1 when the shift register has finished sending all bits and no new data is waiting in the buffer. This indicates that the transmission is truly complete. TSRE is reset when TBE is cleared.

UARTBRK — Break Signal

Bit 11 (UARTBRK) of the ADKCON register, when set, forces the TXD output line low and halts serial transmission. This generates a "break" condition on the RS232 line, which the remote device can detect. Clear the bit to resume normal operation.

ADKCON Serial Bit
$DFF09EADKCON bit 11 — UARTBRK: set to force TXD low (break condition)
$DFF010ADKCONR bit 11 — read back UARTBRK state
$DFF030

Baud Rate Calculation

The lower 15 bits of SERPER (bits 14–0, the RATE field) specify the bit period as a number of bus clock cycles. One bus clock cycle lasts approximately 279.365 nanoseconds (based on the PAL system clock of 3.546895 MHz).

The formula to convert a desired baud rate to the SERPER value is:

SERPER = (1 / (baud_rate * 279.365 * 10^-9)) - 1

Or equivalently:

SERPER = (3,579,545 / baud_rate) - 1 (NTSC clock) SERPER = (3,546,895 / baud_rate) - 1 (PAL clock)

Common Baud Rates

Baud Rate SERPER Value (PAL) SERPER Value (NTSC)
3001182211931
120029552982
240014771491
4800738745
9600369372
19200184186
31250 (MIDI)112113

The calculated value is rounded to the nearest integer before writing to SERPER:

    move.w #745,$DFF032        ; set 4800 baud (NTSC), LONG=0 (8-bit)

For 9-bit receive mode, set bit 15:

    move.w #$8000+745,$DFF032  ; set 4800 baud, LONG=1 (9-bit receive)
$DFF030

Interrupts and Programming

The UART generates two interrupt signals, both managed through INTREQ/INTEN:

INTREQ Bit Name Condition Level
0TBETransmit buffer empty — ready for next word1
11RBFReceive buffer full — data available5

Typical Receive Handler

SerialReceiveISR:
    move.w $DFF018,d0          ; read SERDATR
    btst   #15,d0              ; check OVRUN
    bne    .overrun            ; handle overrun condition
    and.w  #$00FF,d0           ; extract 8 data bits
    ; ... process received byte in d0 ...
    move.w #$0800,$DFF09C      ; clear RBF in INTREQ
    rte

.overrun:
    move.w #$0800,$DFF09C      ; clear RBF to recover
    ; ... signal overrun error ...
    rte

Typical Transmit Sequence

SendByte:
    ; d0.b = byte to send
    and.w  #$00FF,d0           ; mask to 8 bits
    or.w   #$0100,d0           ; add 1 stop bit (bit 8 = 1)
    move.w d0,$DFF030          ; write to SERDAT
    ; TBE interrupt will fire when buffer is free for next byte
    rts

The UART in Paula handles start bit insertion and bit serialization automatically. Software only needs to write the data word (with stop bits) to SERDAT and wait for TBE before sending the next byte.