The complete memory map assembled from the six section pages into one
continuous listing. Nothing here is maintained directly: each section is
pulled in from its own page, so edits made there appear here automatically.
Use the section pages to edit; use this page to read or search the whole map
in one place.
Exception vectors and basic RAM & ROM locations
Maintained at Exception vectors and basic RAM & ROM locations
===========#==#=======#===============================================#=====
----------------------|Exception Vectors |-----
===========#==#=======#===============================================#=====
$00000000.L|R-|XPT_SPR|SSP after Reset |
$00000000 and $00000004 Reset vectors
$00000000 longword, supervisor stack pointer after reset
$00000004 longword, program counter after reset
These two are read from ROM, not RAM. At reset the memory
controller maps ROM to address zero so the 68000 fetches the
initial stack pointer and start address from there, then TOS
switches the mapping so RAM appears at zero.
Add-on ROM boards commonly claim $00000000 to $00000007 for
exactly this reason: to supply their own reset vectors and
take control before TOS.
From the Atari Compendium and Atari TOS bios/startup.S.
$00000004.L|R-|XPT_PCR|PC after Reset |
$00000008.L|RW|XPT_BUS|Bus Error |
$0000000C.L|RW|XPT_ADR|Address Error |
$00000010.L|RW|XPT_ILL|Illegal Instruction |
$00000014.L|RW|XPT_DBZ|Divide by Zero |
$00000018.L|RW|XPT_CHK|Chk, Chk2 Instruction |
$0000001C.L|RW|XPT_TRV|Trapv Instruction |
$00000020.L|RW|XPT_PRV|Privilege Violation |
$00000024.L|RW|XPT_TRC|Trace |
$00000028.L|RW|XPT_LNA|Line-A |
$00000028 and $0000002C Line-A and Line-F vectors
$00000028 longword, Line-A exception
$0000002C longword, Line-F exception
The 68000 traps any instruction whose top four bits are $A or
$F, since neither is a valid opcode.
Atari used Line-A for a set of fast low level graphics
routines, documented on the wiki as Line-A. Those were removed
on later machines, so anything using them must check the
machine type first.
Line-F is used by the 68881 and 68882 floating point
coprocessors. On a machine without an FPU it is free.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$0000002C.L|RW|XPT_LNF|Line-F |
$00000030.L|RW| - |reserved |
$00000034.L|RW|XPT_FPU|Coprocessor Protocol Violation |030+
$00000038.L|RW|XPT_FRM|Format Error |010+
$0000003C.L|RW|XPT_DSP|DSP Transfer Interrupt |*
$00000040.L|RW| - |reserved |
$00000044.L|RW| - |reserved |
$00000048.L|RW| - |reserved |
$0000004C.L|RW| - |reserved |
$00000050.L|RW| - |reserved |
$00000054.L|RW| - |reserved |
$00000058.L|RW| - |reserved |
$0000005C.L|RW| - |reserved |
$00000060.L|RW|XPT_SPU|Spurious Interrupt |
$00000064.L|RW|XPT_LV1|Level 1 - |
$00000068.L|RW|XPT_HBL|Level 2 - HBL |
$00000068 to $0000007C Auto-vector interrupts
$68 Level 2 HBL, horizontal blank
$70 Level 4 VBL, vertical blank
$78 Level 6 MFP 68901
Levels 1, 3, 5 and 7 exist in the table but are unused on a
standard ST. Level 5 is the SCC on machines that have one.
The VBL at level 4 is the one most software hooks, though the
supported route is the VBL queue at $00000456 rather than
taking the vector directly.
The MFP at level 6 is the busiest: every timer, the keyboard,
the floppy controller and the serial port all arrive through
it, dispatched by the MFP's own vector table at $00000100.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$0000006C.L|RW|XPT_LV3|Level 3 - |
$00000070.L|RW|XPT_VBL|Level 4 - VBL |
$00000074.L|RW|XPT_LV5|Level 5 - SCC |
$00000078.L|RW|XPT_LV6|Level 6 - MFP |
$0000007C.L|RW|XPT_LV7|Level 7 - |
$00000080.L|RW|XPT_T00|Trap #00 |
$00000084.L|RW|XPT_T01|Trap #01 - GEMDOS |
$00000080 to $000000BC Trap vectors
Trap #1 ($84) GEMDOS
Trap #2 ($88) AES and VDI
Trap #13 ($B4) BIOS
Trap #14 ($B8) XBIOS
The remaining twelve traps are unused by TOS and free for
application use, though some resident utilities claim them.
Function number is passed on the stack, not in a register.
Full call documentation is in tos.hyp rather than this map.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$00000088.L|RW|XPT_T02|Trap #02 - AES/VDI |
$0000008C.L|RW|XPT_T03|Trap #03 |
$00000090.L|RW|XPT_T04|Trap #04 |
$00000094.L|RW|XPT_T05|Trap #05 |
$00000098.L|RW|XPT_T06|Trap #06 |
$0000009C.L|RW|XPT_T07|Trap #07 |
$000000A0.L|RW|XPT_T08|Trap #08 |
$000000A4.L|RW|XPT_T09|Trap #09 |
$000000A8.L|RW|XPT_T10|Trap #10 |
$000000AC.L|RW|XPT_T11|Trap #11 |
$000000B0.L|RW|XPT_T12|Trap #12 |
$000000B4.L|RW|XPT_T13|Trap #13 - BIOS |
$000000B8.L|RW|XPT_T14|Trap #14 - XBIOS |
$000000BC.L|RW|XPT_T15|Trap #15 |
$000000C0.L|RW|FPU_BOS|FFCP Branch or Set |020+
$000000C4.L|RW|FPU_INX|FFCP Inexact Result |020+
$000000C8.L|RW|FPU_DBZ|FFCP Divide by Zero |020+
$000000CC.L|RW|FPU_UNR|FFCP Underflow |020+
$000000D0.L|RW|FPU_OPE|FFCP Operand Error |020+
$000000D4.L|RW|FPU_OVR|FFCP Overflow |020+
$000000D8.L|RW|FPU_NAN|FFCP signaling NAN |020+
$000000DC.L|RW| - |reserved |
$000000E0.L|RW|XPT_MMU|MMU Configuration Error |030+
$000000E4.L|RW| - |reserved |
$000000E8.L|RW| - |reserved |
$000000EC.L|RW| - |reserved |
$000000F0.L|RW| - |reserved |
$000000F4.L|RW| - |reserved |
$000000F8.L|RW| - |reserved |
$000000FC.L|RW| - |reserved |
$00000100.L|RW|XPT_CTR|B0 Centronics busy |*
$00000100 to $0000013C MFP interrupt vectors
The MFP 68901 supplies its own vector number, so its sixteen
interrupt sources each get a dedicated entry here rather than
sharing the level 6 auto-vector.
Which source maps to which vector is set by the MFP vector
register at $FFFFFA17, which holds the upper nibble of the
vector base. On the Atari that is $40, putting the sixteen
vectors at $40 to $4F, which are these addresses.
Priority runs from the top of the list down: B7 (FDC/HDC) is
higher priority than B0 (Centronics busy), and register A
sources outrank register B.
Enable, mask, pending and in-service for each source are
controlled by the MFP registers at $FFFFFA07 to $FFFFFA15.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$00000104.L|RW|XPT_DCD|B1 RS232 DCD |*
$00000108.L|RW|XPT_CTS|B2 RS232 CTS |*
$0000010C.L|RW|XPT_BLT|B3 Blitter Done |*BLT
$00000110.L|RW|XPT_T_D|B4 Timer D |*
$00000114.L|RW|XPT_T_C|B5 Timer C |*
$00000118.L|RW|XPT_KBD|B6 IKBD/MIDI |*
$0000011C.L|RW|XPT_FDC|B7 FDC/HDC |*
$00000120.L|RW|XPT_T_B|A0 Timer B |*
$00000124.L|RW|XPT_XMT|A1 Transmit Error |*
$00000128.L|RW|XPT_EMP|A2 Transmit Buffer empty |*
$0000012C.L|RW|XPT_REC|A3 Receive Error |*
$00000130.L|RW|XPT_FUL|A4 Receive Buffer full |*
$00000134.L|RW|XPT_T_A|A5 Timer A |*
$00000138.L|RW|XPT_RNG|A6 RS232 Ring Indicator |*
$0000013C.L|RW|XPT_SND|A7 Monochrome Detect/Audio Subsystem |*
$00000140.L|RW| - |User defined Vectors |
...........|RW| - |.................... |
$000003FC.L|RW| - |User defined Vectors |
| | | CHECK: $140-$17C are the TT MFP vectors and |
| | | $180-$1BC the SCC vectors on machines that |
| | | have them; $380-$3CC is the TOS exception |
| | | crash save area. Not all of this range is |
| | | genuinely user defined. |
===========#==#=======#===============================================#=====
----------------------|Random Access Memory |-----
===========#==#=======#===============================================#=====
$00000008.B|RW|RAM_TOP|RAM TOP |
...........|RW| - |....... |
$00CFFFFF.B|RW|RAM_END|RAM END |
===========#==#=======#===============================================#=====
----------------------|Alternative RAM (add-on boards) |-----
===========#==#=======#===============================================#=====
$00400000.B|RW|ALT_TOP|Alt-RAM TOP, add-on boards |*
$00400000 onward Alternative RAM
Alt-RAM on the ST range conventionally starts at the 4MB mark,
$00400000, immediately above the 4MB of ST RAM a stock machine
can address.
Common fits:
$00400000 to $007FFFFF 4MB
$00400000 to $00BFFFFF 8MB, the usual size
$00400000 to $00DFFFFF 10MB
Boards exist that go higher.
The address range above the alt-RAM area is nominally VME bus
space on machines that have it, the TT and Mega STE. That
allocation should stand. In practice, on machines with no VME
bus fitted or with VME unused, alt-RAM boards sometimes extend
into that range as well.
THE VME OVERLAP, now confirmed. On a Mega STE the VME bus
address space begins at $00A00000, so it does NOT sit above
the alt-RAM area, it sits INSIDE it:
4MB fit $00400000-$007FFFFF no overlap
8MB fit $00400000-$00BFFFFF overlaps VME from $00A00000
10MB fit $00400000-$00DFFFFF covers the whole VME range
So an 8MB or larger alt-RAM board on a Mega STE is using
address space the VME bus would otherwise claim. That is
workable when no VME card is fitted, which is the usual case,
but the two cannot coexist at those addresses.
The TT is unaffected: its VME space is at $FE000000, well
clear of alt-RAM.
Ranges confirmed by Hatari src/scu_vme.c, which cites the
Atari TT030 Hardware Reference Manual (June 1990) and the
Atari Profibuch ST-STE-TT chapter 9 (1991), and independently
by the Atari Compendium.
This is separate from TT RAM on the TT and Falcon, which lives
at $01000000 and is reported through the ramtop system
variable at $000005A4, validated by ramvalid at $000005A8.
Known to be used by: FLASHY CLOCK, SEC BOOSTER.
...........|RW| - |............ |*
$00DFFFFF.B|RW|ALT_END|Alt-RAM END, largest fit seen |*
===========#==#=======#===============================================#=====
----------------------|VME Bus Address Space |-----
===========#==#=======#===============================================#=====
$00A00000.B|RW|VME_A24|VMEbus A24:D16 addressable area TOP |ME
$00A00000 onward VME Bus Address Space
The VME bus is fitted to the Mega STE and TT only. Two address
windows are provided on each, one for 24 bit VME addressing
and a smaller one for 16 bit.
Mega STE:
$00A00000 to $00DEFFFF VMEbus A24:D16
$00DF0000 to $00DFFFFF VMEbus A16:D16
TT:
$FE000000 to $FEFEFFFF VMEbus A24:D16
$FEFF0000 to $FEFFFFFF VMEbus A16:D16, shadow image
All transfers are word based, D16. The Mega STE window is the
more limited of the two.
IMPORTANT: on the Mega STE this space overlaps the range used
by alt-RAM boards of 8MB and larger. See the alt-RAM entry
above.
The VME control registers are separate and live in the I/O
area at $FFFF8E01 to $FFFF8E0F, documented on the MFP, RTC and
anything else page. Those cover the interrupt mask, interrupt
state and the two forced interrupt registers, alongside the
SCU general purpose registers.
From the TT hardware reference, VME SYSFAIL generates a
motherboard IRQ7 to the processor but does not generate an
IRQ7 back onto the VME bus. SCU generated IRQ1 and IRQ3 are
always auto vectored; only interrupts 5 and 6 have external
IACK pins and can produce vectored interrupts.
Ranges and interrupt behaviour from Hatari src/scu_vme.c,
citing the Atari TT030 Hardware Reference Manual (June 1990)
and the Atari Profibuch ST-STE-TT chapter 9 (1991).
Cross-checked against the Atari Compendium.
...........|RW| - |............................... |ME
$00DEFFFF.B|RW| - |VMEbus A24:D16 addressable area END |ME
$00DF0000.B|RW|VME_A16|VMEbus A16:D16 addressable area TOP |ME
...........|RW| - |............................... |ME
$00DFFFFF.B|RW| - |VMEbus A16:D16 addressable area END |ME
$FE000000.B|RW|VME_T24|VMEbus A24:D16 addressable area TOP |TT
...........|RW| - |............................... |TT
$FEFEFFFF.B|RW| - |VMEbus A24:D16 addressable area END |TT
$FEFF0000.B|RW|VME_T16|VMEbus A16:D16 area TOP, shadow image |TT
...........|RW| - |............................... |TT
$FEFFFFFF.B|RW| - |VMEbus A16:D16 area END |TT
===========#==#=======#===============================================#=====
----------------------|TT RAM (Fast RAM) |-----
===========#==#=======#===============================================#=====
$01000000.B|RW|TTR_TOP|TT Fast RAM TOP |TT,F
$01000000 onward TT RAM (Fast RAM)
Present on the TT and Falcon. Physically separate from ST RAM
and connected directly to the processor rather than through
the video and DMA hardware.
$01000000 to $01FFFFFF TT Fast RAM, up to 16MB
$02000000 to $FDFFFFFF Reserved
IMPORTANT: TT RAM is UNSUITABLE for direct DMA and Shifter
transfers. It cannot be used for screen memory, and it cannot
be the target or source of a DMA transfer. Anything going to
or from disk, or being displayed, has to live in ST RAM. This
is the single most important thing to know about it.
What it is good for is code and data, where the lack of
contention with the video hardware makes it appreciably faster
than ST RAM.
The top of installed TT RAM is reported in the system variable
ramtop at $000005A4, validated by ramvalid at $000005A8
holding $1357BD13. A zero ramtop means no TT RAM is fitted.
GEMDOS tracks it through a second memory descriptor chained
from themd at $0000048E, which is why Malloc can hand out
either kind. Mxalloc lets a program ask for one specifically.
CONFLICT on the extent: the Atari Compendium gives the range
as $01000000 to $01FFFFFF, 16MB. The older Hardware Register
Listing page gives $01000000 to $013FFFFF, 4MB. The larger
figure is most likely the architectural maximum and the
smaller one a common fitted size, but this has not been
confirmed.
Note this is entirely separate from alt-RAM on add-on boards
for the ST and STE, which lives at $00400000. See the
alternative RAM entry above.
Range and the DMA restriction from the Atari Compendium.
...........|RW| - |............... |TT,F
$01FFFFFF.B|RW|TTR_END|TT Fast RAM END |TT,F
$02000000.B|--| - |Reserved |
...........|--| - |........ |
$FDFFFFFF.B|--| - |Reserved |
| | | CHECK: was annotated "14MB". $00CFFFFF is |
| | | 13MB. For 14MB, RAM should end at $00DFFFFF. |
| | | Either the address or the size is wrong. |
===========#==#=======#===============================================#=====
----------------------|1MB System Read Only Memory |-----
===========#==#=======#===============================================#=====
$00E00000.B|R-|ROM_TOP|1MB ROM TOP |F
$00E00000 onward System ROM
$00E00000 to $00EFFFFF 1MB ROM area, Falcon and TT
$00FC0000 to $00FEFFFF 192KB ROM area, ST and STE
The ST and STE map their 192KB ROM at $00FC0000. The TT and
Falcon use a larger 1MB region starting at $00E00000.
ADD-ON BOARDS: ROM expansion boards commonly claim
$00E00000 to $00E3FFFF for their own 256KB ROM, and some add a
flash area at $00E40000 to $00E7FFFF. Known to be used by
FLASHY CLOCK, TRUDIE and SEC BOOSTER. Such boards also take
the reset vectors at $00000000 to $00000007 and the 192KB
region at $00FC0000 to $00FEFFFF.
CHECK: the wiki listing gives the 1MB ROM area as ending at
$00F0003F, which is 1MB plus 64 bytes. For exactly 1MB the
end would be $00EFFFFF.
Extended bit information is not currently available for the
add-on ROM and flash areas.
...........|R-| - |........... |F
$00F0003F.B|R-|ROM_END|1MB ROM END |F
$00E40000.B|R-|FLA_TOP|Flash space TOP, add-on boards |*
$00E40000 to $00E7FFFF Flash space, add-on boards
Not present on stock Atari hardware. 256KB of flash memory
fitted by some ROM expansion boards, sitting immediately above
the add-on ROM area at $00E00000 to $00E3FFFF.
Known to be used by: FLASHY CLOCK.
Extended bit information is not currently available.
...........|R-| - |............... |*
$00E7FFFF.B|R-|FLA_END|Flash space END |*
| | | CHECK: $00E00000 to $00F0003F is 1MB plus 64 |
| | | bytes. For exactly 1MB the end would be |
| | | $00EFFFFF. |
===========#==#=======#===============================================#=====
$00F00040.B|--| - |Illegal Address Space |
...........|--| - |..................... |
$00F9FFFF.B|--| - |Illegal Address Space |
===========#==#=======#===============================================#=====
----------------------|128KB Expansion Cartridge Port |-----
===========#==#=======#===============================================#=====
$00FA0000.L|R-|ROM_PRT|Cartridge Magic($FA52235F=Diag,$ABCDEF42=User*)|
$00FA0000 to $00FBFFFF Cartridge port, 128KB
$00FA0000 longword, cartridge magic
$00FA0004 longword, entry point for a diagnostic cartridge
Two magic values are recognised, and Atari's own TOS source
tests both:
$FA52235F diagnostic cartridge. Tested very early in
bios/startup.S, before RAM is even sized, and
jumped to immediately if found.
$ABCDEF42 normal application cartridge. Tested later, once
the system is up.
A diagnostic cartridge therefore takes control before almost
anything else, which is what makes it useful for hardware
fault finding on a machine that will not boot.
Magic values confirmed in Atari TOS bios/startup.S, which
compares against both.
$00FA0004.L|R-|ROM_CAL|Call Diagnostic Cartridge |
...........|R-| - |............ |
$00FBFFFF.B|R-| - |ROM Port END |
===========#==#=======#===============================================#=====
----------------------|192KB System Read Only Memory |-----
===========#==#=======#===============================================#=====
$00FC0000.B|--| - |192KB ROM TOP |ST
...........|--| - |............. |ST
$00FEFFFF.B|--| - |192KB ROM END |ST
Back to Memory Map for Atari ST,STE,TT and Falcon
System variables and low RAM
Maintained at System variables and low RAM
===========#==#=======#===============================================#=====
----------------------|TT MFP Vectors |-----
===========#==#=======#===============================================#=====
$00000140.L|RW|TTMFP00|GPI 0 |TT
$00000144.L|RW|TTMFP01|GPI 1 |TT
$00000148.L|RW|TTMFP02|SCC-DMA Controller |TT
$0000014C.L|RW|TTMFP03|Ring Indicator SCC B |TT
$00000150.L|RW|TTMFP04|Timer D (RS232 baud rate generator) |TT
$00000154.L|RW|TTMFP05|Timer C (SCC TRxCB) |TT
$00000158.L|RW|TTMFP06|Reserved, GPI 4 |TT
$0000015C.L|RW|TTMFP07|SCSI DMA Controller |TT
$00000160.L|RW|TTMFP08|Timer B |TT
$00000164.L|RW|TTMFP09|Send Error |TT
$00000168.L|RW|TTMFP10|Send buffer empty |TT
$0000016C.L|RW|TTMFP11|Receive error |TT
$00000170.L|RW|TTMFP12|Receive buffer full |TT
$00000174.L|RW|TTMFP13|Timer A |TT
$00000178.L|RW|TTMFP14|TT Clock (MC146818A) |TT
$0000017C.L|RW|TTMFP15|TT-SCSI Drive Controller NCR 5380 |TT
===========#==#=======#===============================================#=====
----------------------|SCC Interrupt Vectors |-----
===========#==#=======#===============================================#=====
$00000180.L|RW| - |SCC Port B Transmit Buffer Empty |SCC
$00000184.L|RW| - |Unused |SCC
$00000188.L|RW| - |SCC Port B External Status Change |SCC
$0000018C.L|RW| - |Unused |SCC
$00000190.L|RW| - |SCC Port B Receive Character Available |SCC
$00000194.L|RW| - |Unused |SCC
$00000198.L|RW| - |SCC Port B Special Receive Condition |SCC
$0000019C.L|RW| - |Unused |SCC
$000001A0.L|RW| - |SCC Port A Transmit Buffer Empty |SCC
$000001A4.L|RW| - |Unused |SCC
$000001A8.L|RW| - |SCC Port A External Status Change |SCC
$000001AC.L|RW| - |Unused |SCC
$000001B0.L|RW| - |SCC Port A Receive Character Available |SCC
$000001B4.L|RW| - |Unused |SCC
$000001B8.L|RW| - |SCC Port A Special Receive Condition |SCC
$000001BC.L|RW| - |Unused |SCC
| | | CORRECTED: this table was previously built |SCC
| | | densely (4 consecutive different meanings per |SCC
| | | channel). The real layout is sparse, every |SCC
| | | other slot unused, confirmed by the Atari |SCC
| | | Compendium AND Atari's own TOS 2.06/3.06 |SCC
| | | source (tos3x bios/chardev.S, sccvect: table).|SCC
===========#==#=======#===============================================#=====
----------------------|Exception Crash Save Area |-----
===========#==#=======#===============================================#=====
$00000380.L|RW|PRCLIVE|Validates crash page, if $12345678 |
$00000380 to $000003CC Processor state save area
When TOS survives a crash it saves the processor state here
before displaying the bombs, so a debugger can recover it.
$380 proc_lives set to $12345678 if the save succeeded
$384 proc_dregs saved D0-D7, 32 bytes
$3A4 proc_aregs saved A0-A7, 32 bytes
$3C4 proc_enum the exception number that caused the crash
$3C8 proc_usp saved user stack pointer
$3CC proc_stk top 16 words from the exception stack frame
Only valid when proc_lives holds the magic value. TOS clears
it once the state has been read.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$00000384. |RW|PRCDREG|Saved registers D0-D7 (32 bytes) |
$000003A4. |RW|PRCAREG|Saved registers A0-A7 (32 bytes) |
$000003C4.L|RW|PRCENUM|Vector number of crash exception |
$000003C8.L|RW|PRC_USP|Saved user stack pointer |
$000003CC. |RW|PRC_STK|16 words from exception stack (32 bytes) |
===========#==#=======#===============================================#=====
----------------------|GEM Vectors |-----
===========#==#=======#===============================================#=====
$00000400.L|RW|ETVTIMR|etv_timer - GEM event timer vector |
$00000404.L|RW|ETVCRIT|etv_critic - GEM critical error handler |
$00000408.L|RW|ETVTERM|etv_term - GEM program termination vector |
$0000040C.L|RW|ETVXTRA|etv_xtra - 5 additional vectors, unused |
===========#==#=======#===============================================#=====
----------------------|System Variables |-----
===========#==#=======#===============================================#=====
$00000420.L|RW|MEMVALD|memvalid - memory conf valid if $752019F3 |
$00000420 memvalid Memory configuration valid flag
Longword. Holds $752019F3 when the memory configuration is
valid. Checked together with memval2 at $0000043A ($237698AA)
and memval3 at $0000051A ($5555AAAA).
If all three match, TOS trusts the existing memory setup and
performs a warm start. If any is wrong it runs the full memory
sizing routine, which is slower and clears RAM.
Clearing these is how a program forces a cold start.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$00000424.B|RW|MEMCTRL|memcntlr - copy of $FFFF8001 %____xxxx |
| | | Bank 0 size 00:128k,01:512k,10:2Mb-------+||| |
| | | Bank 1 size 00:128k,01:512k,10:2Mb---------+| |
$00000426.L|RW|RESVALD|resvalid - resvector valid if $31415926 |
$00000426 and $0000042A resvalid and resvector
$426 resvalid longword, magic number $31415926
$42A resvector longword, address to jump to
If resvalid holds $31415926 at reset time, TOS jumps through
resvector very early in the reset sequence, before most of the
system is initialised.
This is the standard hook for reset-resident code. The routine
must be extremely careful: almost nothing is set up yet.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$0000042A.L|RW|RESVECT|resvector - system reset bailout vector |
$0000042E.L|RW|PHYSTOP|phystop - physical top of ST RAM |
$0000042E to $00000436 Memory extent variables
$42E phystop longword, physical top of ST RAM
$432 _membot longword, lowest address available to the heap
$436 _memtop longword, highest address available to the heap
phystop is the real end of ST RAM as found by the memory
sizing routine. _membot and _memtop bracket the area GEMDOS
will allocate from, so they exclude the screen buffer and any
memory TOS has reserved for itself.
Alternative RAM (TT RAM, fast RAM) is tracked separately by
ramtop at $000005A4 and ramvalid at $000005A8.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$00000432.L|RW|_MEMBOT|_membot - bottom of TPA (user memory) |
$00000436.L|RW|_MEMTOP|_memtop - top of TPA (user memory) |
$0000043A.L|RW|MEMVAL2|memval2 - validates memcntlr if $237698AA |
$0000043E.W|RW|_FLOCK |flock - if <>0, VBL floppy routine is off |
$0000043E flock Floppy and DMA lock
Word. Set to a non-zero value before touching the DMA or FDC
registers directly, and clear it again afterwards.
While flock is non-zero the vertical blank floppy routine
leaves the hardware alone. If it is left clear, the VBL can
deselect the drive or disturb a transfer part way through.
This is the single most important variable to get right when
writing directly to the floppy hardware.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$00000440.W|RW|SEEKRAT|seekrate - floppy step rate %______xx |
| | | 0:6ms 1:12ms 2:2ms 3:3ms (WD1772)----------+| |
$00000440 seekrate Floppy drive step rate
Word. Sets the step rate for BOTH floppy drives.
0 = 6 ms
1 = 12 ms
2 = 2 ms
3 = 3 ms (default)
These values are written straight into the low two bits of a
WD1772 Type I command, so they are the chip's own encoding.
IMPORTANT: these are WD1772 values. The WD1770 uses 6, 12, 20
and 30 ms for the same four encodings, so values must never be
carried between the two chips.
On the Atari 3 ms is the normal setting. 2 ms works but gives
less reliable seeks in practice.
TOS declares this as _seekrate at $440 in common/tosvars.inc.
Values from the Atari Compendium, cross-checked against the
WD1772 command encoding.
$00000442.W|RW|TIMR_MS|_timr_ms - system timer calibration, ms |
$00000442 _timr_ms System timer period
Word. The interval between system timer ticks, in
milliseconds. Normally 20, giving the 50 Hz tick that drives
the GEM event timer.
Not the same as the 200 Hz counter at $000004BA, which is
driven directly by MFP Timer C.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$00000444.W|RW|FVERIFY|_fverify - if <>0, verify floppy writes |
$00000444 _fverify Floppy write verify flag
Word. When non-zero, every floppy write is read back and
compared. When zero, no verification is done.
Verification roughly doubles write time. TOS defaults it on.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$00000446.W|RW|BOOTDEV|_bootdev - default boot drive |
$00000446 _bootdev Boot device
Word. The device the system was booted from.
0 = A: 1 = B: 2 = C: and so on
Hatari writes this directly during machine setup
(src/stMemory.c: STMemory_WriteWord(0x446, nBootDrive)),
commented "Boot up on A(0) or C(2)".
TOS declares it as _bootdev at $446 in common/tosvars.inc.
Meaning from the Atari Compendium.
$00000448.W|RW|PALMODE|palmode - 0:NTSC(60Hz), else PAL(50Hz) |
$00000448 palmode Video standard flag
Word. Zero indicates NTSC (60 Hz) video, any other value
indicates PAL (50 Hz).
Reflects the state of the sync mode register at $FFFF820A
bit 1, which is set from the country code in the OS header.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$0000044A.B|RW|DEFSHFT|defshiftmd - default video resolution |
$0000044C.B|RW|SSHIFTM|sshiftmd - copy of $FFFF8260 %_____xxx |
| | | 0:low 1:medium 2:high resolution----------+|| |
$0000044C sshiftmd Shifter mode shadow
Byte. A copy of the hardware shift mode register at
$FFFF8260, kept so software can read the current resolution
without touching the hardware.
0 = low 320x200, 4 planes
1 = medium 640x200, 2 planes
2 = high 640x400, 1 plane
The related variable defshiftmd at $0000044A holds the
resolution to use at the next reset.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$0000044E.L|RW|V_BAS_A|_v_bas_ad - screen base address |
$0000044E _v_bas_ad Logical screen address
Longword. The address of the logical screen, the buffer that
drawing operations write into.
Before TOS 1.06 this had to be on a 256 byte boundary, since
the ST video base register has no low byte. From TOS 1.06 and
on an STE or later it can be any even address.
The physical screen, the one the shifter is actually reading,
is set by the video base registers at $FFFF8201, $FFFF8203 and
$FFFF820D. The two can point at different buffers, which is
how double buffering works.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$00000452.W|RW|_VBLSEM|vblsem - if >0, VBL routine is executed |
$00000452 to $0000045E Vertical blank control
$452 vblsem word, 0 disables all VBL processing, 1 enables
$454 nvbls word, number of slots in the VBL handler list
$456 _vblqueue longword, pointer to the list of handlers
$45A colorptr longword, palette to load at the next VBL
$45E screenpt longword, screen base to set at the next VBL
The VBL queue is an array of nvbls longword pointers. A zero
entry is skipped, so installing a handler means finding a free
slot and writing your routine's address into it.
colorptr and screenpt are one-shot: if non-zero at VBL time,
the value is used and the variable is cleared. That gives a
tear-free way to change palette or screen base.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$00000454.W|RW|_NVBLS |nvbls - number of VBL routines |
$00000456.L|RW|VBLQUEU|_vblqueue - pointer to list of VBL routines |
$0000045A.L|RW|COLORPT|colorptr - palette to load at next VBL |
$0000045E.L|RW|SCREENP|screenpt - video RAM base for next VBL |
$00000462.L|RW|VBCLOCK|_vbclock - count of VBL interrupts |
$00000462 and $00000466 Vertical blank counters
$462 _vbclock longword, VBLs actually processed
$466 frclock longword, VBLs that occurred
frclock counts every vertical blank. _vbclock counts only
those where processing was allowed to run, so the difference
between them is the number of VBLs blocked by vblsem.
Note the wiki label FRCLOCK matches Atari's own name; the
Atari Compendium calls the same variable _frlock.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$00000466.L|RW|FRCLOCK|frclock - count of unblocked VBL interrupts |
$0000046A.L|RW|HDVINIT|hdv_init - hard disk initialisation vector |
$0000046A to $0000047E Hard disk vectors
$46A hdv_init initialisation routine
$46E swv_vec called on a monitor resolution change
$472 hdv_bpb used by Getbpb()
$476 hdv_rw used by Rwabs()
$47A hdv_boot JSRed through to boot from hard disk
$47E hdv_mediach used by Mediach()
All longwords. A value of zero means no hard disk driver is
installed for that function.
These are the standard hook points a hard disk driver patches
during boot. swv_vec is the odd one out: it is called when the
system detects the monitor has been changed between colour and
monochrome.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$0000046E.L|RW|SWV_VEC|swv_vec - resolution change vector |
$00000472.L|RW|HDV_BPB|hdv_bpb - hard disk Getbpb vector |
$00000476.L|RW|HDV_RW |hdv_rw - hard disk read/write vector |
$0000047A.L|RW|HDVBOOT|hdv_boot - hard disk boot vector |
$0000047E.L|RW|HDVMEDC|hdv_mediach- hard disk media change vector |
$00000482.W|RW|CMDLOAD|_cmdload - if <>0, load COMMAND.PRG at boot |
$00000482 _cmdload Command shell load flag
Word. If non-zero at boot, the system attempts to load and run
COMMAND.PRG from the root of the boot drive instead of going
straight to the desktop.
Set by a boot sector or an AUTO folder program that wants to
replace the shell.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$00000484.B|RW|CONTERM|conterm - console attributes %____SBRK |
| | | Bconin returns shift status--------------+||| |
| | | System bell 0:off,1:on--------------------+|| |
| | | Key repeat 0:off,1:on----------------------+| |
| | | Key click 0:off,1:on------------------------+ |
$00000484 conterm Console attribute bits
Byte. A bit array controlling several console behaviours:
Bit 3 Cause Bconin() to return the shift status in the
high word of its return value
Bit 2 Enable system bell
Bit 1 Enable key repeat
Bit 0 Enable key click
Bit 3 is the useful one for anything reading the keyboard
directly: with it set, Bconin() returns the state of the
shift, control and alternate keys alongside the character.
The byte at $00000485 immediately after is reserved.
TOS declares this as _conterm at $484 in common/tosvars.inc,
described there as the attribute vector for console output.
Bit meanings from the Atari Compendium.
$00000485.B|RW| - |Reserved |
$00000486.L|RW|TRP14RT|trp14ret - trap #14 return address, unused |
$0000048A.L|RW|CRITRET|criticret - critical error handler return |
$0000048E. |RW|_THEMD |themd - first memory descriptor (16 bytes)|
$0000048E and $0000049E Memory descriptors
$48E themd first memory descriptor, 16 bytes
$49E _md longword, space for an additional descriptor
A memory descriptor block describes one contiguous region
GEMDOS may allocate from:
long m_link pointer to the next descriptor, 0 if last
long m_start start address of the region
long m_length length in bytes
long m_own owner process, 0 if free
On a machine with alternative RAM there are two descriptors,
one for ST RAM and one for TT RAM, chained through m_link.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$0000049E.L|RW|___MD |_md - space for additional descriptor |
$000004A2.L|RW|SAVPTR |savptr - pointer to BIOS register save area|
$000004A2 savptr BIOS register save area pointer
Longword. Points to the buffer the BIOS uses to save its
internal registers when re-entered.
Because the BIOS is not re-entrant, a routine that calls BIOS
functions from inside an interrupt must give it a separate
save area: allocate /2 bytes/, point savptr at it, make the
call, then restore savptr. Otherwise the interrupted call's
saved state is overwritten.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$000004A6.W|RW|_NFLOPS|nflops - number of floppy drives attached |
$000004A6 _nflops Number of floppy drives
Word. The number of floppy drives actually connected, 0, 1
or 2.
This is the variable to test for a second physical drive.
_drvbits at $000004C2 always shows both A and B set when any
floppy is present, because of virtual drive swapping.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$000004A8.L|RW|CONSTAT|con_state - vector for screen output |
$000004A8 and $000004AC Console state
$4A8 con_state longword, vector to the current console
output routine
$4AC save_row word, temporary store for the cursor row
con_state is switched between several internal routines as the
console works through a VT-52 escape sequence, so its value
depends on how much of a sequence has been received.
save_row holds the cursor row while an ESC-Y cursor
positioning sequence is being decoded, since the row arrives
before the column.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$000004AC.W|RW|SAVEROW|save_row - temporary cursor line storage |
$000004AE.L|RW|SAVCTXT|sav_context- exception processing save area |
$000004B2. |RW|_BUFL |bufl - 2 GEMDOS buffer list heads(8bytes)|
$000004B2 bufl GEMDOS buffer list heads
Two longwords, 8 bytes total.
$4B2 pointer to the data sector buffer list
$4B6 pointer to the FAT and directory sector buffer list
Each points to a chain of buffer control blocks GEMDOS uses to
cache disk sectors. Walking these chains is how disk cache
utilities find and flush TOS's own buffers.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$000004BA.L|RW|_HZ_200|hz_200 - 200 Hz system clock counter |
$000004BA _hz_200 200 Hz system counter
Longword. Increments 200 times a second, driven directly by
MFP Timer C. Free running from power on.
The most useful timing reference available without touching
hardware: read it, do the work, read it again and subtract.
Resolution is 5 ms.
Also commonly used as a random number seed.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$000004BE.L|RW|THE_ENV|the_env - default environment string |
$000004C2.L|RW|DRVBITS|_drvbits - bit map of mounted drives |
$000004C2 _drvbits Connected drive bitmap
Longword. One bit per drive letter:
Bit 0 = A:, bit 1 = B:, through to bit 25 = Z:
A set bit means that drive exists.
Note: if at least ONE floppy drive is connected, BOTH the A
and B bits are always set. This is because of virtual drive
swapping, where a single physical drive answers as both A and
B with a disk change prompt. Testing bit 1 does not tell you
whether a second physical drive is fitted; use nflops at
$000004A6 for that.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$000004C6.L|RW|DSKBUFP|_dskbufp - pointer to 1K disk buffer |
$000004C6 and $000004CA Disk buffer and autoexec path
$4C6 _dskbufp longword, pointer to a 1K disk buffer
$4CA _autopath longword, pointer to the AUTO folder path
The 1K buffer at _dskbufp is used by TOS for disk operations
and is also borrowed by some graphics routines. It is safe to
use as scratch space between disk calls, but not across one.
_autopath points to the GEMDOS path specification of the
directory programs are loaded from at boot.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$000004CA.L|RW|AUTOPAT|_autopath - pointer to autoexec path |
$000004CE. |RW|VBLLIST|_vbl_list - 8 VBL routine pointers (32 bytes) |
$000004EE.W|RW|DUMPFLG|_dumpflg - screen dump flag |
$000004EE and $000004F0 Screen dump control
$4EE _dumpflg word, screen dump flag
$4F0 prtabt word, printer abort flag
_dumpflg is initialised to $FFFF. The ALT-HELP screen dump
code sets it to 0 while a dump is in progress and back to
$FFFF when finished, so setting it to 0 yourself prevents a
dump starting.
Note: the Atari Compendium calls the variable at $4EE
_prt_cnt. Atari's own TOS source calls it _dumpflg, which is
the name used here.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$000004F0.W|RW|_PRTABT|prtabt - printer abort flag |
$000004F2.L|R-|SYSBASE|_sysbase - pointer to start of OS |
$000004F2 _sysbase Pointer to the operating system
Longword. Points to the start of TOS in memory, which begins
with the OS header structure:
Offset Size Field Meaning
$00 word os_entry BRA.S to the reset handler
$02 word os_version TOS version number
$04 long reseth pointer to the reset handler
$08 long os_beg base address of the OS
$0C long os_end end of ST-RAM used by the OS
$10 long os_rsv1 reserved, default UI entry point
$14 long os_magic GEM memory usage parameter block
$18 long os_date TOS date
$1C word os_conf PAL flag and country code
$1E word os_dosdate TOS date in GEMDOS format
$20 long os_root BDOS quick pool pointer (1.2+)
$24 long os_kbshift pointer to the shift state (1.2+)
$28 long os_run pointer to current basepage(1.2+)
$2C long reserved (1.2+)
The last four fields only exist from TOS 1.2 onward. Check
os_version before reading them.
os_version is BCD: $0102 is TOS 1.02, $0404 is TOS 4.04.
CONFLICT on os_date format: the Atari Compendium gives it as
$YYYYMMDD. EmuTOS include/biosdefs.h comments it as BCD
MMDDYYYY. Not resolved here.
EmuTOS note: EmuTOS puts the ASCII signature 'ETOS' in the
final longword at offset $2C, where real TOS leaves it
reserved. That is a reliable way to detect EmuTOS.
Structure from the Atari Compendium and EmuTOS
include/biosdefs.h. Hatari reads this variable at
src/gemdos.c to locate the OS.
$000004F6.L|RW|SHELL_P|_shell_p - pointer to shell |
$000004F6 to $000004FE OS pointers
$4F6 _shell_p longword, shell process pointer
$4FA end_os longword, end of the OS in RAM
$4FE exec_os longword, OS entry point
_shell_p allows a shell process to be installed which is
entered when the current program terminates. Normally unused.
exec_os is jumped through once operating system initialisation
is complete, normally pointing at the AES startup.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$000004FA.L|R-|_END_OS|end_os - pointer to end of OS in RAM |
$000004FE.L|R-|EXEC_OS|exec_os - pointer to OS entry point |
$00000502.L|RW|SCR_DMP|scr_dump - pointer to screen dump routine |
$00000502 to $00000512 Printer and auxiliary vectors
$502 scr_dump called when ALT-HELP is pressed
$506 prt_stat check status of the PRN: device
$50A prt_vec output a byte to the PRN: device
$50E aux_stat check status of the AUX: device
$512 aux_vec output a byte to the AUX: device
All longwords. The four printer and auxiliary vectors are used
by Prtblk(), so replacing them redirects printer output
without patching GEMDOS.
Atari's own source names the last four prv_lsto, prv_lst,
prv_auxo and prv_aux.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$00000506.L|RW|PRTSTAT|prt_stat - pointer to prv_lsto |
$0000050A.L|RW|PRT_VEC|prt_vec - pointer to prv_lst |
$0000050E.L|RW|AUXSTAT|aux_stat - pointer to prv_auxo |
$00000512.L|RW|AUX_VEC|aux_vec - pointer to prv_aux |
$00000516.L|RW|PUN_PTR|pun_ptr - pointer to pun_info if AHDI |
$00000516 pun_ptr AHDI partition information
Longword. Points to a PUN_INFO structure maintained by AHDI,
Atari's hard disk driver, describing the mounted partitions.
The structure begins:
word puns number of drives supported, including
floppies (maximum 16)
then pun[16] one byte per drive:
bits 0-2 physical ACSI unit
bit 7 set if the drive is not
present
then start[16] longword starting sector of each
partition
A null pointer means AHDI is not loaded.
This is a driver structure rather than hardware, so its exact
layout depends on the AHDI version in use. Treat the above as
indicative.
TOS declares it as _pun_ptr at $516 in common/tosvars.inc with
the comment "if AHDI, pointer to pun_info". Structure from the
Atari Compendium.
$0000051A.L|RW|MEMVAL3|memval3 - memory conf valid if $5555AAAA |
$0000051E. |RW|BCONSTA|bconstat_vec - 8 input status vectors(32 bytes)|
$0000051E to $0000057E BIOS device vector tables
Four tables of eight longwords each:
$51E bconstat_vec input status routines
$53E bconin_vec input routines
$55E bcostat_vec output status routines
$57E bconout_vec output routines
Indexed by BIOS device number:
0 = PRT printer
1 = AUX RS-232
2 = CON console (screen and keyboard)
3 = MIDI
4 = IKBD keyboard controller
5 = RAW console without VT-52 processing
6 and 7 unused on most machines
Replacing an entry redirects that device's I/O. This is how
serial port drivers and screen accelerators hook in.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$0000053E. |RW|BCONIN |bconin_vec - 8 input vectors (32 bytes) |
$0000055E. |RW|BCOSTAT|bcostat_vec - 8 output status vectors(32bytes)|
$0000057E. |RW|BCONOUT|bconout_vec - 8 output vectors (32 bytes) |
$0000059E.W|R-|LNGFRAM|_longframe - if <>0, CPU uses long stack frames|
$0000059E _longframe Processor stack frame format
Word. Zero means the processor uses short (68000) exception
stack frames; any other value means long (68010 and above)
frames.
This matters to any exception handler that inspects the stack:
the offset to the saved PC differs between the two formats.
Testing this variable is the correct way to handle both,
rather than assuming the CPU type.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$000005A0.L|R-|P_COOKI|_p_cookie - pointer to cookie jar |1.06+
$000005A0 _p_cookie Cookie jar pointer
Longword. Points to the cookie jar, a table of longword pairs
describing installed hardware and software features.
Each entry is two longwords: a four character tag and a value.
The list ends with an entry whose tag is zero, where the value
gives the total number of slots allocated.
Common tags include _CPU, _FPU, _SND, _MCH, _VDO, _FLK and
_IDT. A null pointer means no cookie jar exists, which is the
case before TOS 1.06.
Present from TOS 1.06 onward.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$000005A4.L|RW|_RAMTOP|ramtop - top of alternative (Fast) RAM |TT,F
$000005A8.L|RW|RAMVALD|ramvalid - validates ramtop if $1357BD13 |TT,F
$000005AC.L|RW|BELHOOK|bell_hook - vector for system bell |1.06+
$000005AC and $000005B0 Sound hooks
$5AC bell_hook vector jumped through to sound the bell
$5B0 kcl_hook vector jumped through for key clicks
Both longwords. The key click routine is entered with the
scancode of the key just pressed, so a replacement can vary
the click by key.
Replacing these is the supported way to change or silence the
system sounds without patching the BIOS.
Present from TOS 1.06 onward.
From the Atari Compendium and Atari TOS common/tosvars.inc.
$000005B0.L|RW|KCLHOOK|kcl_hook - vector for keyclick |1.06+
===========#==#=======#===============================================#=====
----------------------|STBook |-----
===========#==#=======#===============================================#=====
$00000889.B|RW|LCDPSHD|Shadow of LcdPowerControl ($FFFF827F) |STB
===========#==#=======#===============================================#=====
Magic validation values, collected for reference:
memvalid $420 = $752019F3
resvalid $426 = $31415926
memval2 $43A = $237698AA
memval3 $51A = $5555AAAA
ramvalid $5A8 = $1357BD13
proc_lives $380 = $12345678
flock ($43E) must be non-zero before any direct FDC or DMA access, so
the VBL floppy routine does not deselect the drive or disturb the DMA
mid-transfer. Clear it again afterwards.
Sources: addresses and labels from Atari's own TOS source
(th-otto/tos1x, common/tosvars.inc), cross-checked against Hatari,
EmuTOS (bios/tosvars.S) and The Atari Compendium Appendix B. Sizes are
inferred from address spacing and the Compendium; the byte-versus-word
calls on memcntlr, defshiftmd and sshiftmd are judgement rather than
documented. Read-only marks reflect convention, not hardware
enforcement.
Back to Memory Map for Atari ST,STE,TT and Falcon
IDE, Memory control & video
Maintained at IDE, Memory control & video
===========#==#=======#===============================================#=====
----------------------|IDE Bus |-----
===========#==#=======#===============================================#=====
$FFF00000.W|RW|IDE_DAT|Data Register |
$FFF00005.B|RW|IDE_ERR|Read:Error / Write:Features Register |
$FFF00005 IDE_ERR Error Register (read) / Features (write)
READ - error register, valid when the error bit is set in the
status register at $FFF0001D:
Bit 7 Bad Block Mark
Bit 6 Uncorrectable Error
Bit 5 (reserved)
Bit 4 ID Field Not Found
Bit 3 (reserved)
Bit 2 Command Aborted
Bit 1 Track 0 Not Found
Bit 0 DAM (Data Address Mark) Not Found
WRITE - features register, command specific. Used mainly by
SET FEATURES to enable or disable drive options.
Bit assignments from the Atari Compendium, matching the
standard ATA error register layout.
$FFF00009.B|RW|IDE_SCC|Sector count |
$FFF0000D.B|RW|IDE_SNR|Sector number |
$FFF00011.B|RW|IDE_CYL|Cylinder low |
$FFF00011 and $FFF00015 Cylinder Low / Cylinder High
$FFF00011 Cylinder Low bits 7-0 of the cylinder number
$FFF00015 Cylinder High bits 9-8 of the cylinder number
Together these form the ten bit cylinder number used in CHS
addressing.
In LBA mode the same two registers carry LBA bits 23-8 instead,
with the full eight bits of each used.
From the Atari Compendium, matching the standard ATA layout.
$FFF00015.B|RW|IDE_CYH|Cylinder high |
$FFF00019.B|RW|IDE_H_D|Head/Drive Register |
$FFF00019 IDE_H_D Drive / Head Register
Bit 7 (always 1 on early ATA)
Bit 6 0 = CHS addressing, 1 = LBA addressing
Bit 5 (always 1 on early ATA)
Bit 4 Drive select: 0 = master, 1 = slave
Bits 3-0 Head number, 0-15
In LBA mode bits 3-0 carry LBA bits 27-24 instead of the head
number.
Drive select and head number from the Atari Compendium. The
addressing and reserved bits follow the standard ATA layout.
$FFF0001D.B|RW|IDE_S_C|Read:Status Register/Write:Command Register |
$FFF0001D IDE_S_C Status (read) / Command (write)
READ - status register:
Bit 7 BSY busy, drive owns the registers
Bit 6 DRDY drive ready
Bit 5 DF drive fault
Bit 4 DSC drive seek complete
Bit 3 DRQ data request, drive wants a transfer
Bit 2 CORR corrected data
Bit 1 IDX index
Bit 0 ERR error, see the error register at $FFF00005
Reading this register clears a pending interrupt. Read the
alternate status at $FFF00039 instead when polling, since that
does not clear the interrupt.
WRITE - command register. Writing starts a command using the
values already loaded into the other registers.
CONFLICT: EmuTOS bios/ide.c places status and command at this
offset. The Atari Compendium places them at $FFF0001F and
marks $FFF0001A to $FFF0001D as unused. Every other Compendium
IDE entry agrees with EmuTOS, so $FFF0001D is the more likely
value, but neither has been checked on hardware.
Bit assignments follow the standard ATA status register.
$FFF00039.B|RW|IDE_ALT|Read:Alt Status/Write:Device Control |
$FFF00039 IDE_ALT Alternate Status (read) / Device Control (write)
READ - alternate status. Returns exactly the same bits as the
status register at $FFF0001D, but reading it does NOT clear a
pending interrupt. This is the register to poll with.
WRITE - device control:
Bit 2 SRST software reset
Bit 1 nIEN 1 = disable the drive's interrupt
From the Atari Compendium, which names it Alternate Status on
read and Alternate Command on write, and the standard ATA
layout.
$FFF00042.B|RW| - |Add-on control, not present on stock hardware |*
$FFF00042 and $FFF00044 Add-on control registers
Not present on stock Atari hardware. These sit in the same
address space as the IDE interface above.
Known to be used by: TRUDIE.
TRUDIE also claims $FFF00000 to $FFF00038, which is the IDE
register range itself, and $FFFFFFFF.
Extended bit information is not currently available for these
registers. The addresses are documented; what each bit does is
not.
Checked against EmuTOS: its IDE driver uses a plain ATA
register structure based at $FFF00000 and touches only the
standard offsets. It does not reference $FFF00042 or $FFF00044,
and has no concept of add-on IDE hardware in this range.
$FFF00044.B|RW| - |Add-on control, not present on stock hardware |*
===========#==#=======#===============================================#=====
----------------------|Memory Controller, System Control |-----
===========#==#=======#===============================================#=====
$FFFF8001.B|RW|MEM_CTL|Memory Controller |
$FFFF8001 MEM_CTL Memory Controller Configuration
Bits 3-2 Bank 1 size
Bits 1-0 Bank 0 size
Size encoding, same for both banks:
00 = 128k
01 = 512k
10 = 2M
11 = reserved
A shadow copy of this byte is kept in the system variable
memcntlr at $00000424, validated by memval2 at $0000043A.
Bit assignments from the Atari Compendium.
$FFFF8006.W|RW|SYS_CTL|System Control %MM______ _RS_bB_C |F
| | | Monitor Type (M0,M1)--------++ || || | |F
| | | Monochrome Monitor----------00 || || | |F
| | | RGB Monitor-----------------01 || || | |F
| | | VGA Monitor-----------------10 || || | |F
| | | TV--------------------------11 || || | |F
| | | Reset 0:ignore resetvector------------+| || | |F
| | | STE-compatible-I/O 0:off,1:on----------+ || | |F
| | | Blitterflag 0:on,1:off-------------------+| | |F
| | | Blitterspeed 0:half clock,1:full clock----+ | |F
| | | CPUspeed 0:half clock,1:full clock----------+ |F
$FFFF8006 SYS_CTL System Control / Connected Monitor Type
Bits 15-14, monitor type:
0 = Atari monochrome
1 = Atari colour (RGB)
2 = VGA colour
3 = television
Bit 9 Reset: 0 = ignore reset vector
Bit 8 STE compatible I/O: 0 = off, 1 = on
Bit 6 Blitter flag: 0 = on, 1 = off
Bit 5 Blitter speed: 0 = half clock, 1 = full clock
Bit 3 CPU speed: 0 = half clock, 1 = full clock
Monitor bits confirmed by Atari TOS 4.04, which tests
(byte >> 6) & 3 == 0 to detect a monochrome monitor, and by
the Atari Compendium value table.
Falcon only. On earlier machines monitor detection is through
MFP GPIP bit 7 at $FFFFFA01.
$FFFF8007.B|RW|SYS_FBC|Falcon Bus Control %_SB_BS__ |F
| | | Start type 0:cold,1:warm-------------+||||||| |
| | | STe Bus emulation 0:on,1:off----------+|||||| |
| | | Blitter control 0:on,1:off--------------+|||| |
| | | Blitter speed 0:8MHz,1:16MHz-------------+||| |
| | | CPU speed 0:8MHz,1:16MHz--------------------+ |
| | | Verified: EmuTOS bios/machine.c documents all |
| | | five bits and writes $25 (STe bus emulation |
| | | off, 16MHz blitter and CPU). Atari TOS |
| | | 3.06/4.04 bios/startup.S writes the same $25. |
$FFFF8007 SYS_FBC Falcon Bus Control
Bit 6 Start type: 0 = cold start, 1 = warm start
Bit 5 STe Bus emulation: 0 = on, 1 = off
Bit 3 Blitter control: 0 = on, 1 = off
Bit 2 Blitter speed: 0 = 8MHz, 1 = 16MHz
Bit 0 CPU speed: 0 = 8MHz, 1 = 16MHz
STe bus emulation has to be switched off for bus-error based
hardware detection to work on the Falcon.
EmuTOS bios/machine.c documents all five bits and writes $25,
setting STe bus emulation off with 16MHz blitter and CPU.
Atari TOS 3.06/4.04 bios/startup.S writes the same $25 and
tests bit 6.
Falcon only.
===========#==#=======#===============================================#=====
----------------------|DMA, VIDEL Controller |-----
===========#==#=======#===============================================#=====
$FFFF8201.B|RW|VDL_VBH|Video Base Hi |
$FFFF8201 / $FFFF8203 / $FFFF820D Video Base Address
Three byte registers holding the screen memory address:
$FFFF8201 bits 23-16, high
$FFFF8203 bits 15-8, middle
$FFFF820D bits 7-0, low (STE and Falcon only)
On the ST and Mega ST only the high and middle bytes exist, so
the screen base must be on a 256 byte boundary. The STE added
the low byte, allowing any even address.
Bit 0 of the low byte is ignored; the address is always even.
The current value is shadowed in the system variable
_v_bas_ad at $0000044E. Changing the base takes effect at the
next vertical blank, or immediately if written during one.
From the Atari Compendium.
$FFFF8203.B|RW|VDL_VBM|Video Base Mi |
$FFFF8205.B|Rw|VDL_VCH|Video Count Hi |
$FFFF8205 / $FFFF8207 / $FFFF8209 Video Address Counter
Three byte registers holding the address the shifter is
currently reading from:
$FFFF8205 bits 23-16, high
$FFFF8207 bits 15-8, middle
$FFFF8209 bits 7-0, low
The Atari Compendium marks all three read only, though the
wiki listing shows them as Rw. Writing them is not useful.
Reading these during display gives the shifter's position in
screen memory, which is how raster-timed effects work out where
the beam is. The three bytes are not read atomically, so the
counter can advance between reads.
From the Atari Compendium.
$FFFF8207.B|Rw|VDL_VCM|Video Count Mi |
$FFFF8209.B|Rw|VDL_VCL|Video Count Lo %xxxxxxx_ |
$FFFF820A.B|RW|VDL_SYM|Sync mode %______VS |
| | | Vfrequency 0:60hz(NTSC),1:50Hz(PAL)--------+| |
| | | Sync 0:internal,1:external------------------+ |
$FFFF820A VDL_SYM Video Shifter Sync Mode
Bit 1 Vertical frequency: 0 = 60Hz (NTSC), 1 = 50Hz (PAL)
Bit 0 Sync source: 0 = internal, 1 = external
Setting bit 0 stops the shifter generating its own sync and
makes it follow an external signal. This is the register used
for the classic sync-switching border removal tricks: writing
it at a precise point in the scanline makes the shifter miss
the border, opening the display area.
Bit assignments from the Atari Compendium.
$FFFF820D.B|RW|VDL_VBL|Video Base Lo %xxxxxxx_ |STE,F
$FFFF820E.B|RW|VDL_LOF|Line Offset |STE,F
$FFFF820E and $FFFF820F Line Offset and Line Width
$FFFF820E Line Offset. Number of extra words to skip at the
end of each scanline. STE and Falcon.
$FFFF820F Line Width, in words, minus one.
Together these let the shifter display a window onto a screen
buffer wider than the visible display, which is how the STE
does hardware horizontal scrolling.
On the Falcon the line width is a word value at $FFFF8210
instead, and is NOT minus one.
Note: writing the horizontal scroll low byte at $FFFF8265
clears the line width register. Set the width after the scroll,
not before.
$FFFF820E is not listed in the Atari Compendium; $FFFF820F is,
described as scanline width in words minus one.
$FFFF820F.B|RW| - |Line Width-1 |STE
$FFFF8210.W|RW|VDL_LWD|Line Width in Words %______xx xxxxxxxx |F
$FFFF8240.W|RW|VDL_STC|ST Palette Register 00 %____rRRR gGGGbBBB |
$FFFF8240 to $FFFF825E ST/STE Palette Registers 0-15
Word registers, one per palette entry.
ST layout: XXXX XRRR XGGG XBBB (3 bits per gun, 512
colours)
STE layout: XXXX RRRR GGGG BBBB (4 bits per gun, 4096
colours)
IMPORTANT: on the STE the four bits within each nibble are NOT
in natural order. The bit arrangement per nibble is 0-3-2-1.
The extra bit the STE adds is placed at the TOP of the nibble
rather than the bottom, so that an ST program writing only the
lower three bits still produces the same colour it would on an
ST. Reading an STE palette value as a plain 4 bit number gives
the wrong intensity.
Hatari masks writes to $0777 on an ST and $0FFF on an STE.
Some games write $FFFF and read the value back to detect
whether they are running on an STE.
These registers are simulated for compatibility on the TT and
Falcon, which have their own wider palettes at $FFFF8400 and
$FFFF9800.
Layout and nibble ordering from the Atari Compendium, masking
behaviour from Hatari src/video.c.
...........|RW| - |...................... |
$FFFF825E.W|RW| - |ST Palette Register 15 |
$FFFF8260.B|RW|VDL_SSM|ST-Shift-Mode %_____xxx |
| | | 320*200*4---------------------------------000 |
| | | 640*200*2---------------------------------001 |
| | | 640*400*1---------------------------------010 |
$FFFF8260 VDL_SSM ST Video Shifter Mode
Bits 1-0 resolution
00 = 320x200, 4 planes (low)
01 = 640x200, 2 planes (medium)
10 = 640x400, 1 plane (high)
11 = reserved
The TT modes were previously listed here. Atari uses a separate
TT shifter register at $FFFF8262.
A shadow copy of the current value is kept in the system
variable sshiftmd at $0000044C.
Writing 11 is not a documented mode. On real hardware it
produces the same output as one of the other modes rather than
anything useful; neither Atari TOS nor EmuTOS ever writes it.
Bit assignments from the Atari Compendium and Atari TOS
bios/startup.S.
===========#==#=======#===============================================#=====
$FFFF8262.B|RW|VDL_TSM|TT-Shift-Mode %_____xxx |TT
| | | ST low 320*200*4----------------------000 |TT
| | | ST medium 640*200*2----------------------001 |TT
| | | ST high 640*400*1----------------------010 |TT
| | | (Falcon rez marker)-----------------------011 |TT
| | | TT medium 640*480*4----------------------100 |TT
| | | (unused)----------------------------------101 |TT
| | | TT high 1280*960*1----------------------110 |TT
| | | TT low 320*480*8----------------------111 |TT
$FFFF8262 VDL_TSM TT Video Shifter Mode
Word register. The byte at $FFFF8262 is the high half:
Bit 7 Special video mode
Bit 4 Special video mode
Bits 2-0 resolution
000 = 320x200, 4 planes ST low
001 = 640x200, 2 planes ST medium
010 = 640x400, 1 plane ST high
011 = (Falcon rez marker)
100 = 640x480, 4 planes TT medium
101 = (unused)
110 = 1280x960, 1 plane TT high
111 = 320x480, 8 planes TT low
The byte at $FFFF8263 is the low half and holds the ST Palette
Bank, selecting which 16 entry bank of the 256 entry TT palette
the ST compatible palette registers map onto.
The two special video mode bits are named Smear Mode and Hyper
Mono Mode by the Atari Compendium. CHECK: which name goes with
which bit is not certain from the available sources. Hatari
masks both together as 0x90 without naming them individually.
Atari TOS 3.06 bios/startup.S declares this register as
shift_tt and defines TTMED=4, TTHIGH=6, TTLOW=7. When the
resolution is 2 or lower, Hatari mirrors the value into
$FFFF8260 so the ST shifter register stays consistent.
Resolution values from Atari TOS source, bit positions from
Hatari src/video.c, names from the Atari Compendium.
===========#==#=======#===============================================#=====
$FFFF8264.B|RW|VDL_HSH|H-Scroll Hi %____xxxx |F
$FFFF8264 and $FFFF8265 Horizontal Scroll
$FFFF8264 Bits 3-0, scroll amount, no side effect
$FFFF8265 Bits 3-0, scroll amount, ALSO clears line width
Both hold a pixel scroll offset of 0 to 15. Writing $FFFF8265
additionally clears the line width register at $FFFF820F, so
the two must be written in the right order: scroll first, then
width.
$FFFF8264 exists to allow the scroll to be changed without
disturbing the width. It is Falcon only.
$FFFF8265 is documented in the Atari Compendium as the
Horizontal Scroll Register. $FFFF8264 is not listed there.
$FFFF8265.B|RW|VDL_HSL|H-Scroll Lo - clears Line Width %____xxxx |STE,F
$FFFF8266.W|RW|VDL_FSM|Falcon Shift Mode %_____2OT _HV8PPPP |F
| | | 2 Color mode 0:off,1:on----------+|| ||||||| |F
| | | Overlay mode 0:off,1:on-----------+| ||||||| |F
| | | True(high) color 0:off,1:on--------+ ||||||| |F
| | | Hsync 0:internal,1:external-----------+|||||| |F
| | | Vsync 0:internal,1:external------------+||||| |F
| | | 8 Bitplanes 0:off,1:on------------------+|||| |F
| | | falcon Palette 16 of 256 colors----------++++ |F
$FFFF8266 VDL_FSM SPSHIFT / Falcon Shift Mode
Bit 10 Enable 2-colour mode
Bit 8 Enable truecolor mode
Bit 6 Use external HSYNC
Bit 5 Use external VSYNC
Bit 4 Enable bitplane mode (8 bitplanes)
Bits 3-0 Falcon palette bank, 16 of 256 colours
Bit 9 is the overlay mode bit.
Only one of the mode bits should be set at a time. Truecolor
mode takes the pixel value straight to the DAC and ignores the
palette entirely.
Atari TOS 4.04 (tos3x bios/vsetmode.c) writes $0100 to select
truecolor and $0010 to select 8 bitplane mode, confirming bits
8 and 4.
Bit meanings from the Atari Compendium, confirmed against
Atari TOS 4.04 and EmuTOS.
$FFFF827E.B|RW|STY_DSP|STACY Display State |STB
| | | UNVERIFIED: Atari Compendium only. Not |
| | | referenced by EmuTOS or any available TOS |
| | | source. |
$FFFF827E STY_DSP STACY Display State
Bit 1 1 = backlight off
Bit 0 1 = display off
STACY only, the portable ST. Rare hardware.
UNVERIFIED: Atari Compendium only. Not referenced by EmuTOS,
Hatari or any available TOS source.
$FFFF8280.W|RW|VDL_HHC|Horizontal Hold Counter %_______x xxxxxxxx |F
$FFFF8280 to $FFFF82AC VIDEL Timing Registers
These define the video timing directly, replacing the fixed
timings the ST shifter used. All are word registers, Falcon
only.
Horizontal, in pixel clocks unless noted:
$FFFF8280 Horizontal Hold Counter
$FFFF8282 Horizontal Hold Timer
$FFFF8284 Horizontal Border Begin
$FFFF8286 Horizontal Border End
$FFFF8288 Horizontal Display Begin (bit 8 selects which
half line the display starts on)
$FFFF828A Horizontal Display End
$FFFF828C Horizontal Sync Start
$FFFF828E Horizontal FS
$FFFF8290 Horizontal EE
Vertical, in half lines:
$FFFF82A0 Vertical Frequency Counter
$FFFF82A2 Vertical Frequency Timer
$FFFF82A4 Vertical Border Begin
$FFFF82A6 Vertical Border End
$FFFF82A8 Vertical Display Begin
$FFFF82AA Vertical Display End
$FFFF82AC Vertical Sync Start
The FS and EE registers are only used when bit 3 of the video
control register is clear.
Atari TOS 4.04 (tos3x bios/vsetmode.c) and EmuTOS both write
this whole block as a table of values per video mode rather
than computing them, so the exact meaning of each field is
best understood from those mode tables.
Names from the Atari Compendium; register set confirmed
against Atari TOS 4.04 and EmuTOS bios/videl.c.
$FFFF8282.W|RW|VDL_HHT|Horizontal Hold Timer %_______x xxxxxxxx |F
$FFFF8284.W|RW|VDL_HBB|Horizontal Border Begin %_______x xxxxxxxx |F
$FFFF8286.W|RW|VDL_HBE|Horizontal Border End %_______x xxxxxxxx |F
$FFFF8288.W|RW|VDL_HDB|Horizontal Display Begin %______Hx xxxxxxxx |F
| | | 0:1.Halfline, 1:2.Halfline--------+ |F
$FFFF828A.W|RW|VDL_HDE|Horizontal Display End %_______x xxxxxxxx |F
$FFFF828C.W|RW|VDL_HSS|Horizontal Sync Start %_______x xxxxxxxx |F
$FFFF828E.W|RW|VDL_HFS|Horizontal FS %_______x xxxxxxxx |F
$FFFF8290.W|RW|VDL_HEE|Horizontal EE %_______x xxxxxxxx |F
$FFFF82A0.W|RW|VDL_VFC|Vertical Frequency Counter %_____xxx xxxxxxxx |F
$FFFF82A2.W|RW|VDL_VFT|Vertical Frequency Timer %_____xxx xxxxxxxx |F
$FFFF82A4.W|RW|VDL_VBB|Vertical Border Begin %_____xxx xxxxxxxx |F
$FFFF82A6.W|RW|VDL_VBE|Vertical Border End %_____xxx xxxxxxxx |F
$FFFF82A8.W|RW|VDL_VDB|Vertical Display Begin %_____xxx xxxxxxxx |F
$FFFF82AA.W|RW|VDL_VDE|Vertical Display End %_____xxx xxxxxxxx |F
$FFFF82AC.W|RW|VDL_VSS|Vertical Sync Start %_____xxx xxxxxxxx |F
$FFFF82C0.W|RW|VDL_VCT|Video Control %_______O BHVUSCMM |F
| | | h-base-Offset 0:128cyc,1:64cyc-----+ |||||||| |F
| | | Buswide 0:16bit,1:32bit--------------+||||||| |F
| | | Hsync 0:negative,1:positive-----------+|||||| |F
| | | Vsync 0:negative,1:positive------------+||||| |F
| | | Use FS & EE 0:on,1:off------------------+|||| |F
| | | 15 halfline hSyncs at VBB----------------+||| |F
| | | video Clock 0:32Mhz,1:25.175Mhz-----------+|| |F
| | | Monitor 0:Mono,1:RGB,2:VGA,3:TV------------++ |F
| | | NAMING CHECK: TOS 4.04 (tos3x vsetmode.c) and |F
| | | EmuTOS write video_control to $82C2 and |F
| | | video_clock to $82C0 - the reverse of these |F
| | | two labels. Addresses/bits correct either way.|F
$FFFF82C0 VDL_VCT Video Control
Bit 8 h-base offset: 0 = 128 cycles, 1 = 64 cycles
Bit 7 Bus width: 0 = 16 bit, 1 = 32 bit
Bit 6 HSYNC polarity: 0 = negative, 1 = positive
Bit 5 VSYNC polarity: 0 = negative, 1 = positive
Bit 4 Use FS and EE registers: 0 = on, 1 = off
Bit 3 15 half-line HSYNCs at vertical border begin
Bit 2 Video clock: 0 = 32MHz, 1 = 25.175MHz
Bits 1-0 Monitor: 0 = mono, 1 = RGB, 2 = VGA, 3 = TV
EmuTOS writes $0080 for monochrome, $0186 for VGA, and
$0181 or $0183 for RGB and television. Decoding those confirms
the monitor field, the clock bit set only for VGA, and the bus
width bit always set.
NAMING CHECK: Atari TOS 4.04 (tos3x bios/vsetmode.c) writes
video_control to $FFFF82C2 and video_clock to $FFFF82C0, and
EmuTOS uses the same naming. That is the reverse of the labels
used on this page. The addresses and bit layouts are confirmed
correct by both sources; only the names may be swapped.
This address is NOT listed in the Atari Compendium at all,
which only documents $FFFF82C2. That may itself be a clue to
the naming question.
Bit assignments confirmed against Atari TOS 4.04 and EmuTOS
bios/videl.c.
$FFFF82C2.W|RW|VDL_VMD|Video Mode %________ ____xxID |F
| | | Pixclock:4,Divider:4(VGA)/16(STE)/4------00|| |F
| | | Pixclock:2,Divider:2(VGA)/16(STE)/2------01|| |F
| | | Pixclock:1,Divider:2(VGA)/16(STE)/1------10|| |F
| | | (unused)---------------------------------11|| |F
| | | Interlace 0:off,1:on-----------------------+| |F
| | | Double Scan 0:off,1:on----------------------+ |F
$FFFF82C2 VDL_VMD VCO / Video Mode
Bit 3 Quarter pixel width
Bit 2 Halve pixel width
Bit 1 Interlace mode
Bit 0 Line doubling
Bits 3-2 together give the pixel clock divider:
00 = full width (divider 4 on VGA, 16 on STE)
01 = half width (divider 2 on VGA, 16 on STE)
10 = quarter width(divider 2 on VGA, 16 on STE)
11 = not used, never written by TOS or EmuTOS
Line doubling and interlace are mutually exclusive: line
doubling is used on VGA to display a 200 line mode at 400
lines, interlace on television output.
NAMING CHECK: Atari TOS 4.04 (tos3x bios/vsetmode.c) writes
video_control to $FFFF82C2 and video_clock to $FFFF82C0, and
EmuTOS uses the same naming. That is the reverse of the labels
used on this page. The addresses and bit layouts are confirmed
correct by both sources; only the register names may be the
wrong way round.
Bit assignments from the Atari Compendium, confirmed against
Atari TOS 4.04 and EmuTOS.
===========#==#=======#===============================================#=====
----------------------|TT Palette Registers |-----
===========#==#=======#===============================================#=====
$FFFF8400.W|RW|TT__PAL|TT Palette Register 000 |TT
$FFFF8400 to $FFFF85FE TT Palette Registers 0-255
Word registers, one per palette entry, 256 entries.
Layout: XXXX RRRR GGGG BBBB
Unlike the ST and STE registers at $FFFF8240, each nibble here
is in natural order, 3-2-1-0. There is no compatibility
reordering.
The ST compatible palette registers at $FFFF8240 map onto a
16 entry bank of this palette, selected by the ST Palette Bank
field in the low byte of $FFFF8262.
TT only.
Layout from the Atari Compendium.
...........|RW| - |....................... |TT
$FFFF85FE.W|RW| - |TT Palette Register 255 |TT
===========#==#=======#===============================================#=====
----------------------|VIDEL Palette Register |-----
===========#==#=======#===============================================#=====
$FFFF9800.L|RW|VDL_PAL|Palette Register 000 %RRRRRR__ GGGGGG__ |F
$FFFF9800 to $FFFF98FC VIDEL Palette Registers 0-255
Longword registers, one per palette entry, 256 entries.
Layout, across the four bytes of each longword:
Byte 0 RRRRRR-- red, 6 bits
Byte 1 GGGGGG-- green, 6 bits
Byte 2 -------- unused
Byte 3 BBBBBB-- blue, 6 bits
Six bits per gun, so 262144 possible colours, of which 256 can
be displayed at once. The low two bits of each byte are unused
and read back as zero.
Falcon only. Ignored entirely in truecolor mode, where the
pixel value goes straight to the DAC.
Layout from the Atari Compendium.
...........|RW| - |.................... ________ BBBBBB__ |F
$FFFF98FC.L|RW| - |Palette Register 255 |F
===========#==#=======#===============================================#=====
----------------------|DMA, Blitter |-----
===========#==#=======#===============================================#=====
$FFFF8A00.W|RW|BLT_HTR|Halftone-RAM 00 |BLT
$FFFF8A00 to $FFFF8A1E Blitter Halftone RAM
Sixteen word registers, one per halftone line.
Which word is used for a given blit line is chosen by the
halftone line number in bits 3-0 of the control register at
$FFFF8A3C, or by source bits 0-3 when the SMUDGE bit is set.
The halftone word feeds the halftone operation at $FFFF8A3A,
which in turn feeds the logical operation at $FFFF8A3B.
Verified against Hatari src/blitter.c.
...........|RW| - |............... |BLT
$FFFF8A1E.W|RW| - |Halftone-RAM 15 |BLT
$FFFF8A20.W|RW|BLT_SXI|Source X increment %xxxxxxxx xxxxxxx_ |BLT
$FFFF8A20 / $FFFF8A22 / $FFFF8A2E / $FFFF8A30 Increments
$FFFF8A20 Source X increment
$FFFF8A22 Source Y increment
$FFFF8A2E Destination X increment
$FFFF8A30 Destination Y increment
All four are signed word values in BYTES, added to the current
address as the blit proceeds.
X increment is added after each word within a line. Y increment
is added at the end of each line, and is applied INSTEAD of the
final X increment, not in addition to it.
Bit 0 is ignored in all four: the blitter works in words, so
increments are always even. Negative values are allowed and are
how downward or right-to-left blits are done, which matters for
overlapping copies.
Verified against Hatari src/blitter.c.
$FFFF8A22.W|RW|BLT_SYI|Source Y increment %xxxxxxxx xxxxxxx_ |BLT
$FFFF8A24.L|RW|BLT_SRC|Source Address %xxxxxxxx xxxxxxxx xxxxxxx_ |BLT
$FFFF8A24 and $FFFF8A32 Source and Destination Address
$FFFF8A24 Source address, longword
$FFFF8A32 Destination address, longword
Both are 24 bit addresses held in a longword. The Atari
Compendium notes that bits 7-0 of the first byte are bits
23-16 of the address, which is the usual 68000 24 bit layout.
Bit 0 is ignored; addresses are always even.
These registers ADVANCE during a blit. After the operation
completes they hold the address just past the last word
transferred, not the value originally written, so they must be
reloaded for each new blit.
Verified against Hatari src/blitter.c.
$FFFF8A28.W|RW|BLT_EM1|Endmask 1 |BLT
$FFFF8A28 / $FFFF8A2A / $FFFF8A2C Endmasks
$FFFF8A28 Endmask 1, applied to the FIRST word of each line
$FFFF8A2A Endmask 2, applied to all MIDDLE words
$FFFF8A2C Endmask 3, applied to the LAST word of each line
Each is a 16 bit mask. Where a mask bit is 1 the result is
written; where it is 0 the destination is left alone.
Endmask 2 is normally $FFFF. Endmasks 1 and 3 are used to clip
a blit to a pixel boundary within the first and last words.
IMPORTANT: whenever a mask is not all ones, the blitter must
read the destination before writing it, turning the operation
into a read-modify-write and roughly halving throughput. Atari
documentation states NFSR can also trigger this; Hatari's
authors state that is wrong and only the mask does.
If a line is only one word wide, endmask 1 and endmask 3 are
ANDed together and endmask 2 is not used.
Verified against Hatari src/blitter.c.
$FFFF8A2A.W|RW|BLT_EM2|Endmask 2 |BLT
$FFFF8A2C.W|RW|BLT_EM3|Endmask 3 |BLT
$FFFF8A2E.W|RW|BLT_DXI|Destination X increment %xxxxxxxx xxxxxxx_ |BLT
$FFFF8A30.W|RW|BLT_DYI|Destination Y increment %xxxxxxxx xxxxxxx_ |BLT
$FFFF8A32.L|RW|BLT_DST|Destination Adr. %xxxxxxxx xxxxxxxx xxxxxxx_ |BLT
$FFFF8A36.W|RW|BLT_WPL|Words per Line in BOB (0:65536)|BLT
$FFFF8A36 and $FFFF8A38 X Count and Y Count
$FFFF8A36 X count, words per line
$FFFF8A38 Y count, number of lines
A value of 0 means 65536, not zero.
Y count is the register the blitter decrements as it works.
When it reaches 0 the transfer is complete and the busy bit in
$FFFF8A3C clears. Reading Y count during a blit shows how many
lines remain.
X count is reloaded at the start of each line.
The Atari Compendium calls these BLiTTER X Count and Y Count.
This listing calls them Words per Line and Lines per BOB;
they are the same registers.
Quirk: with x count = 1 and NFSR set, real STE and Falcon
hardware produce results that depend on the sign of the source
X increment.
Verified against Hatari src/blitter.c.
$FFFF8A38.W|RW|BLT_LPB|Lines per BOB (0:65536)|BLT
$FFFF8A3A.B|RW|BLT_HTO|Halftone Operation %______xx |BLT
| | | 0:set all Bits, 1:HTR, 2:SRC, 3:SRC & HTR |BLT
$FFFF8A3A BLT_HTO Halftone Operation, bits 1-0
0 all ones ($FFFF)
1 halftone RAM word
2 source word
3 source word AND halftone RAM word
HOP runs first, LOP second. The HOP result is what the logical
operation sees as its "source" input.
Verified against Hatari src/blitter.c.
$FFFF8A3B.B|RW|BLT_LGO|Logical Operation %____xxxx |BLT
| | | (!S AND !D)------------------------------+||| |BLT
| | | (!S AND D)-------------------------------+|| |BLT
| | | ( S AND !D)--------------------------------+| |BLT
| | | ( S AND D)---------------------------------+ |BLT
$FFFF8A3B BLT_LGO Logical Operation, bits 3-0
S = output of the halftone operation above
D = current destination word
$0 all zeros $8 NOT S AND NOT D (NOR)
$1 S AND D $9 NOT (S XOR D) (NXOR)
$2 S AND NOT D $A NOT D
$3 S $B S OR NOT D
$4 NOT S AND D $C NOT S
$5 D $D NOT S OR D
$6 S XOR D $E NOT (S AND D) (NAND)
$7 S OR D $F all ones
The register takes a value 0-15 selecting one of sixteen
operations, not just the four AND combinations shown above.
Verified against Hatari src/blitter.c.
$FFFF8A3C.B|RW|BLT_LNM|Line Number %BHS_xxxx |BLT
| | | Busy (1:start Blitter)---------------+|| |||| |BLT
| | | HOG (1:stop CPU when Busy)------------+| |||| |BLT
| | | SMUDGE (use sourcebits 0-3 as HTR num)-+ |||| |BLT
| | | Halftone-RAM number----------------------++++ |BLT
$FFFF8A3C BLT_LNM Control, %BHS_nnnn
Bit 7 BUSY write 1 to start the blitter. Reads 1 while a
transfer is in progress, cleared when y count
reaches 0.
Bit 6 HOG 0 = share the bus with the CPU, 1 = take the
bus for the whole transfer.
Bit 5 SMUDGE use source bits 0-3 as the halftone line
number instead of bits 3-0 of this register.
Bit 4 unused. Hardware masks this bit off on write.
Bits 3-0 halftone line number, 0-15.
In non-hog mode the blitter runs for 64 bus accesses, then
hands the bus to the CPU for 64. Writing 0 to bit 7 while the
CPU owns the bus pauses the blitter; writing 1 resumes it.
Pausing does not end the transfer, and busy still reads 1.
Quirk: in non-hog mode the blitter sometimes uses only 63 bus
accesses rather than 64, if the CPU makes a bus access during
the 4-cycle latency after the busy bit is set.
Verified against Hatari src/blitter.c.
$FFFF8A3D.B|RW|BLT_SKW|SKEW %FN__xxxx |BLT
| | | FXSR (Force eXtra Source Read)-------+| |||| |BLT
| | | NFSR (No Final Source Read)-----------+ |||| |BLT
| | | SKEW (shift)-----------------------------++++ |BLT
$FFFF8A3D BLT_SKW Skew, %FN__nnnn
Bit 7 FXSR Force eXtra Source Read
Bit 6 NFSR No Final Source Read
Bits 5-4 unused
Bits 3-0 skew, 0-15 pixels
Read-modify-write happens whenever an endmask is not all ones.
Atari's own documentation states NFSR can also trigger this;
Hatari's authors state that is wrong and only the mask does.
Quirk: with x count = 1 and NFSR set, real STE and Falcon
hardware produce results that depend on whether the source X
increment is positive or negative.
Verified against Hatari src/blitter.c.
Back to Memory Map for Atari ST,STE,TT and Falcon
DMA & SCSI
Maintained at DMA & SCSI
===========#==#=======#===============================================#=====
----------------------|DMA, WD1772 Disk Controller |-----
===========#==#=======#===============================================#=====
$FFFF8604.W|RW|WDC_SEC|FDC/HDC Access/Sector Count |
$FFFF8604 WDC_SEC FDC/HDC Access / Sector Count
The FDC is NOT in the 68000 address space. Its four registers
sit behind the DMA chip and are reached through this word.
Select which one with the mode register at $FFFF8606, then
read or write here. Only the low 8 bits are used; the upper
byte is ignored on write and reads back as all ones.
Mode register values to select each FDC register:
DMA read mode DMA write mode
FDC Command (W)/Status(R) $0080 $0180
FDC Track Register $0082 $0182
FDC Sector Register $0084 $0184
FDC Data Register $0086 $0186
DMA sector count (W only) $0090 $0190
WD1772 command encodings written to the Command Register:
Type Command b7 b6 b5 b4 b3 b2 b1 b0 Base
I Restore 0 0 0 0 h v r1 r0 $00
I Seek 0 0 0 1 h v r1 r0 $10
I Step 0 0 1 u h v r1 r0 $20
I Step-in 0 1 0 u h v r1 r0 $40
I Step-out 0 1 1 u h v r1 r0 $60
II Read Sector 1 0 0 m h e 0 0 $80
II Write Sector 1 0 1 m h e p a0 $A0
III Read Address 1 1 0 0 h e 0 0 $C0
III Read Track 1 1 1 0 h e 0 0 $E0
III Write Track 1 1 1 1 h e p 0 $F0
IV Force Interrupt 1 1 0 1 i3 i2 i1 i0 $D0
Base is the opcode with all flags clear, not the only byte the
command can take. Read Track can appear as $E0, $E4, $E8 or
$EC depending on h and e. Match on the top nibble.
Flags:
u bit 4 update Track Register
m bit 4 multiple sector
h bit 3 0 = enable spin-up sequence, 1 = disable
v bit 2 verify destination track
e bit 2 add settling delay
p bit 1 0 = ENABLE write precompensation, 1 = disable
a0 bit 0 0 = normal data mark, 1 = deleted data mark
Step rates (r1,r0), WD1772 values at 8MHz:
00 = 6ms 01 = 12ms 10 = 2ms 11 = 3ms
These are WD1772 specific. The WD1770 uses 6, 12, 20 and 30ms
for the same encodings. On the Atari 3ms is the normal setting
and h must always be 0, since MO is wired straight to the drive.
Sources: Western Digital's own WD1772 data sheet, cross-checked
against EmuTOS bios/fdc.h. Read Track being 1110 confirmed by
both, correcting a misprint in DrCoolZic's edition.
$FFFF8606.W|R-|WDC_DMA|DMA Status %________ _____DSE |
| | | Data request condition--------------------+|| |
| | | Sector count 0:zero,1:not zero-------------+| |
| | | DMA 0:error,1:no error----------------------+ |
|-W| |DMA Mode %_______W FD_SHAA_ |
| | | 0:read,1:write---------------------+ || |||| |
| | | 0:HDC,1:FDC access-------------------+| |||| |
| | | DMA 0:on,1:off (ignored STF/STE)----+ |||| |
| | | 0:FDC/HDC register 1:sector count-------+||| |
| | | 0:FDC,1:HDC access-----------------------+|| |
| | | A1/A0 pin 0:low,1:high--------------------++ |
$FFFF8606 WDC_DMA DMA Status (read) / DMA Mode (write)
READ - status, bits 2-0:
Bit 2 state of the FDC DRQ signal
Bit 1 sector count: 0 = reached zero, 1 = not zero
Bit 0 DMA error: 1 = NO error, 0 = error
Bit 0 is inverted from the obvious reading. It was documented
the wrong way round here and in the widely mirrored Dan Hollis
listing for many years. Atari's own TOS tests it as:
move.w #$0090,(a6) examine DMA status register
move.w (a6),d0
btst #0,d0 bit zero indicates DMA ERROR
beq.s floprd6 (when its zero -- retry)
EmuTOS agrees: DMA_OK is 0x0001, commented 1=ok, 0=error.
Confirmed by ijor, July 2026.
WRITE - mode control:
Bit 8 direction, 1 = memory to controller (write)
Toggling this bit RESETS the DMA, flushing both
FIFOs and clearing the sector count register.
Bit 7 1 = acknowledge FDC DRQ, 0 = acknowledge HDC DRQ
Bit 6 nominally DMA enable, but IGNORED on STF and STE
Bit 4 0 = external controller registers, 1 = sector count
Bit 3 0 = assert FDCS*, 1 = assert HDCS*
Bit 2 CA2 output, drives FDC A1
Bit 1 CA1 output, drives FDC A0
Bit 0 unused, set 0
The DMA FIFOs are 16 bytes and are never flushed automatically,
so data only reaches memory in multiples of 16 bytes. A single
Read Address moves 6 bytes and therefore reaches memory not at
all; issue it repeatedly to push data through.
Do not poll this status register during a transfer, it can
disrupt it. Poll MFP GPIP bit 5 at $FFFFFA01 instead: mask with
$20, result zero means the FDC has interrupted.
$FFFF8609.B|RW|WDC_BSH|DMA Base and Counter Hi |
$FFFF860B.B|RW|WDC_BSM|DMA Base and Counter Mi |
$FFFF860D.B|RW|WDC_BSL|DMA Base and Counter Lo |
$FFFF860E.B|RW|WDC_FDN|Frequency and Density control %______FD |STE,F
| | |Frequency 0:8MHz,1:16MHz--------------------+| |
| | |Density 0:DD,1:HD----------------------------+ |
$FFFF860E WDC_FDN Frequency and Density control
Bit 1 Frequency 0 = 8MHz, 1 = 16MHz
Bit 0 Density 0 = DD (double), 1 = HD (high)
STE and Falcon only. Was previously labelled WDC_BSL here,
duplicating the label on $FFFF860D.
===========#==#=======#===============================================#=====
----------------------|DMA SCSI |-----
===========#==#=======#===============================================#=====
$FFFF8701.B|RW|SCS_DA0|DMA Address Pointer (Highest byte) |TT
$FFFF8703.B|RW|SCS_DA1|DMA Address Pointer (High byte) |TT
$FFFF8705.B|RW|SCS_DA2|DMA Address Pointer (Low byte) |TT
$FFFF8707.B|RW|SCS_DA3|DMA Address Pointer (Lowest byte) |TT
$FFFF8709.B|RW|SCS_BC0|DMA Byte Counter (Highest byte) |TT
$FFFF870B.B|RW|SCS_BC1|DMA Byte Counter (High byte) |TT
$FFFF870D.B|RW|SCS_BC2|DMA Byte Counter (Low byte) |TT
$FFFF870F.B|RW|SCS_BC3|DMA Byte Counter (Lowest byte) |TT
$FFFF8710.W|Rw|SCC_RD0|Rest data (High Word) |TT
$FFFF8712.W|Rw|SCC_RD1|Rest data (Low Word) |TT
$FFFF8714.W|Rw|SCS_CTL|DMA SCSI 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
| | | DMA 0:read,1:write--------------------------+ |TT
===========#==#=======#===============================================#=====
----------------------|5380 SCSI Drive Controller |-----
===========#==#=======#===============================================#=====
$FFFF8781.B|RW|SCS_CDB|Contents of SCSI-Data Buses |TT
NCR 5380 SCSI CONTROLLER - REGISTER MAP
IMPORTANT: the register names on this page were wrong for five
of the eight registers and have been corrected. The old names
are noted below so anyone who finds them elsewhere knows why
they differ. The 5380 is a standard part with a well known
register map; several registers do different things on read
and on write, which is the likely source of the confusion.
Addr Reg Read Write
$FFFF8781 0 Current SCSI Data Output Data
$FFFF8783 1 Initiator Command Initiator Command
$FFFF8785 2 Mode Register Mode Register
$FFFF8787 3 Target Command Target Command
$FFFF8789 4 Current SCSI Bus Status Select Enable
$FFFF878B 5 Bus and Status Start DMA Send
$FFFF878D 6 Input Data Start DMA Target Receive
$FFFF878F 7 Reset Parity/Interrupt Start DMA Initiator Recv
Old names on this page, now corrected:
$8785 was 'Transfer Start Register' -> Mode Register
$8789 was 'Bus Status Register' -> ID Select / Bus Status
$878B was 'Device Status Register' -> DMA Send / Bus+Status
$878D was 'SCSI-Bus Command Data' -> DMA Target Rx / Input
$878F was 'Reset Interrupts, Parity
error, Start DMA-Action' -> DMA Init Rx / Reset
Address to register number mapping, per Hatari src/ncr5380.c:
register = (address / 2) & 7
so $FFFF8781 is register 0, $FFFF8783 register 1, and so on.
Only odd addresses respond; even addresses are ignored.
CONFLICT NOTE: the Atari Compendium lists this block starting at
$00FF8780 with OB (odd byte) markers, which resolves to the same
odd addresses shown here. Its names match the standard 5380 map
and therefore agree with Hatari. This wiki's earlier names
matched neither. If you find a listing using the old names, it
most likely descends from the same source as this page did.
Verified against Hatari src/ncr5380.c and the Atari Compendium.
$FFFF8783.B|RW|SCS_ICR|Init Command Register |TT
$FFFF8785.B|RW|SCS_MR |Mode Register |TT
$FFFF8787.B|RW|SCS_TCR|Target Command Register |TT
$FFFF8789.B|RW|SCS_SEL|ID Select / Current SCSI Bus Status |TT
$FFFF8789 Register 4
READ - Current SCSI Bus Status:
Bit 7 RST
Bit 6 BSY
Bit 5 REQ
Bit 4 MSG
Bit 3 C/D (command/data)
Bit 2 I/O (input/output)
Bit 1 SEL
Bit 0 DBP (data bus parity)
Bits 4-2 together give the current bus phase:
000 Data Out 011 Status
001 Data In 110 Message Out
010 Command 111 Message In
WRITE - Select Enable Register: sets which SCSI ID the
controller responds to when selected as a target.
Verified against Hatari src/ncr5380.c, which builds this value
from the live bus signals and shifts the bus phase into bits
4-2 exactly as above.
$FFFF878B.B|RW|SCS_DMA|Start DMA Send / Bus and Status Register |TT
$FFFF878B Register 5
READ - Bus and Status Register:
Bit 7 End of DMA
Bit 6 DMA Request
Bit 5 Parity Error
Bit 4 Interrupt Request active
Bit 3 Phase Match (bus phase equals Target Command bits)
Bit 2 Busy Error
Bit 1 ATN
Bit 0 ACK
WRITE - Start DMA Send: writing here begins a DMA transfer
from memory to the SCSI bus.
Verified against Hatari src/ncr5380.c.
$FFFF878D.B|RW|SCS_TRG|Start DMA Target Rx / Input Data Register |TT
$FFFF878F.B|RW|SCS_INI|Start DMA Initiator Rx / Reset Parity-Interrupt|TT
Back to Memory Map for Atari ST,STE,TT and Falcon
YM, DSP & DMA Sound
Maintained at YM, DSP & DMA Sound
===========#==#=======#===============================================#=====
----------------------|YM2149/AY-3-8910 Sound Chip |-----
===========#==#=======#===============================================#=====
$FFFF8800.B|R-|PSG_SEL|Read Data |
|-W| |Register Select |
$FFFF8800 PSG_SEL YM2149 register select (W) / read data (R)
Write a register number 0-15 here, then read or write the
value at $FFFF8802. The register set:
0 Channel A tone period, fine (8 bits)
1 Channel A tone period, coarse (4 bits)
2 Channel B tone period, fine
3 Channel B tone period, coarse
4 Channel C tone period, fine
5 Channel C tone period, coarse
6 Noise generator period (5 bits)
7 Mixer control and I/O port direction
8 Channel A amplitude
9 Channel B amplitude
10 Channel C amplitude
11 Envelope period, fine
12 Envelope period, coarse
13 Envelope shape (4 bits)
14 I/O Port A (floppy select, printer, RS232)
15 I/O Port B (Centronics data)
Register 7, mixer control:
Bit 7 Port B direction, 1 = output
Bit 6 Port A direction, 1 = output
Bit 5 Noise off, channel C
Bit 4 Noise off, channel B
Bit 3 Noise off, channel A
Bit 2 Tone off, channel C
Bit 1 Tone off, channel B
Bit 0 Tone off, channel A
Note the enable bits are inverted: a 0 enables that source.
Registers 8-10, amplitude:
Bits 3-0 fixed volume level 0-15
Bit 4 1 = use envelope instead of fixed volume
Register 13, envelope shape, bits 3-0:
Bit 3 CONT continue after first cycle
Bit 2 ATT attack, 1 = rising
Bit 1 ALT alternate direction each cycle
Bit 0 HOLD hold at final level
YM2149 versus AY-3-8910
The YM2149 is Yamaha's licensed version of General Instrument's
earlier AY-3-8910. The two are register compatible: same 16
registers, same layout, same writes. There are no extra
registers on either part. The differences are internal:
- The envelope counter is 5 bit on the YM2149 (32 steps)
against 4 bit on the AY (16 steps), giving smoother volume
ramps. The envelope clock is divided by 8 rather than 16
to keep the cycle time the same across twice the steps.
The volume registers stay 4 bit on both, so there is
nothing extra to write.
- The YM reads registers back exactly as written. The AY
returns 0 for unused bits regardless of what was written.
- The YM has a 2V DC offset on all outputs; the AY has 0.2V
on a channel only while an envelope is active. This is why
the AY sounds louder.
Nothing in TOS depends on any of this. AY documentation applies
to the ST unchanged as far as the register interface goes.
Register names verified against Hatari src/includes/psg.h.
Mixer and port-direction bit masks verified against EmuTOS
bios/psg.h (PSG_PORTB_OUTPUT 0x80, PSG_PORTA_OUTPUT 0x40,
PSG_NOISE_MASK 0x38, PSG_TONE_MASK 0x07).
$FFFF8802.B|rW|PSG_DAT|Write Data |
| | | PSG Register 14 - Port A %RICDPBAS |
| | | Reset IDE 0:no,1:reset (slow down)---+||||||| |F
| | | Internal Speaker 0:on,1:off-----------+|||||| |F
| | | Centronics Strobe----------------------+||||| |
| | | Reset DSP 0:no,1:reset------------------+|||| |F
| | | Printer Select In------------------------+||| |
| | | Drive B select 0:on,1:off-----------------+|| |
| | | Drive A select 0:on,1:off------------------+| |
| | | Side select 0:side1,1:side0-----------------+ |
| | | PSG Register 15 - Port B %xxxxxxxx |
| | | Centronics Data Port-----------------++++++++ |
$FFFF8802 PSG_DAT YM2149 data register
Reads or writes the register previously selected at $FFFF8800.
PORT A, register 14, is the one that matters on the ST. It
carries the floppy drive and side select lines:
Bit 7 Reset IDE 0 = no, 1 = reset Falcon
Bit 6 Internal speaker 0 = on, 1 = off Falcon
Bit 5 Centronics strobe
Bit 4 Reset DSP 0 = no, 1 = reset Falcon
Bit 3 Printer select in
Bit 2 Drive B select 0 = selected
Bit 1 Drive A select 0 = selected
Bit 0 Side select 1 = side 0, 0 = side 1
Note the side select polarity: the bit SET selects side 0.
This is not a typo in the listing, it is how the hardware works.
Bits 3-7 carry RS232 RTS and DTR, the Centronics strobe and a
general purpose output. Always read the port, modify only the
bits you need and write it back. Writing a whole byte will
disturb the serial and printer lines.
Disable interrupts around any access to this register, or the
floppy VBL routine can deselect the drive underneath you. Set
flock at $0000043E to a non-zero value first.
Register layout verified against Hatari and EmuTOS.
$FFFF8804.B|RW| - |Add-on sound, not present on stock hardware |*
$FFFF8804 to $FFFF8808 Add-on sound registers
Not present on stock Atari hardware. $FFFF8800 and $FFFF8802 are
the YM2149 select and data registers; some add-on boards extend
the decoded range upward to $FFFF8808 for their own sound
hardware.
Known to be used by: SEC Booster.
IMPORTANT, FALCON: these addresses do NOT behave this way on a
Falcon. On that machine the PSG registers are fixed at $FFFF8800
and $FFFF8802 only, and every other address in the range is
masked out. Any write to the shadow registers $FFFF8804 to
$FFFF88FF will cause a BUS ERROR.
So an add-on using this range works on the ST and STE, where the
PSG address decoding is incomplete and the registers repeat
through the range, but the same code will bus error on a Falcon.
Anything writing here should check the machine type first.
Source: the Atari F030 and CT60 Hardware Register Listing, which
states the shadow registers are masked out and warns game and
demo coders specifically.
Extended bit information is not currently available for these
registers. The addresses are documented; what each bit does is
not.
$FFFF8806.B|RW| - |Add-on sound, not present on stock hardware |*
$FFFF8808.B|RW| - |Add-on sound, not present on stock hardware |*
===========#==#=======#===============================================#=====
----------------------|DMA, CODEC, ADC, DAC, DSP-Transmit/Receive |-----
===========#==#=======#===============================================#=====
$FFFF8900.W|RW|SND_DMA|Sound-DMA-Control %____RPRP F_EL__EL |F,STE
| | | Timer A after Record/Play-------++|| | || || |F
| | | MFP I/O 7 after Record/Play-------++ | || || |F
| | | Frame Registers 0:play,1:record------+ || || |F
| | | DMA record Enable/Loop-----------------++ || |F
| | | DMA play Enable/Loop-----------------------++ |F,STE
$FFFF8900 SND_DMA Sound DMA control
Bits 1-0, DMA play:
Bit 1 loop: 0 = play once, 1 = repeat from frame start
Bit 0 enable: 0 = stop, 1 = start playback
Bits 5-4, DMA record (Falcon only), same enable/loop pair.
Bit 7 frame register select: 0 = play frame, 1 = record
Bits 11-8 and 15-12 select what happens at the end of a
record or play frame: Timer A event and MFP I/O 7 event.
On the STE only bits 1-0 exist. The record path and the event
bits are Falcon additions.
Playback reads from the frame start address at $FFFF8903-07
and continues to the frame end at $FFFF890F-13. The current
position can be read from $FFFF8909-0D while playing.
$FFFF8903.B|RW|SND_FSH|Frame Start Hi |F,STE
$FFFF8903 / $FFFF8905 / $FFFF8907 Frame Start address
Three byte registers holding a 24 bit address:
$FFFF8903 bits 23-16, high
$FFFF8905 bits 15-8, middle
$FFFF8907 bits 7-0, low
The address of the first byte of sample data. Bit 0 of the low
byte is ignored: the DMA fetches on even addresses only, so the
frame must start word aligned.
On the Falcon, bit 7 of $FFFF8900 selects whether these
registers address the play frame or the record frame.
Loaded into the DMA counter when playback starts, and reloaded
from here on each repeat if the loop bit is set.
$FFFF8905.B|RW|SND_FSM|Frame Start Mi |F,STE
$FFFF8907.B|RW|SND_FSL|Frame Start Lo |F,STE
$FFFF8909.B|RW|SND_FCH|Frame Count Hi |F,STE
$FFFF8909 / $FFFF890B / $FFFF890D Frame Count
Three byte registers holding the current 24 bit DMA address:
$FFFF8909 bits 23-16, high
$FFFF890B bits 15-8, middle
$FFFF890D bits 7-0, low
Read these while playing to find how far through the sample the
DMA has reached. The value advances from the frame start toward
the frame end.
Reading the three bytes is not atomic, so the counter can move
between reads. Read high, middle then low and re-read if the
high byte changed, or read with interrupts disabled.
Hatari tracks this internally as frameCounterAddr, refilling
its FIFO from that address as playback advances.
$FFFF890B.B|RW|SND_FCM|Frame Count Mi |F,STE
$FFFF890D.B|RW|SND_FCL|Frame Count Lo |F,STE
$FFFF890F.B|RW|SND_FEH|Frame End Hi |F,STE
$FFFF890F / $FFFF8911 / $FFFF8913 Frame End address
Three byte registers holding a 24 bit address:
$FFFF890F bits 23-16, high
$FFFF8911 bits 15-8, middle
$FFFF8913 bits 7-0, low
The address one past the last byte of sample data. Playback
stops when the frame counter reaches this value.
If the loop bit in $FFFF8900 is set, the counter reloads from
the frame start registers and playback continues. If not,
playback stops and the enable bit clears.
As with the start address, bit 0 of the low byte is ignored.
$FFFF8911.B|RW|SND_FEM|Frame End Mi |F,STE
$FFFF8913.B|RW|SND_FEL|Frame End Lo |F,STE
$FFFF8920.W|RW|SND_SMC|Sound Mode Control %__SS__PP MB____FF |F,STE
| | | DAC to track %SS--------------++ || || || |F
| | | Play %PP+1 tracks-----------------++ || || |F
| | | 0:Stereo,1:Mono----------------------+| || |F
| | | 0:8bit,1:16bit------------------------+ || |F
| | | Falcon:(unused)--STE: 6258 Hz--------------00 |F,STE
| | | Falcon:12292 Hz--STE:12517 Hz--------------01 |F,STE
| | | Falcon:19668 Hz--STE:25033 Hz--------------10 |F,STE
| | | Falcon:49170 Hz--STE:50066 Hz--------------11 |F,STE
$FFFF8920 SND_SMC Sound mode control
This is a word register, but the two halves are separate:
$FFFF8920 is the track control byte and $FFFF8921 the mode
control byte. Hatari and EmuTOS treat them separately.
$FFFF8921, mode control:
Bit 7 0 = stereo, 1 = mono
Bit 6 0 = 8 bit, 1 = 16 bit
Bits 1-0 sample rate:
Falcon: 00 unused, 01 12292Hz, 10 19668Hz, 11 49170Hz
STE: 00 6258Hz, 01 12517Hz, 10 25033Hz, 11 50066Hz
$FFFF8920, track control (Falcon only):
Bits 5-4 which track the DAC monitors
Bits 1-0 number of tracks to play, minus one
The mono/stereo bit was previously printed on this page with
both states as 0. Corrected from EmuTOS bios/dmasound.c, which
does modectrl |= 0x80 with the comment 'Select mono', and from
Hatari src/falcon/crossbar.c, which reads isStereo as the
inverse of bit 7 and is16Bits from bit 6.
$FFFF8922.B|RW| - |Microwire Data Register |STE
$FFFF8922 Microwire Data Register (with $FFFF8924 Mask)
The STE and TT use a Microwire serial link to control an
LMC1992 audio processor, which handles master volume, left and
right balance, bass, treble, and the mix between DMA sound and
the YM2149 output. Write the command word here; $FFFF8924 is
the mask that clocks it out.
Command format: 10 CCC DDD DDD
10 chipset address, always this value
CCC command
DDD DDD data
Commands:
000 XXX XDD Mixing
00 DMA sound only
01 DMA sound + YM2149, full frequency range
10 DMA sound + YM2149 through a low pass
filter -> gives DMA sound only
11 input 3, not connected -> DMA only
001 XXD DDD Bass 0 000 = -12dB, 0 110 = 0dB,
1 100 = +12dB, 2dB steps
010 XXD DDD Treble same scale as bass
011 DDD DDD Master volume
000 000 = -80dB, 010 100 = -40dB,
101 XXX = 0dB, 2dB steps
100 XDD DDD Right channel volume
00 000 = -40dB, 01 010 = -20dB,
10 1XX = 0dB
101 XDD DDD Left channel volume, same scale as right
Any other command value is undefined.
THE STE MIXING BUG
Note the arrows on mixing modes 10 and 11 above. Mode 10 is
supposed to mix the YM2149 in through a low pass filter, which
would attenuate it relative to the DMA sound. On the STE it
does not work: input 2 is not wired, so selecting it drops the
YM output entirely and you get DMA sound only. Mode 11 selects
input 3, which is not connected at all.
The practical effect is that the STE gives you only two useful
choices, DMA alone or DMA plus YM at full volume, with no way
to balance the two in software. In games such as Xenon the
YM sound ends up considerably louder than the DMA samples.
A hardware fix for this was worked out by P. Putnik and is
documented here, along with the rest of the STE DAC work:
exxosforum.co.uk STE DAC fix, LMC section
Command set verified against Hatari src/dmaSnd.c, which
documents the same non-functional mixing modes and carries the
full LMC1992 volume tables.
$FFFF8924.B|RW| - |Microwire Mask Register |STE
$FFFF8924 Microwire Mask Register
Works with the data register at $FFFF8922. The mask marks which
bits of the data word are the command; the hardware shifts both
registers out together over the Microwire serial link to the
LMC1992.
The usual value is $07FF, an 11 bit command window matching the
10 CCC DDD DDD command format described at $FFFF8922.
Behaviour during a transfer, per Hatari src/dmaSnd.c:
- The data register shifts left one bit per step.
- The mask register ROTATES left rather than shifting, so
after a complete transfer it reads back as it started.
- One shift takes 8 CPU cycles, so a full 16 step transfer
takes 128 cycles.
Because the mask rotates back to its original value, reading it
is not a reliable way to tell whether a transfer has finished.
The data register shifting to zero is the usable indicator.
Verified against Hatari src/dmaSnd.c.
===========#==#=======#===============================================#=====
----------------------|Falcon Sound Matrix and CODEC |-----
===========#==#=======#===============================================#=====
$FFFF8930.W|RW|SND_CBO|Crossbar Output Select Controller |F
$FFFF8930 SND_CBO Crossbar source (input) select
Word register, four 4-bit fields, one per source device.
Bit layout from Hatari src/falcon/crossbar.c:
Bits 15-12 A/D Converter
Bits 13-12 clock: 00 = 25.175MHz, 01 = external,
10 = 32MHz (do not use)
Bits 11-8 External Input
Bit 11 0 = DSP IN, 1 = all others
Bits 10-9 clock, as above
Bit 8 0 = handshake on, 1 = handshake off
Bits 7-4 DSP transmit
Bit 7 0 = tristate and disconnect DSP (external SSI
use only), 1 = connect DSP to multiplexer
Bits 6-5 clock, as above
Bit 4 0 = handshake on, 1 = handshake off
Bits 3-0 DMA playback
Bit 3 0 = handshaking on, destination DSP receive
1 = destination is not DSP receive
Bits 2-1 clock, as above
Bit 0 0 = handshake on, 1 = handshake off
Verified against Hatari src/falcon/crossbar.c.
$FFFF8932.W|RW|SND_CBI|Crossbar Input Select Controller |F
$FFFF8932 SND_CBI Crossbar destination (output) select
Word register, four 4-bit fields, one per destination.
Bit layout from Hatari src/falcon/crossbar.c:
In each field the two-bit source selector means:
00 = DMA output 01 = DSP output
10 = External input 11 = ADC input
Bits 15-12 D/A Converter
Bits 13-12 source, as above
Bits 11-8 External output
Bit 11 0 = DSP out, 1 = all others
Bits 10-9 source, as above
Bit 8 0 = handshake on, 1 = handshake off
Bits 7-4 DSP receive
Bit 7 0 = tristate and disconnect DSP (external SSI
use only), 1 = connect DSP to multiplexer
Bits 6-5 source, as above
Bit 4 0 = handshake on, 1 = handshake off
Bits 3-0 DMA record
Bit 3 0 = handshaking on, destination DSP transmit
1 = all
Bits 2-1 source, as above
Bit 0 0 = handshake on, 1 = handshake off
Verified against Hatari src/falcon/crossbar.c.
$FFFF8934.B|RW|SND_FDE|Frequency Divider, External Sync |F
$FFFF8934 SND_FDE Frequency Divider, External Sync
Clock divider used when the crossbar is set to take an external
clock. Hatari accepts writes here but the value only matters
when an external clock source is actually connected, which on
a standard Falcon it is not.
See $FFFF8930 and $FFFF8932 for the clock and source selection
that decides whether this register is used at all.
$FFFF8935.B|RW|SND_FDI|Frequency Divider, Internal Sync |F
$FFFF8935 SND_FDI Frequency Divider, Internal Sync
Bits 3-0 clock divider, 0-15
Bits 7-4 unused
Divides the selected internal clock (25.175MHz or 32MHz, chosen
per device in $FFFF8930) down to the sample rate. Together with
the clock choice and the number of active tracks this sets the
actual playback frequency.
Verified against Hatari src/falcon/crossbar.c, which masks the
written value with 0x0F and recalculates the clock cycles.
$FFFF8936.B|RW|SND_RTS|Record Tracks Select |F
$FFFF8936 SND_RTS Record Tracks Select
Bits 1-0 number of tracks to record
0 = 1 track
1 = 2 tracks
2 = 3 tracks
3 = 4 tracks
Bits 7-2 unused
Verified against Hatari src/falcon/crossbar.c.
$FFFF8937.B|RW|SND_CIS|CODEC Input Source |F
$FFFF8937 SND_CIS CODEC Input Source
Bit 1 source = multiplexer (the crossbar)
Bit 0 source = A/D converter
Bits 7-2 unused
Selects what feeds the CODEC's 16 bit adder. Both bits can be
set, which sums the two sources.
Verified against Hatari src/falcon/crossbar.c.
$FFFF8938.B|RW|SND_CAD|CODEC ADC Input |F
$FFFF8938 SND_CAD CODEC ADC Input
Bit 1 Left channel 0 = microphone, 1 = PSG (YM2149)
Bit 0 Right channel 0 = microphone, 1 = PSG (YM2149)
Bits 7-2 unused
This is how the Falcon routes the YM2149 output into the ADC so
it can be mixed digitally, rather than through the analogue
path the STE uses.
Verified against Hatari src/falcon/crossbar.c.
$FFFF8939.B|RW|SND_GAI|Gain settings %LLLLRRRR |F
$FFFF8939 SND_GAI Gain settings, input amplifier
Bits 7-4 Left channel gain, 0-15
Bits 3-0 Right channel gain, 0-15
Amplification for the ADC input, in +1.5dB steps per increment.
Verified against Hatari src/falcon/crossbar.c, which indexes
its ADC volume table with (value >> 4) for left and (value & 15)
for right.
$FFFF893A.W|RW|SND_ATT|Attenuation settings %LLLLRRRR |F
$FFFF893A SND_ATT Attenuation settings, output reduction
Word register:
Bits 11-8 Left channel attenuation, 0-15
Bits 7-4 Right channel attenuation, 0-15
Bits 15-12 and 3-0 unused
Reduction for the DAC output, in -1.5dB steps per increment.
Note the field positions: this is not the same layout as the
gain register at $FFFF8939. Hatari reads left from
(value >> 8) & 0x0F and right from (value >> 4) & 0x0F.
Verified against Hatari src/falcon/crossbar.c.
$FFFF893C.W|R-|SND_CST|CODEC Status |F
$FFFF893C SND_CST CODEC Status
Bit 1 Left channel overflow
Bit 0 Right channel overflow
Bits 15-2 unused
Overflow flags set when the CODEC input clips. Read only in
practice, though Hatari accepts writes.
This register is absent from the Atari Compendium listing and
was found in Hatari and EmuTOS. EmuTOS bios/dmasound.c sets it
to $003F on reset.
Verified against Hatari src/falcon/crossbar.c.
$FFFF8940.W|RW|SND_GPD|GPIO Data Direction |F
$FFFF8940 SND_GPD GPIO Data Direction
Bits 2-0 direction for the three general purpose I/O pins
0 = input, 1 = output
Bits 15-3 unused
Three GPIO pins are brought out on the Falcon's DSP connector.
They are not used by TOS and are free for expansion hardware.
UNVERIFIED: address confirmed by the Atari Compendium, but the
bit detail here is not corroborated by Hatari or EmuTOS, neither
of which implements these pins.
$FFFF8942.W|RW|SND_GPI|GPIO Data |F
$FFFF8942 SND_GPI GPIO Data
Bits 2-0 data for the three general purpose I/O pins
Bits 15-3 unused
Reads the pin state for pins set as inputs at $FFFF8940, and
drives the pin for those set as outputs.
UNVERIFIED: address confirmed by the Atari Compendium, but the
bit detail here is not corroborated by Hatari or EmuTOS.
Back to Memory Map for Atari ST,STE,TT and Falcon
MFP, RTC & anything else
Maintained at 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.
From the Atari Compendium.
$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.
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.
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 |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. |
$FFFF8E0D.B|RW|VME_MR1|VME Mask Register 1 |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 |ME
| | | $FF 16MHz with cache |ME
| | | $FE 16MHz, cache off |ME
| | | $F4 8MHz |ME
| | | 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. |
===========#==#=======#===============================================#=====
----------------------|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 |
$FFFF9202.W|RW|PAD_MOV|Paddle/Joy Move |STE,F
$FFFF9210.W|RW|PAD_PD0|Pad0 Position |STE,F
$FFFF9212.W|RW|PAD_PD1|Pad1 Position |STE,F
$FFFF9214.W|RW|PAD_PD2|Pad2 Position |STE,F
$FFFF9216.W|RW|PAD_PD3|Pad3 Position |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.
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 Register |ME
$FFFFFA42.W|RW|FPC_CTL|Control Register |ME
$FFFFFA44.W|RW|FPC_SAV|Save Register |ME
$FFFFFA46.W|RW|FPC_RES|Restore Register |ME
$FFFFFA48.W|RW|FPC_OPW|Operation Word Register |ME
$FFFFFA4A.W|RW|FPC_CMD|Command Register |ME
$FFFFFA4C.W|RW| - |Reserved |ME
$FFFFFA4E.W|RW|FPC_CCR|Condition Code Register |ME
$FFFFFA50.L|RW|FPC_OPR|Operand Register |ME
$FFFFFA54.W|RW|FPC_SEL|Register Select |ME
$FFFFFA56.W|RW| - |Reserved |ME
$FFFFFA58.L|RW|FPC_IAR|Instruction Address Register |ME
$FFFFFA5C.L|RW|FPC_OAR|Operand Address Register |ME
===========#==#=======#===============================================#=====
----------------------|MFP 68901 number 2 |-----
===========#==#=======#===============================================#=====
$FFFFFA81.B|RW|MF2_PDR|Parallel Port Data Register |TT
...........| | |........................... |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|RW| - |No label or description recorded |
| | | CHECK: this entry has never carried a |
| | | description. Purpose unknown. Either identify |
| | | it or remove it. |
===========#==#=======#===============================================#=====
$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.
Back to Memory Map for Atari ST,STE,TT and Falcon