Battery-Backed Memory Bit Map (battmem.resource)

battmem.resource (V36) gives access to the system's battery-backed nonvolatile RAM. The NDK headers assign this memory to a handful of boot-time hardware settings: SCSI selection timeout, LUN scanning, host ID, synchronous/fast/tagged transfers, and the extra IDE wait at boot. Access is bit-addressed and protected by a semaphore. The NDK splits the bit map over three headers, each owning a fixed range of bit addresses.

Header Bit range Owner
<resources/battmembitsamiga.h> 0–31 Amiga-specific bits
<resources/battmembitsamix.h> 32–63 Amix: "See Amix documentation for these bit definitions"
<resources/battmembitsshared.h> 64 and above Bits shared between Amiga and Amix

All three are $VER 47.1 (3.8.2019) in NDK 3.2 R4. Every item is a pair of #defines: BATTMEM_<name>_ADDR (first bit number) and BATTMEM_<name>_LEN (number of bits). Pass them directly as the Offset and Len arguments of ReadBattMem()/WriteBattMem().

Bit map

Amiga bits (0–31)

Item ADDR LEN Meaning (header comments)
BATTMEM_AMIGA_AMNESIA 0 1 Memory-loss flag. Zero indicates that a memory loss has occurred. Used to tell the user that "all battery-backed bit have been reset and that some attention is required"
BATTMEM_SCSI_TIMEOUT 1 1 SCSI selection timeout: 0 = short (128 ms), 1 = long (2 s). For "Seagate drives (and some Maxtors apparently) that don't respond to selection until they are fully spun up"
BATTMEM_SCSI_LUNS 2 1 1 = probe logical units above 0 at each SCSI address. Default 0 "meaning don't support LUNs", which avoids drives that answer on every LUN

Bits 3–31 are not assigned in the header.

Shared bits (64 and up)

Item ADDR LEN Meaning (header comments)
BATTMEM_SHARED_AMNESIA 64 1 Memory-loss flag for the shared area. Zero = memory loss occurred
BATTMEM_SCSI_HOST_ID 65 3 Controller SCSI ID 0–7, stored complemented "so that default value of 0 really means 7". "used to set the A3000 controllers SCSI ID (on reset)"
BATTMEM_SCSI_SYNC_XFER 68 1 1 = the driver initiates synchronous transfer requests. Default 0 = leave it to the drive (for drives that "crash or otherwise get confused" by a sync message)
BATTMEM_SCSI_FAST_SYNC 69 1 Default 0 = fast synchronous (>5 MB/s) requests are used. Only matters if synchronous transfers are negotiated
BATTMEM_SCSI_TAG_QUEUES 70 1 1 = use SCSI-2 tagged queuing. Default 0 = disabled
BATTMEM_IDE_EXTRA_WAIT 71 1 1 = wait extra seconds at boot before accessing IDE drives ("Currently in V40 the number is 8 seconds"). The IDE counterpart of SCSI_TIMEOUT
bit:  0   1   2   3 ........ 31 | 32 ...... 63 | 64  65 66 67  68  69  70  71
      AM  TO  LN  (unassigned)  |    Amix      | SA  HOST_ID   SY  FS  TQ  IW

Polarity gotchas

The bits do not share one convention:

  • Amnesia bits are active-low. A value of 0 means the memory was lost.
  • SCSI_HOST_ID is complemented. Read 3 bits, then compute id = 7 - value (equivalently ~value & 7). Write 7 - id.
  • SCSI_FAST_SYNC is "enable by default". 0 means fast sync is used, so setting the bit to 1 disables fast sync. SCSI_SYNC_XFER and SCSI_TAG_QUEUES are the other way round: 1 enables the feature.

battmem.resource API

<resources/battmem.h> defines the name:

#define BATTMEMNAME "battmem.resource"

It is a resource, not a library, so you get its base with exec.library/OpenResource(). "There is no CloseResource() function." The SFD uses ==bias 6, and the LVOs start at -6:

Function LVO Registers Prototype
ObtainBattSemaphore() 2.0+ -6 — VOID ObtainBattSemaphore(VOID)
ReleaseBattSemaphore() 2.0+ -12 — VOID ReleaseBattSemaphore(VOID)
ReadBattMem() 2.0+ -18 A0 buffer, D0 offset, D1 length ULONG ReadBattMem(APTR buffer, ULONG offset, ULONG length)
WriteBattMem() 2.0+ -24 A0 buffer, D0 offset, D1 length ULONG WriteBattMem(CONST_APTR buffer, ULONG offset, ULONG length)

The base variable expected by <proto/battmem.h> is BattMemBase (struct Library *).

Autodoc rules:

  • Offset and length are in bits. "Partial byte reads (less than 8 bits) result in the bits read being put in the low-order bits of the destination byte". Writes take them from the low-order bits of the source byte.
  • Result: zero if no error.
  • Checksum: "The battery-backed memory is checksummed. If a checksum error is detected, all bits in the battery-backed memory are silently set to zero." That reset is what the amnesia bits detect: after it, both read as 0.
  • Missing bits: "Bits in the battery-backed memory that do not exist are read as zero."
  • ObtainBattSemaphore() "Aquires exclusive access to the system nonvolatile ram". Bracket read-modify-write sequences with it and ReleaseBattSemaphore().

battclock.resource also has ReadBattClockMem()/WriteBattClockMem() entries in its SFD, but they sit in the ==private section. Use battmem.resource. battclock 47.2 fixed WriteBattClockMem trashing the caller's return address when writing past the clock chip's memory limit.

Example: read and print the settings

#include <exec/types.h>
#include <resources/battmem.h>
#include <resources/battmembitsamiga.h>
#include <resources/battmembitsshared.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/battmem.h>

struct Library *BattMemBase;

static ULONG getbits(ULONG addr, ULONG len)
{
    UBYTE b = 0;
    if (ReadBattMem(&b, addr, len) != 0)
        return (ULONG)~0;               /* error */
    return b;                           /* bits are in the low-order end */
}

int main(void)
{
    if (!(BattMemBase = (struct Library *)OpenResource(BATTMEMNAME)))
    {
        PutStr("No battmem.resource\n");
        return RETURN_WARN;
    }

    ObtainBattSemaphore();

    Printf("Amiga amnesia flag : %ld (0 = memory was lost)\n",
           getbits(BATTMEM_AMIGA_AMNESIA_ADDR, BATTMEM_AMIGA_AMNESIA_LEN));
    Printf("SCSI long timeout  : %ld\n",
           getbits(BATTMEM_SCSI_TIMEOUT_ADDR, BATTMEM_SCSI_TIMEOUT_LEN));
    Printf("SCSI LUNs          : %ld\n",
           getbits(BATTMEM_SCSI_LUNS_ADDR, BATTMEM_SCSI_LUNS_LEN));
    Printf("SCSI host ID       : %ld\n",
           7 - getbits(BATTMEM_SCSI_HOST_ID_ADDR, BATTMEM_SCSI_HOST_ID_LEN));
    Printf("Initiate sync      : %ld\n",
           getbits(BATTMEM_SCSI_SYNC_XFER_ADDR, BATTMEM_SCSI_SYNC_XFER_LEN));
    Printf("Fast sync disabled : %ld\n",
           getbits(BATTMEM_SCSI_FAST_SYNC_ADDR, BATTMEM_SCSI_FAST_SYNC_LEN));
    Printf("Tagged queuing     : %ld\n",
           getbits(BATTMEM_SCSI_TAG_QUEUES_ADDR, BATTMEM_SCSI_TAG_QUEUES_LEN));
    Printf("IDE extra wait     : %ld\n",
           getbits(BATTMEM_IDE_EXTRA_WAIT_ADDR, BATTMEM_IDE_EXTRA_WAIT_LEN));

    ReleaseBattSemaphore();
    return RETURN_OK;
}

Example: set the SCSI host ID

BOOL SetHostID(ULONG id)            /* id = 0..7 */
{
    UBYTE b = (UBYTE)(7 - (id & 7)); /* stored complemented */
    ULONG err;

    ObtainBattSemaphore();
    err = WriteBattMem(&b, BATTMEM_SCSI_HOST_ID_ADDR, BATTMEM_SCSI_HOST_ID_LEN);
    ReleaseBattSemaphore();

    return (BOOL)(err == 0);
}

The header says the host ID is applied "on reset", so a change takes effect at the next boot.

Assembler

        INCLUDE "lvo/exec_lib.i"
        INCLUDE "resources/battmembitsshared.i"

        move.l  4.w,a6
        lea     BattMemName(pc),a1
        jsr     _LVOOpenResource(a6)
        move.l  d0,a6                       ; BattMemBase
        tst.l   d0
        beq.s   .nores

        jsr     -6(a6)                      ; ObtainBattSemaphore
        lea     Buffer(pc),a0
        moveq   #BATTMEM_SCSI_HOST_ID_ADDR,d0
        moveq   #BATTMEM_SCSI_HOST_ID_LEN,d1
        jsr     -18(a6)                     ; ReadBattMem
        jsr     -12(a6)                     ; ReleaseBattSemaphore
        ...
BattMemName:    dc.b    "battmem.resource",0

See Also


Sources: NDK 3.2 R4 Include_H/resources/{battmem,battmembitsamiga,battmembitsamix,battmembitsshared,battclock}.h, SFD/battmem_lib.sfd, SFD/battclock_lib.sfd, Include_I/lvo/battmem_lib.i, Include_H/pragmas/battmem_pragmas.h, Include_H/proto/battmem.h, Autodocs/battmem.doc, ReleaseNotes/battclock-RelNotes Updated: 2026-11-13