Using the IIGS Battery-Backed-Up RAM and Clock From Assembly Language.txt

(23 KB) Pobierz
Using the IIGS Battery-Backed-Up RAM and Clock From Assembly Language

Neil Parker

nparker@cie.uoregon.edu
parker@corona.uoregon.edu
Version 1.00
January 1994

COPYRIGHT by 1993 Neil Parker
All Rights Reserved

========
Abstract
========
This technical note discusses how a machine-language programmer can access
the Apple IIGS battery-backed-up RAM and clock hardware directly, bypassing
the firmware and system software.  The BRAM and clock are normally accessed
through a set of subroutines in the Miscellaneous Toolset, which is the only
Apple-supported method accessing them.  Direct manipulation of the hardware
provides access to several features that the Miscelaneous Toolset does not,
such as the "raw" time and the BRAM write-protect register.

===========
Terminology
===========

Terminology:
	Bit 0		The least significant bit in a byte
	Bit 7		The most  significant bit in a byte
	BRAM		Battery backed-up RAM.  Information stored in the
			BRAM is not lost when the IIGS is turned off.
	CLOCKCTL	Clock/BRAM protocol control register
	CLOCKDATA	Clock/BRAM data register

========================
Accessing the IIGS Clock
========================
The IIGS BRAM/Clock chip seems to be identical to the one documented in
_The Macintosh Family Hardware Reference_.  The BRAM/Clock chip uses a
simple protocol to transfer data in and out using two memory locations:

	Register	Address		Function				
	---------	----------	------------------------------------
	CLOCKCTL	0xC034		Clock/BRAM control register
	CLOCKDATA	0xC033		Clock/BRAM command and data register

The protocol for a "write" is:
	CLOCKDATA <-- command specifying register to be written
	CLOCKCTL  <-- bits to initiate transfer
	CLOCKDATA <-- data to be written
	CLOCKCTL  <-- bits to continue transfer

The protocol for a "read" is:
	CLOCKDATA <-- command specifying register to be read
	CLOCKCTL  <-- bits to initiate transfer
	CLOCKDATA --> data from BRAM/Clock
at the conclusion of this sequence, CLOCKDATA contains the desired data.

The available commands are shown in the table:

	Comamnd     Access	Purpose
	--------    ------	--------------------------------------
	z0000001     R/W	Clock seconds register lo
	z0000101     R/W  	Clock seconds register next-to-lo
	z0001001     R/W  	Clock seconds register next-to-hi
	z0001101     R/W  	Clock seconds register hi
	00110001    W-Only	Write to test register
				Always set bits 6 & 7 to "0".
	00110101    W-Only	Write to write-protect register
				Setting bit 7 to "1" locks out further
				writes to the BRAM/Clock
	z010ab01     R/W  	Access BRAM address 100ab
	z1abcd01     R/W  	Access BRAM address 0abcd
	z0111abc     R/W  	Followed by 0defgh00.
				Access BRAM address abcdefgh

The "Command" column contains entries beginning with an "z".  This letter
is replaced by a "0" or "1" indicating the desired access type.  A value
of "0" for this bit specifies a write, while a value of "1" for this bit
specifies a read.

For example, the command to access the low byte of the clock's seconds
register is "z0000001".  To write a value to this register, write the
byte "00000001" followed by the new value for the low byte of the seconds
register.  To read the value of the low byte of the clock seconds register,
write the byte "10000001", and then read the value from CLOCKDATA.

----------------
Seconds Register
----------------
The four bytes of the seconds register form a 32-bit count of seconds since
midnight, January 1, 1904.  They should always be accessed in lo-to-hi
order.  When reading the clock, the ROM reads all four registers several
times, until it gets the same value twice in a row.  When writing, the ROM
immediately tests the written value by reading it back -- if the values
don't match, it tries again.

----------------------------------------
Test Register and Write-Protect Register
----------------------------------------
The test register and the write-protect register are write-only registers.
Setting the high bit of the write-protect register prevents any of the
other registers (or BRAM locations) from being written to, and clearing it
enables writes to the registers and BRAM locations.  The two high-order
bits of the test register are used as control bits during testing, and
should normally be set to 0 (setting them to anything else interferes with
normal clock functioning).

I can't find any code in the IIGS ROM that accesses these registers.

---------------------
Battery Ram Locations
---------------------
The z010ab01 and z1abcd01 commands are holdovers from the early Macintosh
days when there were only 20 bytes of BRAM.  The IIGS doesn't seem to use
these functions--it uses the more general z0111abc 0defgh00 command
instead.

Note that the z0111abc 0defgh00 command is two bytes long.  For reading,
read the data byte after writing the second byte.  For writing, write the
data byte after writing the second byte.

========================
Reading/Writing the BRAM
========================
The CLOCKCTL byte is used to transfer data to and from the BRAM and the
clock.  Only the upper three bits of the CLOCKCTL byte at $C034 are used
by the BRAM/Clock; the lower five bits contain the current screen border
and are thus not used by the BRAM/Clock.  The bits are organized as:
		  7   6   5   4   3   2   1   0  
		+---+---+---+---+---+---+---+---+
		| S | T | A | Z | B | B | B | B |
		+---+---+---+---+---+---+---+---+
	where:
		B	Screen Border Color (Unused By BRAM/Clock)
		S	Start Transaction
		T	Transaction Type (Read/Write)
		A	Clock Enable Assert
		Z	This bit should always be set to 0

------------------
Start Transfer Bit
------------------
Bit 7 is the "Start Transaction" bit.  Writing a "1" to this bit begins a
read or write transaction.  All this means is that the BRAM/Clock begins
processing the value in CLOCKDATA.  When the operation has completed, Bit
7 will be reset to "0".  Thus, testing this bit allows the programmer to
determine when an operation has completed.

--------------------
Transaction Type Bit
--------------------
Bit 6 specifies the "Transaction Type" bit, either a read or a write.  The
values and meanings for this bit are shown below:
	0 = Write
	1 = Read

-----------------------
Clock Enable Assert Bit
-----------------------
Bit 5 is the "Clock Enable Assert" bit.  All the documentation says this
bit should be set to "0" before beginning a transfer, and should be set
back to "1" after the transfer is complete.  However, the ROM routines
do the opposite -- they set the bit to "1" at the beginning of a transfer,
and "0" when the transfer completes.

--------------
Remaining Bits
--------------
Bit 4 should always be 0.  Bits 0-3 have nothing to do with the BRAM/Clock
-- they control the screen border color.

--------------------
Writing Data To BRAM
--------------------
To write a byte, write the command indicating which location is desired to
CLOCKDATA.  Then set bits 7 and 5 of CLOCKCTL, and clear bit 6 of CLOCKCTL.
When bit 7 is cleared by the BRAM, CLOCKDATA can be loaded with the data
value to be written.  If you have more data to write from the BRAM, bits 6
and 5 in CLOCKCTL need not be changed between transfers.  After each write,
clear bit 5.

A write uses the following protocol:
	CLOCKDATA = "write" cmd for desired register or BRAM location
	CLOCKCTL[bit 7] = 1
	CLOCKCTL[bit 6] = 0
	CLOCKCTL[bit 5] = 1
	wait until CLOCKCTL[bit 7] == 0
	if this is a two-byte command ("00111abc 0defgh00")
		CLOCKDATA = second byte of command
		CLOCKCTL[bit 7] = 1
		CLOCKCTL[bit 6] = 0
		CLOCKCTL[bit 5] = 1
		wait until CLOCKCTL[bit 7] = 0
		end if
	CLOCKDATA = data to be written
	CLOCKCTL[bit 7] = 1
	CLOCKCTL[bit 6] = 0
	CLOCKCTL[bit 5] = 1
	wait until CLOCKCTL[bit 7] == 0
	CLOCKCTL[bit 5] = 0

----------------------
Reading Data From BRAM
----------------------
To read a byte, write the command indicating which location is desired to
CLOCKDATA.  Then set bits 7, 6, and 5 of CLOCKCTL.  When bit 7 is cleared
by the BRAM, CLOCKDATA contains the data value.  If you have more data to
read from the BRAM, bits 6 and 5 in CLOCKCTL need not be changed between
transfers.  After each read, clear bit 5.

The algorithm looks like this:
	CLOCKDATA = "read" cmd for desired register or BRAM location
        CLOCKCTL[bit 7] = 1
	CLOCKCTL[bit 6] = 0
	CLOCKCTL[bit 5] = 1
	wait until CLOCKCTL[bit 7] == 0
        If this is a two-byte command ("10111abc 0defgh00")
		CLOCKDATA = second byte of "read" command
		CLOCKCTL[bit 7] = 1
		CLOCKCTL[bit 6] = 0
		CLOCKCTL[bit 5] = 1
		wait until CLOCKCTL[bit 7] == 0
		end if
	CLOCKCTL[bit 7] = 1
	CLOCKCTL[bit 6] = 1
	CLOCKCTL[bit 5] = 1
	wait until CLOCKCTL[bit 7] = 0
	result = CLOCKDATA
	CLOCKCTL[bit 5] = 0

------------------
Computing Checksum
------------------
Any change to the BRAM invalidates the checksum unless the programmer
explicitly recomputes the checksum and stores it in the BRAM.  An invalid
checksum causes the IIGS to reload the BRAM with default values.  The
checksum is a 16-bit number computed by the following algorithm:
	initialize checksum to 0
	start at end of BRAM buffer (BRAM locations $FA and $FB)
	repeat
		rotate checksum left 1 bit
		checksum = checksum + word from buffer
		buffer position = buffer position - 1 byte
	until we reach the beginning of the buffer

The checksum is stored in BRAM bytes $FC (low byte) and $FD (high byte).
The checksum exclusive-ORed with the constant $AAAA is stored in BRAM bytes
$FE (low byte) and $FF (high byte).

The source code for computing the BRAM checksum is included in the ROM
disassembly below.

------...
Zgłoś jeśli naruszono regulamin