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_IDis complemented. Read 3 bits, then computeid = 7 - value(equivalently~value & 7). Write7 - id.SCSI_FAST_SYNCis "enable by default". 0 means fast sync is used, so setting the bit to 1 disables fast sync.SCSI_SYNC_XFERandSCSI_TAG_QUEUESare 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 andReleaseBattSemaphore().
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¶
- battmem.resource Reference
- battclock.resource Reference
- nonvolatile.library Reference
- scsidisk.library Reference
- exec.library Reference (
OpenResource())
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