MFP, RTC & anything else
===========#==#=======#===============================================#=====
----------------------|Realtime Clock Chip, Non Volatile Memory |-----
===========#==#=======#===============================================#=====
$FFFF8961.B|RW|NVM_CTL|Register Select |TT,F
$FFFF8961 and $FFFF8963 Real Time Clock / NVRAM
$FFFF8961 Address register: write the location to access
$FFFF8963 Data register: read or write that location
TT and Falcon. The NVRAM holds 50 bytes of user settings
(language, keyboard, boot preferences) plus the real time
clock registers, in a battery backed MC146818 compatible part.
Access is indirect: write an address to $FFFF8961, then read
or write $FFFF8963. EmuTOS bios/nvram.c wraps this in the
NVMaccess XBIOS call rather than exposing the registers.
On the Falcon the fitted part is a DS1287 (MC146818
compatible). Internal register map, per the F030/CT60
listing:
0 current second 1 alarm second
2 current minute 3 alarm minute
4 current hour 5 alarm hour
6 day of week (1 = Sunday)
7 day of month 8 month
9 year (two digits)
A bit 7: 1 = time update in progress, do not read the
time and date registers while set
B bit 7: 1 = write protect time and date
bit 6: 1 = enable alarm interrupt
bit 5: 1 = interrupt after time updated
bit 2: 1 = binary format, 0 = BCD
bit 1: 1 = 24 hour format, 0 = 12 hour
bit 0: 1 = summer time, 0 = winter time
C bit 6: ? bit 5: 1 = alarm is ringing
bit 4: 1 = date has updated
read this register on interrupt to find the source
D bit 7: 1 = BATTERY DEAD, clock contents invalid
From the Atari Compendium; DS1287 register map from the
F030/CT60 listing, matching the standard MC146818 layout.
$FFFF8963.B|RW|NVM_DAT|Data of selected Register |TT,F
$FFFF8964.B|RW| - |Add-on control, not present on stock hardware |*
$FFFF8964, $FFFF896A, $FFFF896C, $FFFF8970 Add-on control
Not present on stock Atari hardware. These addresses sit in
the gap above the TT and Falcon real time clock registers and
below the reserved area at $FFFF8A00.
Known to be used by:
$FFFF8964 FLASHY CLOCK
$FFFF896A SEC BOOSTER
$FFFF896C FLASHY CLOCK
$FFFF8970 FLASHY CLOCK
FLASHY CLOCK also uses $FFFF89F0 and $FFFF89F2 for its real
time clock, and $FFFFFFFF as a control register.
Extended bit information is not currently available for these
registers. The addresses are documented; what each bit does is
not.
No conflict found: neither EmuTOS nor Hatari references any
address in the $FFFF8964 to $FFFF8970 range.
$FFFF896A.B|RW| - |Add-on control, not present on stock hardware |*
$FFFF896C.B|RW| - |Add-on control, not present on stock hardware |*
$FFFF8970.B|RW| - |Add-on control, not present on stock hardware |*
$FFFF89F0.B|RW| - |Add-on real time clock |*
$FFFF89F0 and $FFFF89F2 Add-on real time clock
Not present on stock Atari hardware.
Known to be used by: FLASHY CLOCK.
Extended bit information is not currently available for these
registers.
No conflict found: neither EmuTOS nor Hatari references either
address.
$FFFF89F2.B|RW| - |Add-on real time clock |*
===========#==#=======#===============================================#=====
----------------------|DMA SCC |-----
===========#==#=======#===============================================#=====
$FFFF8C01.B|RW|SCC_DA0|DMA Address Pointer (Highest byte) |TT
$FFFF8C03.B|RW|SCC_DA1|DMA Address Pointer (High byte) |TT
$FFFF8C05.B|RW|SCC_DA2|DMA Address Pointer (Low byte) |TT
$FFFF8C07.B|RW|SCC_DA3|DMA Address Pointer (Lowest byte) |TT
$FFFF8C09.B|RW|SCC_BC0|DMA Byte Counter (Highest byte) |TT
$FFFF8C0B.B|RW|SCC_BC1|DMA Byte Counter (High byte) |TT
$FFFF8C0D.B|RW|SCC_BC2|DMA Byte Counter (Low byte) |TT
$FFFF8C0F.B|RW|SCC_BC3|DMA Byte Counter (Lowest byte) |TT
$FFFF8C10.W|Rw|SCC_RD0|Rest data (High Word) |TT
$FFFF8C12.W|Rw|SCC_RD1|Rest data (Low Word) |TT
$FFFF8C14.W|Rw|SCC_CTL|DMA SCC Control Register %________ BZ____DW |TT
| | | Bus Error 0:no,1:yes-----------------+| || |TT
| | | Byte Counter Zero 0:no,1:yes----------+ || |TT
| | | DMA 0:off,1:on-----------------------------+| |TT
| | | 0:DMA read,1:DMA write----------------------+ |TT
===========#==#=======#===============================================#=====
----------------------|SCC Y8530 - Serial Communication Controller |-----
===========#==#=======#===============================================#=====
$FFFF8C81.B|RW|SCA_CTL|Channel A Control (select/read/write Register) |SCC
$FFFF8C81 to $FFFF8C87 SCC 8530 Serial Controller
$FFFF8C81 Channel A control
$FFFF8C83 Channel A data
$FFFF8C85 Channel B control
$FFFF8C87 Channel B data
The 8530 has far more internal registers than the four
addresses above suggest. Access is indirect: write a register
number to the control address, then read or write the control
address again to reach that register. Register 0 is reached
directly without a preceding select.
The data addresses map to internal register 8.
INTERNAL REGISTER MAP (Z8530 datasheet, implemented in full by
Hatari src/scc.c):
Write registers:
WR0 register select / command (CRC reset, reset ext/status
interrupts, error reset, and so on)
WR1 interrupt and data transfer mode enables
WR2 interrupt vector base (one per chip, shared A and B)
WR3 receiver parameters: bit 0 RX enable, bits 7-6 bits
per character (00=5, 10=6, 01=7, 11=8)
WR4 bit 0 parity enable, bit 1 even parity, bits 3-2 stop
bits (00=sync, 01=1, 10=1.5, 11=2), bits 7-6 clock
mode (x1, x16, x32, x64)
WR5 transmitter parameters: bit 1 RTS, bit 3 TX enable,
bit 4 send break, bits 6-5 TX bits per character,
bit 7 DTR
WR6 sync character / SDLC address
WR7 sync character / SDLC flag (WR7' extensions reachable
via WR15 bit 0 on the 85C30)
WR8 transmit data buffer (same as the data address)
WR9 master interrupt control and chip reset: bit 0 vector
includes status, bit 1 no vector, bit 3 master int
enable, bits 7-6 reset commands
WR10 misc TX/RX control (encoding: NRZ, NRZI, FM)
WR11 clock source selection for RX/TX
WR12 baud rate generator time constant, low byte
WR13 baud rate generator time constant, high byte
WR14 misc control: bit 0 BRG enable, bit 1 BRG source,
bits 7-5 DPLL commands
WR15 external/status interrupt enables: bit 1 zero count,
bit 3 DCD, bit 4 sync/hunt, bit 5 CTS, bit 6 TX
underrun/EOM, bit 7 break/abort
Read registers:
RR0 status: bit 0 RX character available, bit 2 TX buffer
empty, bit 3 DCD, bit 4 sync/hunt, bit 5 CTS, bit 6
TX underrun/EOM, bit 7 break/abort
RR1 special receive condition status (parity, overrun,
framing errors)
RR2 interrupt vector (channel B read returns it modified
by the interrupt source)
RR3 interrupt pending bits (channel A only)
RR8 receive data buffer (same as the data address)
RR10 loop/clock status
RR12 BRG time constant low readback
RR13 BRG time constant high readback
RR15 external/status interrupt enable readback
Baud rate: on the Atari the SCC PCLK is 8.053976MHz (the
Falcon and TT feed the same master clock), and channel B's
receive/transmit clock TRxCB can instead be driven from MFP
Timer C, which is why that timer is reserved on the TT. Baud
= PCLK / (2 x (time constant + 2) x clock mode divisor) when
the BRG runs from PCLK.
Port assignment on the Atari machines: channel A drives the
LAN connector or Serial 2 (selected by YM port A bit 7 on the
TT and Falcon), channel B drives the modem/serial port.
The SCC generates interrupts through the vector table at
$00000180 to $000001BC. That table is SPARSE: only every other
longword is a real vector, alternating with an unused slot.
See the System variables and low RAM page.
Register map from the Zilog Z8530/85C30 datasheet; register
behaviour cross-checked against the define tables and handlers
in Hatari src/scc.c, which implements WR0-WR15 and RR0-RR15
for the Atari machines.
TT, Mega STE and Falcon.
$FFFF8C83.B|RW|SCA_DAT|Channel A Data (read/write Register 8) |SCC
$FFFF8C85.B|RW|SCB_CTL|Channel B Control (select/read/write Register) |SCC
$FFFF8C87.B|RW|SCB_DAT|Channel B Data (read/write Register 8) |SCC
===========#==#=======#===============================================#=====
----------------------|VME Bus |-----
===========#==#=======#===============================================#=====
$FFFF8E01.B|RW|VME_MR0|VME Mask Register 0 %EMSV_HS_ |TT,ME
| | | Enable bits for the same interrupt sources as |TT,ME
| | | VME_SR0 below, same bit positions, 1=enabled. |TT,ME
| | | Cleared to $00 on reset; TOS sets $14 (HBL + |TT,ME
| | | VBL). Per Hatari src/scu_vme.c. |TT,ME
$FFFF8E03.B|RW|VME_SR0|VME Status Register 0 %EMSV_HS_ |TT,ME
| | | Error 0:no,1:yes---------------------+||| || |TT,ME
| | | MFP-----------------------------------+|| || |TT,ME
| | | SCC------------------------------------+| || |TT,ME
| | | VBL-------------------------------------+ || |TT,ME
| | | HBL---------------------------------------+| |TT,ME
| | | Software Interrupt-------------------------+ |TT,ME
$FFFF8E05.B|RW|VME_IN0|Force Interrupt on Level 1 %_______F |TT,ME
$FFFF8E07.B|RW|VME_IN1|Force Interrupt on Level 3 %_______F |TT,ME
$FFFF8E09.B|RW|SCU_GP1|SCU General Purpose Register 1 |TT,ME
| | | Verified: EmuTOS bios/machine.h (SCU_GPR1 |
| | | 0xffff8e09) and Atari TOS 3.06 bios/startup.S,|
| | | which uses bit 0 as a memory-config-valid |
| | | flag. |
$FFFF8E0B.B|RW|SCU_GP2|SCU General Purpose Register 2 |TT,ME
| | | UNVERIFIED: Atari Compendium only. GPR1 next |
| | | door is confirmed twice, so this is very |
| | | likely real, but no source touches it. |
| | | Both GP registers are plain byte latches with |
| | | no assigned bits: cleared on cold boot only, |
| | | they keep their contents over a warm boot |
| | | (Hatari src/scu_vme.c). |
$FFFF8E0D.B|RW|VME_MR1|VME Mask Register 1 %7654321_ |TT,ME
| | | Enable bits for VME bus interrupts 1-7, same |TT,ME
| | | positions as VME_SR1 below, 1=enabled. Bit 0 |TT,ME
| | | unused. Cleared to $00 on reset; TOS sets $60 |TT,ME
| | | (IRQ6=MFP + IRQ5=SCC). Per Hatari |TT,ME
| | | src/scu_vme.c. |TT,ME
$FFFF8E0F.B|RW|VME_SR1|VME Status Register 1 %7654321_ |TT,ME
| | | VME Interrupt 1-7 0:on,1:off---------+++++++ |
===========#==#=======#===============================================#=====
$FFFF8E21.B|RW|M_E_CAC|Mega STe Cache/Processor Control %______SC |ME
| | | cpu Speed 0:8MHz,1:16MHz-------------------+| |ME
| | | Cache 0:disabled,1:enabled------------------+ |ME
| | | $FF 16MHz with cache |ME
| | | $FE 16MHz, cache off |ME
| | | $F4 8MHz |ME
| | | The cache only works at 16MHz: setting bit 0 |
| | | with bit 1 clear reads back with bit 0 forced |
| | | to 0 (write $FD, read $FC). Per Hatari |
| | | src/ioMemTabSTE.c. |
| | | CORRECTED: was listed at $FFFF8E0F, which |
| | | belongs to VME_SR1. Verified at $FFFF8E21 by |
| | | Atari TOS 3.06 bios/startup.S: ori.b |
| | | #3,($ffff8e21).w with the comment "turn on |
| | | 16MHz and cache". Value table from the Atari |
| | | Compendium. |
===========#==#=======#===============================================#=====
----------------------|GAMECART - undocumented STE register |-----
===========#==#=======#===============================================#=====
$FFFF9000.W|-W|GAMECRT|Cartridge remap control %_______G ________ |STE | | | Gamecart 0:normal,1:remapped-------+ |STE | | | UNDOCUMENTED. Not in Hatari, EmuTOS, |STE | | | any TOS, or the Atari Compendium. |STE
$FFFF9000 GAMECART Cartridge address remap (STE)
Bit 8 of the word, which is bit 0 of the byte at $FFFF9000,
drives a signal named GAMECART inside the STE's combined
GLUE/MMU (GST MCU) chip. Writing it moves the cartridge port
chip selects to a different address range:
GAMECART = 0 (normal)
$00FA0000-$00FAFFFF /ROM4
$00FB0000-$00FBFFFF /ROM3
GAMECART = 1 (remapped)
$00D80000-$00DBFFFF /ROM4
$00DC0000-$00DFFFFF /ROM3
and $00FA0000-$00FBFFFF then BUS ERRORS
The bit comes from a flip flop, so it latches. The register is
write only; there is no documented way to read the state back.
ORIGIN: found by Keli Hlodversson by tracing Atari's original
hand-drawn STE ASIC schematics, which were recovered and
converted to PDF by Christian Zietz. Write-up at
https://www.keli.dk/old-asic/ . The remapped address ranges
above and the bus error behaviour are Christian Zietz's
reading of the same schematics.
WHY IT EXISTS, probably: an internal Atari memo reproduced in
"We Love Atari (Volume Two)", page 154, describes a never
released "STE Game Machine" codenamed Project Robin, built
around the GST MCU with 512KB of cartridge ROM. The remapped
range is exactly 512KB. Note that the dating is not settled:
Atari is reported to have been considering an ST based games
machine as early as 1986, which would predate the STE.
PRACTICAL LIMIT: the cartridge port only brings out address
lines up to A15, so only 2 x 64KB can be addressed directly
however the selects are mapped. Using the full 512KB would
need a hardware modification or bank switching on the
cartridge itself. No cartridge is known to do this.
VERIFICATION STATUS - read this before relying on it:
Hatari knows the ADDRESS but not the function. Its STE
and TT tables map $ff9000 as a word with void
read and void write, commented "No bus error
here", and $ff9000-$ff91ff is in its no-bus-error
list for Falcon STE compatible mode. So the
address genuinely responds rather than faulting,
which is consistent, but GAMECART itself is NOT
emulated.
EmuTOS no reference at all.
Atari TOS no reference in any version. Christian Zietz
states plainly that no TOS accesses this
register, so a cartridge cannot boot from the
remapped range.
Compendium not listed.
So this rests on schematic archaeology by two people, with
the address confirmed as decoded by Hatari and nothing else.
It has not been demonstrated on real hardware in any account
found so far. Treat the ranges as credible but untested, and
do not assume an emulator will reproduce them.
RELATED DECODES found in the same schematics, on page 1 of
this memory map: the STE's /ROM0 and /ROM1 selects, unused on
production machines, decode $00E80000-$00EBFFFF and
$00E40000-$00E7FFFF; /ROM5 and /ROM6 decode
$00D00000-$00D7FFFF.
===========#==#=======#===============================================#=====
----------------------|Paddle Ports |-----
===========#==#=======#===============================================#=====
$FFFF9200.W|RW|PAD_BUT|Paddle/Joy Buttons %xxxxxxxx ____3210 |STE,F | | | Switches--------------------++++++++ |,TT | | | On Falcon at U47: MSB on the right, closed=0 |
$FFFF9200 PAD_BUT Joypad fire buttons / DIP switches
Low nibble, read: fire buttons, per the F030/CT60 listing:
Bit 3 Option / F3
Bit 2 F2
Bit 1 F1
Bit 0 Pause / F0
High byte: on the Mega STE and Falcon this byte also returns
the state of the 8 configuration DIP switches on the
motherboard (Falcon: U47, most significant bit on the right,
closed = 0). Hatari src/joy.c implements this.
ACCESS QUIRK: on the STE and Mega STE this register can only
be read as a WORD at $FFFF9200; a byte access at $FFFF9200
does not work, though $FFFF9201 can be read as a byte. Hatari
src/joy.c implements the restriction.
$FFFF9202.W|RW|PAD_MOV|Paddle/Joy Move (R) / Read Mask (W) |STE,F
$FFFF9202 PAD_MOV Joystick inputs (read) / read mask (write)
Write: the read mask; a 0 bit selects the corresponding pin
group for reading. Read: the joystick input pins, per the
F030/CT60 listing:
Bit 15 Controller 1 pin 14 Bit 7 Controller 1 pin 4
Bit 14 Controller 1 pin 13 Bit 6 Controller 1 pin 3
Bit 13 Controller 1 pin 12 Bit 5 Controller 1 pin 2
Bit 12 Controller 1 pin 11 Bit 4 Controller 1 pin 1
Bit 11 Controller 0 pin 14 Bit 3 Controller 0 pin 4
Bit 10 Controller 0 pin 13 Bit 2 Controller 0 pin 3 /
Bit 9 Controller 0 pin 12 Paddle 1 trigger
Bit 8 Controller 0 pin 11 Bit 1 Controller 0 pin 2 /
Paddle 0 trigger
Bit 0 Controller 0 pin 1
The enhanced joystick ports carry the four directions on pins
1-4 and the extra joypad lines on pins 11-14.
$FFFF9210.W|RW|PAD_PD0|Pad0 Position / X Paddle 0 |STE,F
$FFFF9210 to $FFFF9216 Paddle position counters
Four word registers, low byte holds the position.
NAMING: this page has called them Pad0 to Pad3 Position. The
F030/CT60 listing names them X Paddle 0 ($9210), Y Paddle 0
($9212), X Paddle 1 ($9214) and Y Paddle 1 ($9216): two
paddle controllers, each with an X and a Y axis. The two
descriptions are different readings of the same four
registers; the paddle pairing follows the trigger bits at
$FFFF9202 (paddle 0 and 1), so the X/Y naming is likely the
intended one. Not settled by Hatari, EmuTOS or TOS source,
none of which touch these registers.
$FFFF9212.W|RW|PAD_PD1|Pad1 Position / Y Paddle 0 |STE,F
$FFFF9214.W|RW|PAD_PD2|Pad2 Position / X Paddle 1 |STE,F
$FFFF9216.W|RW|PAD_PD3|Pad3 Position / Y Paddle 1 |STE,F
$FFFF9220.W|RW|PAD_LPX|Lightpen X |STE,F
$FFFF9222.W|RW|PAD_LPY|Lightpen Y |STE,F
===========#==#=======#===============================================#=====
----------------------|DSP 56001 Host - Digital Signal Processor |-----
===========#==#=======#===============================================#=====
$FFFFA200.B|RW|DSP_ICR|Interrupt Control Register (%IMMHH_TR) |DSP
$FFFFA200 DSP_ICR Interrupt Control Register (DSP X:$FFE9)
Bit 7 INIT setting this forces initialisation of the
host interface
Bits 6-5 DMA mode control:
00 interrupt mode, DMA off
01 24 bit DMA mode
10 16 bit DMA mode
11 8 bit DMA mode
Bit 4 HF1 host flag 1
Bit 3 HF0 host flag 0
Bit 2 unused
Bits 1-0 Data transfer mode
The host flags are general purpose signalling bits readable by
the DSP; they carry no fixed meaning in hardware.
Falcon only. From the Atari Compendium.
$FFFFA201.B|RW|DSP_CVR|Command Vector Register (%I__VVVVV) |DSP
$FFFFA201 DSP_CVR Command Vector Register (DSP X:$FFE9)
Bit 7 Host command bit
Bits 6-5 unused
Bits 4-0 Host vector, 0 to 31
Writing a vector with the command bit set causes the DSP to
take an interrupt to that vector, which is how the host asks
the DSP to run a routine.
Falcon only. From the Atari Compendium.
$FFFFA202.B|RW|DSP_ISR|Interrupt Status Register (%ID_HHETR) |DSP
$FFFFA202 and $FFFFA203 DSP Status and Vector
$FFFFA202 Interrupt Status Register (DSP X:$FFE8)
$FFFFA203 Interrupt Vector Register
The status register reports the state of the host interface,
including whether the transmit register is empty and the
receive register is full, plus the two host flags coming back
from the DSP.
The vector register holds the 680x0 exception vector number
used when the DSP raises an interrupt to the host.
The wiki summary line gives the status register bit pattern as
%ID_HHETR: I = interrupt, D = DMA, HH = host flags, E = transmit
empty, T = transmit, R = receive.
Falcon only. The Atari Compendium names both registers but
gives no bit breakdown for the status register.
$FFFFA203.B|RW|DSP_IVR|Interrupt Vector Register (Vector Number) |DSP
$FFFFA204.B|RW|DSP_TR0|Transfer Highest Byte (DSP56003 32bit) |DSP32
$FFFFA204 to $FFFFA207 DSP Transfer Registers
$FFFFA204 Transfer byte, highest (DSP56003 32 bit only)
$FFFFA205 Transfer byte, high
$FFFFA206 Transfer byte, middle
$FFFFA207 Transfer byte, low
The DSP56001 fitted to the Falcon is a 24 bit part, so only
the low three bytes are used. $FFFFA204 exists for the 32 bit
DSP56003, which the Falcon does not have.
Reading or writing $FFFFA207 is what actually triggers the
transfer; the other bytes are staged first.
Falcon only.
$FFFFA205.B|RW|DSP_TR1|Transfer Hi |DSP
$FFFFA206.B|RW|DSP_TR2|Transfer Mi |DSP
$FFFFA207.B|RW|DSP_TR3|Transfer Lo |DSP
===========#==#=======#===============================================#=====
----------------------|MFP 68901 - Multi Function Peripheral |-----
===========#==#=======#===============================================#=====
$FFFFFA01.B|RW|MFP_PDR|Parallel Port Data Register %SRFKBRDC |
$FFFFFA01 MFP_PDR General Purpose I/O Port
Bit 7 Monochrome monitor detect
Bit 6 RS-232 ring indicator
Bit 5 FDC / HDC interrupt
Bit 4 Keyboard / MIDI interrupt
Bit 3 Blitter done
Bit 2 RS-232 clear to send
Bit 1 RS-232 carrier detect
Bit 0 Centronics busy
All eight are inputs on a standard ST, set by the data
direction register at $FFFFFA05.
Bit 5 is the one to poll for floppy and hard disk completion:
read the byte, mask with $20, and a result of ZERO means the
controller has interrupted. This is what TOS itself does.
Bit 7 is how machines before the Falcon detect a monochrome
monitor. The Falcon uses $FFFF8006 instead.
FALCON WIRING DIFFERS: on the Falcon two GPIP pins carry
different signals (per the F030/CT60 listing):
Bit 2 MIDI ACIA interrupt (ST: RS-232 clear to send)
Bit 3 DSP connector interrupt (ST: Blitter done)
The corresponding interrupt vectors move with them: on the
Falcon vector $108 is the MIDI ACIA and $10C the DSP
connector, where the ST has RS-232 CTS and Blitter done. Both
assignments are correct for their machine.
From the Atari Compendium.
$FFFFFA03.B|RW|MFP_AER|Active Edge Register %SRFKBRDC | | | | Interrupt on 0:High-Low,1:Low-High |||||||| |!F | | | Interrupt on 0:Low-High,1:High-Low |||||||| |F
$FFFFFA03 MFP_AER Active Edge Register
One bit per GPIO pin, same order as $FFFFFA01:
Bit 7 Monochrome monitor detect
Bit 6 RS-232 ring indicator
Bit 5 FDC / HDC interrupt
Bit 4 Keyboard / MIDI interrupt
Bit 3 Blitter done
Bit 2 RS-232 clear to send
Bit 1 RS-232 carrier detect
Bit 0 Centronics busy
Selects which edge on that pin causes an interrupt:
On the ST and STE: 0 = high to low, 1 = low to high
On the Falcon: 0 = low to high, 1 = high to low
The polarity is inverted on the Falcon, which is why the wiki
summary carries two lines for this register with !F and F tags.
Note: on a Falcon the MFP is not actually used for serial
communications, so the RS-232 bits are not meaningful there.
From the Atari Compendium.
$FFFFFA05.B|RW|MFP_DIR|Data-direction %SRFKBRDC | | | | I/O-7 Mono Detect/Sound--------------+||||||| | | | | I/O-6 RS232 Ring Indicator------------+|||||| | | | | I/O-5 FDC/HDC--------------------------+||||| | | | | I/O-4 IKBD/MIDI-------------------------+|||| | | | | I/O-3 Blitter Done-----------------------+||| | | | | I/O-2 RS232 CTS---------------------------+|| | | | | I/O-1 RS232 DCD----------------------------+| | | | | I/O-0 Centronics Busy-----------------------+ |
$FFFFFA05 MFP_DIR Data Direction Register
One bit per GPIO pin, same order as $FFFFFA01.
Each bit is individually programmed: 0 = input, 1 = output.
On a standard ST all eight pins are inputs, so this register
reads as zero. Changing it without knowing what is wired to
the pin can drive a line that something else is also driving.
From the Atari Compendium.
$FFFFFA07.B|RW|MFP_IEA|Interrupt Enable A %76AbebeB |
$FFFFFA07 MFP_IEA Interrupt Enable Register A
Bit 7 Monochrome monitor detect
Bit 6 RS-232 ring indicator
Bit 5 Timer A (STE and TT sound)
Bit 4 Receive buffer full
Bit 3 Receive error
Bit 2 Transmit buffer empty
Bit 1 Transmit error
Bit 0 Timer B
Setting a bit enables that interrupt source. The same bit
layout applies to all four register A pairs:
$FFFFFA07 Interrupt Enable A
$FFFFFA0B Interrupt Pending A
$FFFFFA0F Interrupt In-Service A
$FFFFFA13 Interrupt Mask A
Enable decides whether the source can interrupt at all; mask
decides whether an enabled and pending interrupt is passed to
the processor. Pending is set by the hardware and cleared by
writing a ZERO to that bit, not a one.
On a Falcon the MFP is not used for serial communications.
From the Atari Compendium.
$FFFFFA09.B|RW|MFP_IEB|Interrupt Enable B %54CD3210 |
$FFFFFA09 MFP_IEB Interrupt Enable Register B
Bit 7 FDC / HDC
Bit 6 Keyboard / MIDI
Bit 5 Timer C (200 Hz system clock)
Bit 4 Timer D (USART baud rate)
Bit 3 Blitter done
Bit 2 RS-232 clear to send
Bit 1 RS-232 carrier detect
Bit 0 Centronics busy
The same bit layout applies to all four register B pairs:
$FFFFFA09 Interrupt Enable B
$FFFFFA0D Interrupt Pending B
$FFFFFA11 Interrupt In-Service B
$FFFFFA15 Interrupt Mask B
Timer C at bit 5 is the one driving the 200 Hz system clock
counter at $000004BA and the VBL queue. Disabling it stops
large parts of TOS working.
From the Atari Compendium.
$FFFFFA0B.B|RW|MFP_IPA|Interrupt Pending A %76AbebeB |
$FFFFFA0D.B|RW|MFP_IPB|Interrupt Pending B %54CD3210 |
$FFFFFA0F.B|RW|MFP_ISA|Interrupt In-Service A %76AbebeB |
$FFFFFA11.B|RW|MFP_ISB|Interrupt In-Service B %54CD3210 |
$FFFFFA13.B|RW|MFP_IMA|Interrupt Mask A %76AbebeB |
| | | I/O 7 Mono Detect/Sound--------------+||||||| |
| | | I/O 6 RS232 Ring----------------------+|||||| |
| | | Timer A--------------------------------+||||| |
| | | Receive Buffer full---------------------+|||| |
| | | Receive Error----------------------------+||| |
| | | Transmit Buffer empty---------------------+|| |
| | | Transmit Error-----------------------------+| |
| | | Timer B-------------------------------------+ |
$FFFFFA15.B|RW|MFP_IMB|Interrupt Mask B %54CD3210 |
| | | I/O 5 FDC/HDC------------------------+||||||| |
| | | I/O 4 IKBD/MIDI-----------------------+|||||| |
| | | Timer C--------------------------------+||||| |
| | | Timer D---------------------------------+|||| |
| | | I/O 3 Blitter Done-----------------------+||| |
| | | I/O 2 RS232 CTS---------------------------+|| |
| | | I/O 1 RS232 DCD----------------------------+| |
| | | I/O 0 Centronics Busy-----------------------+ |
$FFFFFA17.B|RW|MFP_VCR|Vector Register %xxxxI___ |0100 | | | End of Interrupt 0:software, 1:auto------+ |1000 | | | VCR should contain------------------%0100?000 |*
$FFFFFA17 MFP_VCR Vector Register
Bits 7-4 Interrupt vector base, upper nibble
Bit 3 End of interrupt mode:
1 = software end of interrupt
0 = automatic end of interrupt
Bits 2-0 Supplied by the MFP as the interrupt number
On the Atari the base is set to $40, so MFP interrupts use
vectors $40 to $4F, which are addresses $00000100 to
$0000013C in the exception vector table.
In software end of interrupt mode the handler must clear the
corresponding bit in the in-service register itself, otherwise
no further interrupt of that or lower priority is delivered.
The wiki summary notes the register should contain %0100?000.
From the Atari Compendium.
$FFFFFA19.B|RW|MFP_TAC|Timer A Control %____EAAA |
$FFFFFA19 and $FFFFFA1B Timer A and Timer B Control
Bits 3-0 (Timer A) and bits 3-0 (Timer B):
0000 Timer stop
0001 Delay mode, divide by 4
0010 Delay mode, divide by 10
0011 Delay mode, divide by 16
0100 Delay mode, divide by 50
0101 Delay mode, divide by 64
0110 Delay mode, divide by 100
0111 Delay mode, divide by 200
1000 Event count mode
1xxx Pulse extension mode, divider as above
The MFP clock is 2.4576 MHz. With a divide by 10 prescale the
timer ticks at 245.76 kHz, a period of about 4.069 microseconds,
which is the usual choice for measuring short intervals.
Timer A is normally free on an STF and is the usual pick for
user timing. On an STE and TT it is used for DMA sound, so
save and restore the control register there.
Event count mode counts pulses on a GPIO pin rather than the
internal clock, which is how the Timer B display-line counting
trick works.
From the Atari Compendium.
$FFFFFA1B.B|RW|MFP_TBC|Timer B Control %____EBBB |
| | | Event Count Mode-------------------------1000 |
| | | Pulse Extension--------------------------1xxx |
| | | Delay------------------------------------0xxx |
$FFFFFA1D.B|RW|MFP_TDC|Timer C+D Control %_CCC_DDD | | | | Timer C Control-----------------------+++ ||| | | | | Timer D Control---------------------------+++ | | | | Stop Timer--------------------------------000 | | | | Delay,Clockdivide 4 3200Hz--------------001 | | | | Delay,Clockdivide 10 1280Hz--------------010 | | | | Delay,Clockdivide 16 800Hz--------------011 | | | | Delay,Clockdivide 50 256Hz--------------100 | | | | Delay,Clockdivide 64 200Hz--------------101 | | | | Delay,Clockdivide 100 128Hz--------------110 | | | | Delay,Clockdivide 200 64Hz--------------111 |
$FFFFFA1D MFP_TDC Timer C and D Control
Bits 6-4 Timer C control
Bits 2-0 Timer D control
Bits 7 and 3 unused
Both fields use the same encoding:
000 Timer stop
001 Delay mode, divide by 4
010 Delay mode, divide by 10
011 Delay mode, divide by 16
100 Delay mode, divide by 50
101 Delay mode, divide by 64
110 Delay mode, divide by 100
111 Delay mode, divide by 200
Timers C and D have no event count or pulse extension mode,
which is why they take three bits rather than four.
Timer C drives the 200 Hz system clock. Timer D is the USART
baud rate generator. Neither should be stopped by application
code.
From the Atari Compendium.
$FFFFFA1F.B|RW|MFP_TAD|Timer A Data |
$FFFFFA1F to $FFFFFA25 Timer Data Registers
$FFFFFA1F Timer A data
$FFFFFA21 Timer B data
$FFFFFA23 Timer C data
$FFFFFA25 Timer D data
Writing loads the timer's reload value. Reading returns the
current count, which decrements from the reload value toward
zero at the rate set by the prescale in the control register.
When the count reaches zero the timer raises its interrupt and
reloads automatically. A written value of 0 means 256.
Reading a running timer is how short intervals are measured:
note the value, do the work, read again and subtract.
From the Atari Compendium.
$FFFFFA21.B|RW|MFP_TBD|Timer B Data |
$FFFFFA23.B|RW|MFP_TCD|Timer C Data |
$FFFFFA25.B|RW|MFP_TDD|Timer D Data |
$FFFFFA27.B|RW|MFP_SYC|Synchronous Character |
$FFFFFA27 MFP_SYC Synchronous Character Register
Holds the character the USART searches for when running in
synchronous mode, selected by the stop bit field in the USART
control register at $FFFFFA29 being set to 00.
Not used on a standard Atari, which runs the RS-232 port
asynchronously.
$FFFFFA29.B|RW|MFP_UCR|Usart Control %DBBSSPE_ | | | | Divider 0:div1(sync),1:div16---------+|||||| | | | | Databits 00:8,01:7,10:6,11:5----------++|||| | | | | 00:sync,01:1stop,10:1.5stop,11:2stop----++|| | | | | Parity 0:off,1:on-------------------------+| | | | | Parity 0:odd,1:even------------------------+ |
$FFFFFA29 MFP_UCR USART Control Register
Bit 7 Clock divide: if set, divide by 16
Bits 6-5 Data bits:
00 = 8 bits 01 = 7 bits
10 = 6 bits 11 = 5 bits
Bits 4-3 Start and stop bits:
00 = synchronous
01 = 1 start, 1 stop
10 = 1 start, 1.5 stop
11 = 1 start, 2 stop
Bit 2 Parity enable: if clear, parity is ignored
Bit 1 Parity: 1 = even, 0 = odd
Bit 0 unused
Note the wiki summary line labels bits 4-3 as stop bits only;
the Compendium describes them as the combined start and stop
configuration.
From the Atari Compendium.
$FFFFFA2B.B|RW|MFP_RES|Receiver Status %BOPFSCPR | | | | Buffer full--------------------------+||||||| | | | | Overrun Error-------------------------+|||||| | | | | Parity Error---------------------------+||||| | | | | Frame Error-----------------------------+|||| | | | | SCR found/Break--------------------------+||| | | | | SCR received/Startbit detected------------+|| | | | | Synchronous Strip Enable-------------------+| | | | | Receiver Enable-----------------------------+ |
$FFFFFA2B MFP_RES Receiver Status Register
Bit 7 Buffer full
Bit 6 Overrun error
Bit 5 Parity error
Bit 4 Frame error
Bit 3 Search / break detected
Bit 2 Match / character in progress
Bit 1 Synchronous strip enable
Bit 0 Receiver enable
Bit 0 must be set before anything is received. Bits 7-4 are
status and are cleared by reading the data register.
From the Atari Compendium.
$FFFFFA2D.B|RW|MFP_TRS|Transmitter Status %BUAEBHLT | | | | Buffer Empty-------------------------+||||||| | | | | Underrun Error (char sent)------------+|||||| | | | | Auto Turnaround------------------------+||||| | | | | EOT End of Transmission-----------------+|||| | | | | Break------------------------------------+||| | | | | 00:High,01:Low,10:High,11:loopback,High---++| | | | | Transmitter Enable--------------------------+ |
$FFFFFA2D MFP_TRS Transmitter Status Register
Bit 7 Buffer empty
Bit 6 Underrun error
Bit 5 Auto turnaround
Bit 4 End of transmission
Bit 3 Break
Bit 2 High bit
Bit 1 Low bit
Bit 0 Transmitter enable
Bits 2-1 together set the idle state of the transmit line:
00 = high, 01 = low, 10 = high, 11 = loopback, high
Bit 0 must be set before anything is sent. Wait for bit 7 to
be set before writing the next byte to $FFFFFA2F.
From the Atari Compendium.
$FFFFFA2F.B|RW|MFP_UAD|Usart Data |
===========#==#=======#===============================================#=====
----------------------|FPC - Floating Point Coprocessor |-----
===========#==#=======#===============================================#=====
$FFFFFA40.W|RW|FPC_STA|Status (Response) Register |ME
$FFFFFA40 to $FFFFFA5C MC68881 Floating Point Coprocessor
interface (Mega STE)
These are not ordinary control registers: they are the
MC68881's Coprocessor Interface Registers (CIR), memory
mapped because the Mega STE's 68000 has no coprocessor
instructions of its own. Software drives the FPU by writing a
command to $FFFFFA4A, polling this Status register for the
FPU's response, and moving operands through $FFFFFA50. Each
register in the block has its own entry below.
$FFFFFA40 FPC_STA Status (Response) CIR
Read to find out what the coprocessor wants next. The value is
a RESPONSE PRIMITIVE, not a set of independent status bits:
Bit 15 CA, come again. Set means the main processor must
read this register again after servicing the
current primitive.
Bit 14 PC, pass program counter. The instruction address
must be sent to $FFFFFA58.
Bit 13 DR, direction. 0 = main processor to coprocessor,
1 = coprocessor to main processor, for the
transfer this primitive requests.
Bits 12-8 primitive type: null (busy or done), transfer
operation word, transfer single or multiple
operands, evaluate effective address, transfer
status/condition, take pre- or post-instruction
exception.
Bits 7-0 parameter: for transfer primitives, the number of
bytes to move; for exception primitives, the
vector number to take.
A null primitive with CA clear means the operation is
finished. A null primitive with CA set means the FPU is still
busy, so keep polling.
The full primitive encoding table is in the MC68881/68882
User's Manual, section 7 (coprocessor interface); it is a
protocol rather than a fixed bit map, so only the framing bits
above are reproduced here.
SOURCING NOTE: none of the listings in the audit set (Hollis
v7.0, which marks the whole block "???", the Hohwiller
listing, the Compendium, FALREG or the Aura documents) carries
any detail for these registers, and neither Hatari nor EmuTOS
implements the Mega STE FPU interface. The addresses and names
on this page match the standard Motorola CIR map exactly,
which is what confirms them; the per-register descriptions
below come from that map. Where a value can be checked against
code it has been: the state frame format words on $FFFFFA44
are confirmed in Hatari src/cpu/fpp.c.
The SFP004 accessory used the same CIR-mapped scheme at
$FFFFFA40 on the Mega ST, which is why some listings tag this
block Mega ST as well.
$FFFFFA42.W|RW|FPC_CTL|Control Register %______XA |ME
| | | eXception acknowledge----------------------+| |ME
| | | Abort the current operation-----------------+ |ME
$FFFFFA44.W|RW|FPC_SAV|Save Register (state frame format word) |ME
$FFFFFA44 FPC_SAV Save CIR
Read to begin an FSAVE. Returns the state frame format word,
which tells the main processor what kind of internal state
the FPU has and how many bytes must be copied out:
$0000 NULL frame, no context to save (FPU reset or
idle with nothing pending). Nothing further to
read.
version:$18 IDLE frame, MC68881. High byte is the FPU
version number, low byte the frame size in
bytes minus four.
version:$38 IDLE frame, MC68882 (larger internal state).
other BUSY frame, mid-instruction state.
Frame sizes confirmed in Hatari src/cpu/fpp.c, which writes
$1C for a 68881 and $3C for a 68882 (frame size, with the
size-minus-four value going into the format word) and treats
format word $00 as the null frame.
Reading this register also suspends the FPU, which is the
whole point of FSAVE: it freezes the coprocessor so the
operating system can context switch.
$FFFFFA46.W|RW|FPC_RES|Restore Register |ME
$FFFFFA46 FPC_RES Restore CIR
Write the state frame format word here to begin an FRESTORE,
then write back the frame body. Same format word encoding as
the Save register above.
Writing $0000 (the null frame) resets the coprocessor to the
idle state and discards any saved context, which is how TOS
and most FPU drivers initialise the part.
Writing a format word the FPU does not recognise makes it
signal a format error, which the main processor reports as an
F-line or format exception.
$FFFFFA48.W|RW|FPC_OPW|Operation Word Register |ME
$FFFFFA48 FPC_OPW Operation Word CIR
The main processor writes the F-line instruction's FIRST word
(the operation word, $F2xx for coprocessor ID 1) here when the
FPU asks for it with a "transfer operation word" response
primitive. The FPU needs it to work out the addressing mode
the instruction used.
Not used for every instruction: only when the response
primitive in the Status register requests it.
$FFFFFA4A.W|RW|FPC_CMD|Command Register |ME
$FFFFFA4A FPC_CMD Command CIR
Writing the command word here STARTS an operation. It takes
the second word of the F-line instruction, which encodes the
FPU operation, source and destination registers and data
format (for example FADD, FMUL, FMOVE with an extended,
double, single, packed or integer operand).
After the write, poll the Status register at $FFFFFA40 for
the FPU's response primitive, which says what to do next:
transfer an operand through $FFFFFA50, transfer the operation
word, take an exception, or nothing further (operation
complete).
This is the register the whole interface revolves around: no
write here, no FPU activity.
$FFFFFA4C.W|RW| - |Reserved |ME
$FFFFFA4E.W|RW|FPC_CCR|Condition Code Register |ME
$FFFFFA4E FPC_CCR Condition CIR
Used by the conditional instructions FBcc, FScc, FDBcc and
FTRAPcc. The main processor writes the condition predicate
(the low 6 bits of the instruction's condition field, giving
the 32 IEEE conditions plus the unordered variants) and the
FPU evaluates it against the current floating point condition
codes.
The result comes back through the Status register as a "take
branch / do not take branch" response primitive, not as a bit
in this register. The main processor then acts on the branch
itself, since the FPU has no program counter.
A NaN operand makes the unordered conditions true and can
raise the BSUN exception, which is why the predicate matters
rather than a simple true/false test.
$FFFFFA50.L|RW|FPC_OPR|Operand Register |ME
$FFFFFA50 FPC_OPR Operand CIR
The 32 bit data port. Every operand and result passes through
here, a longword at a time, in the direction and count the
response primitive in the Status register specifies:
single precision 1 longword
double precision 2 longwords
extended precision 3 longwords
packed decimal 3 longwords
integer 1 longword (byte and word operands are
sign extended into it)
Transfers must be done in the order and quantity requested;
reading or writing more longwords than the primitive asked
for confuses the interface protocol.
This is the only register in the block that is a longword
port rather than a control word.
$FFFFFA54.W|RW|FPC_SEL|Register Select |ME
$FFFFFA54 FPC_SEL Register Select CIR
Read after a "transfer multiple registers" response primitive
(FMOVEM). Returns a bit mask, one bit per floating point data
register FP0 to FP7, saying which registers the main processor
must move through the Operand register and in which order.
For the control register form of FMOVEM the mask instead
selects among FPCR, FPSR and FPIAR.
Only meaningful immediately after the primitive that requests
it; reading it at any other time returns nothing useful.
$FFFFFA56.W|RW| - |Reserved |ME
$FFFFFA58.L|RW|FPC_IAR|Instruction Address Register |ME
$FFFFFA58 FPC_IAR Instruction Address CIR
The main processor writes the ADDRESS of the F-line
instruction currently being executed, when the FPU requests it
with a "transfer instruction address" response primitive.
The FPU keeps it in FPIAR so that an exception handler can
find the instruction that faulted. Without it the FPU would
have no way to report where an error happened, since it never
sees the program counter.
$FFFFFA5C.L|RW|FPC_OAR|Operand Address Register |ME
$FFFFFA5C FPC_OAR Operand Address CIR
Carries the effective ADDRESS of a memory operand, rather than
the data itself. Used by the "evaluate effective address and
transfer data" and "take pre-instruction exception" response
primitives, so the FPU can tell the main processor where to
fetch from or store to, and so that an exception frame can
record the faulting operand address.
Written by the main processor when the primitive asks for it;
read back when the FPU supplies an address.
===========#==#=======#===============================================#=====
----------------------|MFP 68901 number 2 |-----
===========#==#=======#===============================================#=====
$FFFFFA81.B|RW|MF2_PDR|Parallel Port Data Register (GPIP) %SRD_ISGG |TT
$FFFFFA81 MF2_PDR Second MFP GPIP (TT)
The TT's second MC68901. The register set and every bit layout
are identical to the first MFP at $FFFFFA01 onwards, on the
same odd-address spacing; see the entries there for the bit
detail of the AER, DDR, interrupt, timer and USART registers.
Only the GPIP pin wiring differs:
Bit 7 SCSI controller interrupt (NCR 5380)
Bit 6 RTC interrupt (MC146818A)
Bit 5 SCSI DMAC interrupt
Bit 4 Reserved
Bit 3 RS-232 Ring Indicator (SCC channel B)
Bit 2 SCC-DMA controller interrupt
Bit 1 General purpose input GPI 1
Bit 0 General purpose input GPI 0
The pin map follows the second MFP vector table at $00000140
to $0000017C (see the System variables page) and the Atari
Compendium's TT MFP list. Bits 7 and 5 are confirmed in
EmuTOS bios/scsi.c, which polls TT_MFP gpip bit 7 for the
5380 interrupt and bit 5 for the SCSI DMAC interrupt.
This MFP's interrupts use their own block of 16 vectors: TOS
programs the MF2 vector register with base $50, so vector
numbers $50-$5F land at addresses $00000140 to $0000017C.
$FFFFFA83.B|RW|MF2_AER|Active Edge Register |TT
$FFFFFA85.B|RW|MF2_DDR|Data Direction Register |TT
$FFFFFA87.B|RW|MF2_IEA|Interrupt Enable A |TT
$FFFFFA89.B|RW|MF2_IEB|Interrupt Enable B |TT
$FFFFFA8B.B|RW|MF2_IPA|Interrupt Pending A |TT
$FFFFFA8D.B|RW|MF2_IPB|Interrupt Pending B |TT
$FFFFFA8F.B|RW|MF2_ISA|Interrupt In-Service A |TT
$FFFFFA91.B|RW|MF2_ISB|Interrupt In-Service B |TT
$FFFFFA93.B|RW|MF2_IMA|Interrupt Mask A |TT
$FFFFFA95.B|RW|MF2_IMB|Interrupt Mask B |TT
$FFFFFA97.B|RW|MF2_VCR|Vector Register |TT
$FFFFFA99.B|RW|MF2_TAC|Timer A Control |TT
$FFFFFA9B.B|RW|MF2_TBC|Timer B Control |TT
$FFFFFA9D.B|RW|MF2_TDC|Timer C+D Control |TT
$FFFFFA9F.B|RW|MF2_TAD|Timer A Data |TT
$FFFFFAA1.B|RW|MF2_TBD|Timer B Data |TT
$FFFFFAA3.B|RW|MF2_TCD|Timer C Data |TT
$FFFFFAA5.B|RW|MF2_TDD|Timer D Data |TT
$FFFFFAA7.B|RW|MF2_SCR|Synchronous Character Register |TT
$FFFFFAA9.B|RW|MF2_UCR|USART Control Register |TT
$FFFFFAAB.B|RW|MF2_RSR|Receiver Status Register |TT
$FFFFFAAD.B|RW|MF2_TSR|Transmitter Status Register |TT
$FFFFFAAF.B|RW|MF2_UAD|USART Data Register |TT
===========#==#=======#===============================================#=====
----------------------|ACIA 6850 (Midi/Keyboard) |-----
===========#==#=======#===============================================#=====
$FFFFFC00.B|R-|KBD_CTL|IKBD Status %IPOFCDTR |
$FFFFFC00 KBD_CTL IKBD ACIA Status (read) / Control (write)
READ - status:
Bit 7 Interrupt request
Bit 6 Parity error
Bit 5 Receiver overrun
Bit 4 Frame error
Bit 3 Clear to send
Bit 2 Data carrier detect
Bit 1 Transmit data register full
Bit 0 Receive data register full
WRITE - control:
Bit 7 Enable receive interrupts
Bits 6-5 Transmitter interrupt configuration:
00 RTS low, interrupts disabled
01 RTS low, interrupts enabled
10 RTS high, interrupts disabled
11 RTS low, interrupts disabled, send break
Bits 4-2 Word format, data bits - parity - stop bits:
000 7-E-2 001 7-O-2
010 7-E-1 011 7-O-1
100 8-N-2 101 8-N-1
110 8-E-1 111 8-O-1
Bits 1-0 Clock divide:
00 divide by 1 (500000 cps)
01 divide by 16 (31250 cps, MIDI standard)
10 divide by 64 (7812.5 cps, IKBD)
11 master reset
The IKBD is set to $96: 7 bits, no parity, 1 stop, divide by
64, RTS low, receive interrupts on.
The MIDI ACIA at $FFFFFC04 uses the same register layout and
is set to $95, the same but divide by 16.
From the Atari Compendium.
" |-W|KBD_CTL|IKBD Control %ITTBSPDD |
| | | 7N1,7812.5,RTS low,Rec on,Send off= %10010110 |*
$FFFFFC02.B|RW|KBD_DAT|IKBD Data |
$FFFFFC04.B|R-|MID_CTL|MIDI Status %IPOFCDTR |
| | | Interrupt Request--------------------+||||||| |
| | | Parity Error--------------------------+|||||| |
| | | Receiver Overrun-----------------------+||||| |
| | | Frame Error-----------------------------+|||| |
| | | CTS Clear to Send------------------------+||| |
| | | DCD Data Carrier Detect-------------------+|| |
| | | Transmitter Data Register full-------------+| |
| | | Receiver Data Register full-----------------+ |
" |-W|MID_CTL|MIDI Control %ITTBSPDD |
| | | 7N1,31250,RTS low,Rec on,Send off = %10010101 |*
| | | Interrupt 0:off,1:on-----------------+||||||| |
| | | RTS low, TransmitIRQ off--------------00||||| |
| | | RTS low, TransmitIRQ on---------------01||||| |
| | | RTS high,TransmitIRQ off--------------10||||| |
| | | RTS low, TransmitIRQ off,send break---11||||| |
| | | 8 Databits,2 Stopbits,Parity even-------000|| |
| | | 8 Databits,2 Stopbits,Parity odd--------001|| |
| | | 8 Databits,1 Stopbits,Parity even-------010|| |
| | | 8 Databits,1 Stopbits,Parity odd--------011|| |
| | | 7 Databits,2 Stopbits,Parity off--------100|| |
| | | 7 Databits,1 Stopbits,Parity off--------101|| |
| | | 7 Databits,1 Stopbits,Parity even-------110|| |
| | | 7 Databits,1 Stopbits,Parity odd--------111|| |
| | | Clockdivide 1 - 500000.0cps---------------00 |
| | | Clockdivide 16 - 31250.0cps (MIDI Std)----01 |
| | | Clockdivide 64 - 7812.5cps (IKBD!)-------10 |
| | | Master Reset-------------------------------11 |
$FFFFFC06.B|RW|MID_DAT|MIDI Data |
===========#==#=======#===============================================#=====
----------------------|RP5C15 Real Time Clock |-----
===========#==#=======#===============================================#=====
$FFFFFC21.B|RW| - |Seconds mod 10 %____xxxx |MST
$FFFFFC21 to $FFFFFC39 RP5C15 Clock Registers, Bank 0 and Bank 1
IMPORTANT: this chip has TWO banks of registers at the same
addresses. Bit 0 of the mode register at $FFFFFC3B selects
which bank is visible. The wiki listing documents only Bank 0.
Address Bank 0 Bank 1
$FFFFFC21 Seconds ones (0-9) Clock output frequency
$FFFFFC23 Seconds tens (0-5) Reset seconds (see below)
$FFFFFC25 Minutes ones (0-9) Alarm minutes ones
$FFFFFC27 Minutes tens (0-5) Alarm minutes tens
$FFFFFC29 Hours ones (0-9) Alarm hours ones
$FFFFFC2B Hours tens (0-2) Alarm hours tens
$FFFFFC2D Day of week (0-6) Alarm day of week
$FFFFFC2F Date ones (0-9) Alarm date ones
$FFFFFC31 Date tens (0-3) Alarm date tens
$FFFFFC33 Month ones (0-9) not used
$FFFFFC35 Month tens (0-1) 12/24 hour select
$FFFFFC37 Year ones (0-9) Leap year register (0-3)
$FFFFFC39 Year tens (0-9) not used
All values are BCD digits, one digit per register, low nibble
only.
Bank 0 notes:
Day of week: 0 = Sunday.
Hours tens in 12 hour mode is 0-1, with bit 1 set for PM.
Year is stored as (year - 1980).
Bank 1 notes:
$FFFFFC21 clock output frequency:
0 = open collector CLKOUT 4 = 16 Hz
1 = 16384 Hz 5 = 1 Hz
2 = 1024 Hz 6 = 1/60 Hz
3 = 128 Hz 7 = open collector CLKOUT
$FFFFFC23: setting bit 0 resets the seconds register to zero,
and if seconds were between 30 and 59 it also increments
the minutes register. This is the "round to nearest minute"
function.
$FFFFFC35: bit 1 set = 24 hour mode, clear = 12 hour mode.
$FFFFFC37 leap year register: 0 = this is a leap year.
Mega ST only. From the Atari Compendium.
$FFFFFC23.B|RW| - |Seconds div 10 %____xxxx |MST
$FFFFFC25.B|RW| - |Minutes mod 10 %____xxxx |MST
$FFFFFC27.B|RW| - |Minutes div 10 %____xxxx |MST
$FFFFFC29.B|RW| - |Hours mod 10 %____xxxx |MST
$FFFFFC2B.B|RW| - |Hours div 10 %____xxxx |MST
$FFFFFC2D.B|RW| - |Weekday %____xxxx |MST
$FFFFFC2F.B|RW| - |Day mod 10 %____xxxx |MST
$FFFFFC31.B|RW| - |Day div 10 %____xxxx |MST
$FFFFFC33.B|RW| - |Month mod 10 %____xxxx |MST
$FFFFFC35.B|RW| - |Month div 10 %____xxxx |MST
$FFFFFC37.B|RW| - |Year mod 10 %____xxxx |MST
$FFFFFC39.B|RW| - |Year div 10 %____xxxx |MST
$FFFFFC3B.B|RW| - |Clock mode %____xxxx |MST
$FFFFFC3B Mode Register
Bit 3 Timer enable: 0 = clock stopped
Bit 2 Alarm enable: 0 = alarm off
Bits 1-0 Bank select
Bit 0 is the one that matters: it chooses whether the register
block at $FFFFFC21 to $FFFFFC39 shows Bank 0 (the clock) or
Bank 1 (the alarm and configuration). See $FFFFFC21.
Stopping the clock with bit 3 is how a consistent multi
register read is done, since the counters would otherwise roll
over mid read.
Mega ST only. From the Atari Compendium.
$FFFFFC3D.B|RW| - |Clock test %____xxxx |MST
$FFFFFC3D Test Register
Lower nibble must read as zero for the chip to be considered
working correctly. Used for factory test.
Mega ST only. From the Atari Compendium.
$FFFFFC3F.B|RW| - |Clock reset %____xxxx |MST
$FFFFFC3F Reset Register
Bit 3 1 Hz alarm pulse: 0 = enabled
Bit 2 16 Hz alarm pulse: 0 = enabled
Bit 1 Alarm reset: 1 = reset the alarm registers
Bit 0 Clock reset: 1 = reset the clock registers
Writing the reset bits clears the corresponding register bank
to zero.
Mega ST only. From the Atari Compendium.
===========#==#=======#===============================================#=====
----------------------|Add-on and expansion area |-----
===========#==#=======#===============================================#=====
$FFFFFE00.W|RW| - |Add-on control / MonSTer register |*
$FFFFFE00 and $FFFFFE0E Add-on control
Not present on stock Atari hardware.
Known to be used by: SEC BOOSTER.
CONFLICT: EmuTOS uses this same address block for the MonSTer
expansion board. From EmuTOS source:
bios/machine.h MONSTER_REG $FFFFFE00
bios/clock.c MONSTER_I2C_DIR $FFFFFE02
bios/clock.c MONSTER_I2C_SCL $FFFFFE04
bios/clock.c MONSTER_I2C_SDA $FFFFFE06
MonSTer's main register is at exactly the same address as the
first SEC BOOSTER control register, and its I2C bus lines
occupy $FFFFFE02 to $FFFFFE06 immediately above.
EmuTOS only touches these when built with CONF_WITH_MONSTER
enabled, which is off by default. A stock EmuTOS build will
not write here. A MonSTer-enabled build will.
Anyone fitting both boards, or running a MonSTer-enabled
EmuTOS alongside a SEC BOOSTER, should expect trouble.
EmuTOS also carries CONF_WITH_MAGNUM and CONF_WITH_NOVA for
two further add-on boards; their address usage has not yet
been checked against this listing.
Extended bit information is not currently available for the
SEC BOOSTER side of these registers.
$FFFFFE0E.W|RW| - |Add-on control |*
===========#==#=======#===============================================#=====
$FFFFFF82.W|R-| - |Unknown status register |F
| | | CHECK: purpose unknown. The Aura FALC3.TXT |
| | | listing records it as two new Falcon read |
| | | registers, $FFFFFF82 reading $1C and |
| | | $FFFFFF83 reading $00, with no function |
| | | identified. Not referenced by Hatari, EmuTOS |
| | | or TOS source. |
===========#==#=======#===============================================#=====
$FFFF820D.B|RW|VDL_VBL|Video Base Lo %xxxxxxx_ |STE,F
----+---- | +- ---+--- ------------------+---------------------------- --+--
| | | | | |
| | | | | Computer Type---------------+
| | | | +---Description
| | | +--------------------------Label
| | +--------------------------------Read/Write Access
| +----------------------------------Type (Byte,Word,Long)
+----------------------------------------Address (extended to 32 Bit)
Computer Type:
* |Software defined Standard
!xxx|all except xxx
0x0 |MC680x0 only
0x0+|MC680x0 or higher
BLT |Standard on TT,STE,ME,F (Blitter)
SCC |Standard on TT,ME,F
VME |Standard on TT,ME
ST |Atari ST (260/520/1040)
STE |Atari STE (520/1040)
TT |Atari TT
MST |Atari Mega ST (1/2)
ME |Atari Mega STE
F |Atari Falcon
Read/Write Access:
R/-|Read only (read register)
-/W|Write only (write register)
R/?|Read access allowed
?/W|Write access allowed
r/?|Read access allowed but not sensible
?/w|Write access allowed but not sensible
Source precedence when documents disagree:
1. Live TOS source (th-otto/tos1x, th-otto/tos3x) and EmuTOS source.
Executable and hardware-validated; TOS is Atari's own code.
2. The Atari Compendium. Broad and careful, but not perfect.
3. Everything else, including this wiki's own history and the
Dan Hollis hardware register listing.
Entries marked UNVERIFIED rest on a single source only.