_ReadXPRam/_WriteXPRam actually work
| Offset (hex) | Length (dec) | Related to |
| 1 | 1 | Used by a system program _InternalWait
|
| 8 | 4 | Looks like the last 4 bytes of the regular PRAM (See IM, Vol II, OS Util) |
| 10 | 16 | Looks like the first 16 bytes of the regular PRAM (See IM, Vol II, OS Util) |
| 78 | 4 | Startup Disk info (apparently, SCSI id) |
| 7C | 2 | System Beep. As was pointed out earlier, it is
in fact an id (short int) of the corresponding
'snd ' resource in the System file;accessed through the Sound control panel |
| 7E | 1 | Used by a system program _InitProcMenu
|
| 7F | 1 | Apparently it has something to do with the way windows and dialogs appear on the screen |
| 80 | 2 | Used by a system program _GetVideoDefaultapparently, some default video settings |
| 82 | 6 | Hilite Color, apparently in the RGB format, set up through the Color control panel |
| 8A | 1 | Bit field: Memory/cache control flags
|
| AF | 1 | Has something to do with the RAM disk size
|
| B8 | 4 | A 32-bit field whose
|
| BD | 33 | looks like the name of the default AppleTalk zone (in Str32 format)Used (and set!) by some system programs in ROM,
|
| DE | 2 | at addresses 8009d544 and 8009d73C
|
| E0 | 4 | has something to do with the network: an AppleTalk active/inactive flag, and the selected network access (say, LocalTalk
or EtherTalk). See Chooser and Network control panel |
| E4 | 12 | Latitude/Longitude of the place this Mac is at. Set up through the Map control panel |
xPRAM settings, and restore them at a later moment:
PRAM, and apparently all (or a part of) xPRAM, although xPRAM is not mentioned by name.
xPRAM given the field's offset and length:
LEA buf,a0 ; where to get/put the info
MOVE.W length,d0
SWAP d0 ; Length in the hi word of D0
MOVE.W offset,d0 ; Offset in the lo word of D0
DC.W $A051 or $A052 ; _ReadXPRam or _WriteXPRam
On return, D0 contains 0 (no error) or -1 (failure: say, the offset is not within the 256-byte xPRAM).xPRAM: set the offset to 0 and the length to 256. Note, some old Mac models (II's and IIx's) had a bug in their ROM that prevents from writing the very last byte of xPRAM (offset=255).
size bytes of the xPRAM into a (previously allocated) buffer where, starting from the beginning of xPRAM:
// This is
// CLR.L D0 offset would be 0
// MOVE.W (A7)+,D0 size -> lo word of d0
// SWAP D0 size -> hi word of d0
// MOVEA.L (A7)+,A0 where -> A0
// _ReadXPRam
pascal void read_extended_PRAM(char * where, const short size) =
{ 0x4280, 0x301F, 0x4840, 0x205F, 0xA051 };
When I wrote this code, I had only Symantec C++ 6.0.1 compiler, which didn't permit asm{} inlines in C++ code. So I had to code in hex...
Writing to xPRAM is similar to reading, only one has to use trap A052 rather than A051. The following function writes size bytes from a buffer where into xPRAM, starting at offset:
// This is
// MOVE.L (A7)+,D0
// MOVEA.L (A7)+,A0 where -> A0
// _WriteXPRam
pascal void write_extended_PRAM
(const char * where, const short offset, const short size) =
{0x201F, 0x205F, 0xA052};
A051/A052 traps in MacsBug):0x50f00000 (or something like this).
xPRAM layout_ReadXPRam/_WriteXPRam are not documented, let alone the xPRAM.A051 (_ReadXPRam) and A052 (_WriteXPRam), and let the system go on booting and run. I played with all control panels and watched if setting/resetting some values ends up in the debugger. There, a mere peek at the contents of D0 will tell everything: the location (byte-offset) in xPRAM that is being read/written is in the lower-order word of D0, and the size of the data is in the high-order-word. This is exactly the way I reengineered the xPRAM map (well, I also disassembled a few control panels, e.g., Sound, Cache, and Memory)
.cpt.hqx, 29K]
// Printing out the contents of the xPRAM
// The trick is that _ReadXPRam/_WriteXPRam traps are available only
// from within 68K universe. So, if this code runs in the PowerPC mode,
// we've got to switch universes before running M68K code sequences....
#include <stdio.h>
#include <MixedMode.h>
// This is
// CLR.L D0 offset would be 0
// MOVE.W $4(A7),D0 size -> lo word of d0
// SWAP D0 size -> hi word of d0
// MOVEA.L 6(A7),A0 where -> A0
// _ReadXPRam
// MOVEA.L (A7)+,A0 standard PASCAL epilogue
// ADDQ.W #$6,A7
// JMP (A0)
// RTS
// This is a sequence of M68K instructions; unfortunately,
// a PowerMac compiler doesn't understand them. So we've
// got to assemble by hand <sigh>
//
// BTW, to write into xPRAM, replace 0xA051 in the sequence
// below with 0xA052
//pascal void read_extended_PRAM(char * where, const short size) =
static short read_extended_PRAM []=
{ 0x4280, 0x302F, 0x0004, 0x206F, 0x006, 0x4840, 0xA051, 0x205F, 0x5C4F, 0x4ED0 };
#define COMP_NORET_2(name, a1, a2) \
name##_procinfo = kPascalStackBased \
| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(a1))) \
| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(a2)))
#define RD_ALLOC(routine) static RoutineDescriptor \
routine##_RD = BUILD_ROUTINE_DESCRIPTOR(routine##_procinfo, routine)
enum {
COMP_NORET_2(read_extended_PRAM,char *,const short)
};
void main(void)
{
unsigned char whole_xPRAM_buffer[256];
UniversalProcPtr u_read_extended_PRAM =
NewRoutineDescriptor((long (*)())read_extended_PRAM,
read_extended_PRAM_procinfo,
kM68kISA);
CallUniversalProc(u_read_extended_PRAM,read_extended_PRAM_procinfo,
whole_xPRAM_buffer,sizeof(whole_xPRAM_buffer));
DisposeRoutineDescriptor(u_read_extended_PRAM);
printf("\ncontents of the xPRAM\n");
for(register int i=0; i<sizeof(whole_xPRAM_buffer); i+=16)
{
printf("\n%04x ",i);
for(register int j=0; j<16; j++)
printf("%s%02x", j%4 == 0 ? " " : "", whole_xPRAM_buffer[i+j]);
}
}
I tested the code on PowerMac 7100/80 and 8500/132, using CodeWarrior C++ versions 9 and 12.
oleg-at-okmij.org