Difference between revisions of "83Plus:OS:Raw Flash Commands"

From WikiTI
Jump to: navigation, search
(Created page with 'Raw Flash Commands The TI-83+ through TI-84+SE has a flash chip whose data can be erased and rewritten. Issuing write and erase commands is don…')
 
m (add clarifications about 68k and eZ80)
 
(22 intermediate revisions by 6 users not shown)
Line 1: Line 1:
[[Category:83Plus:OS Information|Raw Flash Commands]]
+
[[Category:83Plus:General Hardware Information|Raw Flash Commands]]
The TI-83+ through TI-84+SE has a flash chip whose data can be erased and rewritten. Issuing write and erase commands is done through memory-mapped writes. The flash chip will not accept any commands unless flash is unlocked. Additionally, any read from flash while issuing a command sequence will abort the command sequence. Consequentially, command sequences can only be issued from RAM.
+
[[Category:84PCSE:General Hardware Information|Raw Flash Commands]]
 +
All calculators with an "archive" and upgradable OS have a flash chip whose data can be erased and rewritten. Issuing write and erase commands is done through memory-mapped writes. The flash chip will not accept any commands unless flash is unlocked. Additionally, any read from flash while issuing a command sequence will abort the command sequence. Consequentially, command sequences can only be issued from RAM and the OS interrupt must be disabled. (You can have a custom interrupt if the IVT and ISR are located in RAM.)
  
== Writing and Erasing ==
+
Note: Although the code on this page is Z80-only, the commands described also apply to eZ80-based calculators that also have flash memory; the flash chips they use accept the same command set. However, the Z80 series requires to write a 0 over a 0, the eZ80 series doesn't care if you write a 0 or a 1 over a 0. In both cases, the resulting bit will be unchanged. Furthermore, the eZ80 series' chips have smaller sectors.
 +
 
 +
== Chip documentation ==
 +
 
 +
Calculators with parallel Flash use AM29F-series Flash chips, which have a common interface and are made by a number of manufacturers. For more detailed but not calculator-specific documentation, refer to [[File:AM29F400BT.pdf]], where AM29F400BT chips were used in early 83+ revisions.
 +
 
 +
== Basic Flash Commands ==
 
It takes the flash chip a long time to perform a write or erase operation. During this time, it is impossible to read data from the flash chip, because all reads will simply report a status byte.
 
It takes the flash chip a long time to perform a write or erase operation. During this time, it is impossible to read data from the flash chip, because all reads will simply report a status byte.
 +
 +
=== Reset ===
 +
You can reset the flash chip by writing 0F0h to 0000h.
 +
ld a, 0F0h
 +
ld (0), a
 +
Reset the flash chip if a program or erase operation fails, to abort either of those, and to leave autoselect mode. The flash chip does not accept resets during write or erase operations.
  
 
=== Writing ===
 
=== Writing ===
<nowiki>
+
The design of flash memory is such that a 0 can be written over a 1, but the reverse is not possible. Any write attempting to do this will fail. To write a 1 over a 0, see the below section. If it is attempted to write a 1 over a 0, the chip may fail to execute the operation. Therefore, it is a best practice to AND the value to be written with the value already there. This differs from the 68k series, where writing a 0 over a 0 will hurt the chip, and writing a 1 over a 0 will not change the value. On the eZ80 series, both are possible.
 +
 
 +
The write command consists of a series of four writes to memory areas mapping flash. The first two writes inform the flash chip that a command is being issued (preventing accidental writes), the next informs the flash chip what you want to do, and the final gives the address you want to write to and the data to write. If any reads or out-of-sequence writes are performed before the fourth write, the command will be aborted and the actual data write will not take place. Remember to copy flash write/erase code to RAM before execution.
 +
 
 +
The first three writes of the write sequence must be performed to addresses whose bottom 12 bits have a specific value. (TI's code writes to port 6 because they mistakenly believe 16 bits are required.) Specifically, write AA to xxxAAA, 55 to xxx555, A0 to xxxAAA, and then finally write what you want to the page and address you want.
 +
 
 +
When a byte is read while a write operation is in progress, the value returned is a status byte, where bit 7 is the inverse of what it will be when it is finished, and bit 5 will be reset during the operation and set if an error occured. To prevent a race condition inside the flash chip's circuitry, make sure to check the value again if bit 5 is set. After this, reset the chip using the appropriate command mentioned above.
 +
 
 +
Please note: this code needs to be rewritten.
 +
<nowiki>
 
writeFlashByte:
 
writeFlashByte:
 
; Writes a byte to flash.  Flash must be unlocked.  Be aware that pressing CLEAR
 
; Writes a byte to flash.  Flash must be unlocked.  Be aware that pressing CLEAR
Line 28: Line 50:
 
di
 
di
 
call writeFlashByteRaw
 
call writeFlashByteRaw
; ei
+
ei
 
pop bc ; restore page without screwing up flags
 
pop bc ; restore page without screwing up flags
 
ld a, b
 
ld a, b
Line 42: Line 64:
 
ld (0AAAh), a
 
ld (0AAAh), a
 
ld (hl), b ; Fourth bus cycle---program data
 
ld (hl), b ; Fourth bus cycle---program data
; Wait for data to be good
+
; Wait for the write operation to complete
 
ld a, 0FDh ; This checks for the CLEAR key.
 
ld a, 0FDh ; This checks for the CLEAR key.
 
out (keyPort), a ; If pressed, it aborts.
 
out (keyPort), a ; If pressed, it aborts.
Line 63: Line 85:
 
programDone:
 
programDone:
 
ret</nowiki>
 
ret</nowiki>
 +
 +
=== Erasing ===
 +
The design of flash memory is such that writing a 1 over a 0 is not possible, except in large blocks known as sectors. The flash chips TI likes to use have sectors that are almost all 64 K in size, except the last, which is broken up into one 32 K sector, two 8 K sectors, and one 16 K sector (in this order). These are split and grouped into 16 K pages for memory mapping. Erase operations take a long time, during which running code from flash is impossible. If you want, you could probably make something blink or something while you're waiting.
 +
 +
The status byte read has the same format as when writing a byte, but bit 7 is of course guaranteed to be reset during the operation, because the target byte is always FF.
 +
 +
Please note: this code needs to be rewritten.
 +
<nowiki>
 +
eraseSector:
 +
; Erases a sector of flash. Note: Use eraseSectorRaw for the certificate.
 +
; Inputs:
 +
;  - C: Page
 +
; Outputs:
 +
;  - Z on fail (this is opposite of writeFlashByte)
 +
; Kills:
 +
;  - AF, BC, HL
 +
in a, (memPageAPort)
 +
push af
 +
ld a, c
 +
out (memPageAPort), a
 +
ld hl, 4000h
 +
di
 +
call eraseSectorRaw
 +
ei
 +
pop bc
 +
ld a, b
 +
out (memPageAPort), a
 +
ret
 +
eraseSectorRaw:
 +
; Flash program sequence
 +
ld a, 0AAh ; First bus cycle---unlock
 +
ld (0AAAh), a
 +
ld a, 55h ; Second bus cycle---unlock
 +
ld (0555h), a
 +
ld a, 080h ; Third bus cycle---write command
 +
ld (0AAAh), a
 +
ld a, 0AAh ; Fourth bus cycle---unlock (again)
 +
ld (0AAAh), a
 +
ld a, 55h ; Fifth bus cycle---unlock (again)
 +
ld (0555h), a
 +
ld a, 30h ; Do not change this value. You could superbrick your calculator.
 +
ld (hl), a
 +
; Wait for the erase operation to complete
 +
ld a, 0FDh
 +
out (keyPort), a
 +
inc hl
 +
dec hl       
 +
eraseWaitLoop:
 +
in a, (keyPort)
 +
cp 0BFh
 +
jr z, abortErase
 +
ld a, (hl)
 +
bit 7, a
 +
jr nz, eraseDone
 +
bit 5, a
 +
jr z, eraseWaitLoop
 +
abortErase:
 +
ld a, 0F0h
 +
ld (4000h), a
 +
xor a
 +
eraseDone:
 +
ret
 +
</nowiki>
 +
 +
=== Erase Suspend ===
 +
The flash chip supports suspending an erase operation in program. This allows you to read data from the flash chip again. I'm not sure why would want to do this, but
 +
ld a, 0B0h
 +
ld (0), a
 +
will suspend an erase operation. Then
 +
ld a, 30h
 +
ld (0), a
 +
will resume the erase operation. According to the data sheet, you can actually start writing data to another sector and resume the erase later.
 +
 +
=== Full Chip Erase ===
 +
Do not use this command under any circumstances. It will fully brick your calculator by means of erasing the boot sector(s) (and everything else). (For the skeptics, this has actually been tested.)
 +
 +
The command itself is not included here for obvious reasons. In the odd case you would need it (you wouldn't), you can find it in the original datasheet.
 +
 +
== Autoselect Mode ==
 +
The flash chips support a set of commands known as the autoselect commands. These commands are intended to allow the flash chip to identify itself to a manufacturer and to verify that sectors are protected. However, they are also usable in-system. To use the autoselect commands, you must first unlock flash.
 +
 +
The basic code for an autoselect operation is
 +
; First bus cycle---unlock
 +
ld a, 0AAh
 +
ld (0AAAh), a
 +
; Second bus cycle---unlock
 +
ld a, 55h
 +
ld (0555h), a
 +
; Third bus cycle---write command
 +
ld a, 090h
 +
ld (0AAAh), a
 +
; Read autoselect code
 +
ld a, (address)
 +
ld b, a
 +
ld a, 0F0h ; You need to issue a reset command to exit autoselect mode
 +
ld (0000h), a
 +
where address is the code for the autoselect command. Address 0 returns the Manufacturer ID; address 2 returns the device ID. Known manufacturer IDs are
 +
{|-
 +
|<u>Manufacturer</u>
 +
|<u>ID</u>
 +
|-
 +
|AMD
 +
|01
 +
|-
 +
|Fujitsu
 +
|04
 +
|-
 +
|EON (read from 200h)
 +
|1C
 +
|-
 +
|Extended code, read real code from 200h&nbsp;&nbsp;&nbsp;
 +
|7F
 +
|-
 +
|Macronix
 +
|C2
 +
|}
 +
Though the manufacturer ID changes from unit to unit, the device ID should be consistent:
 +
{|-
 +
|<u>Flash Chip Size</u>&nbsp;&nbsp;&nbsp;
 +
|<u>ID</u>
 +
|-
 +
|512 K (5.0 V)
 +
|23
 +
|-
 +
|512 K (3.0 V)
 +
|B9
 +
|-
 +
|1 MB
 +
|DA
 +
|-
 +
|2 MB
 +
|C4
 +
|-
 +
|4 MB
 +
|A7
 +
|}
 +
Thus, a TI-83+SE and a TI-84+SE should both have C4 for the device ID; a TI-84+ should have DA for the device ID; and a TI-83+ should have 23 or B9 for the device.
 +
 +
If you swap the first page of any sector into the 4000h memory bank and read from 4004h (or 6004h for the second half of 8 K pages), it will return whether or not that sector is protected by the flash chip's built-in write/erase lock. The older TI-83+SE and TI-84+/SE units did not use the lock feature on the boot sector(s), so they return 0 for all sectors. The TI-84+CSE and TI-84+/SEs manufactured from 2013 up till an unknown date (before 2016) DO, however, have their boot sectors locked. The flash chip's lock feature can only be overridden by applying 12 V to the correct pin. (Applying 12 V to the wrong pin will probably fry the chip.)
 +
 +
It appears that TI used to use the flash chip's locking feature on the original TI-83+, because older units read 01 for sector 1Fh. (Older units read 23 for the device ID, and newer units read B9 for the device ID. It is possible that the switch to the B9 devices occurred at the same time as the switch to the ASIC for the TI-83+.) However, since at least 2007, TI has not used the locking feature on the TI-83+. These units always read 0. Therefore, it is still possible that the ASIC supports unlocking the boot sector of these units.

Latest revision as of 15:50, 4 October 2020

All calculators with an "archive" and upgradable OS have a flash chip whose data can be erased and rewritten. Issuing write and erase commands is done through memory-mapped writes. The flash chip will not accept any commands unless flash is unlocked. Additionally, any read from flash while issuing a command sequence will abort the command sequence. Consequentially, command sequences can only be issued from RAM and the OS interrupt must be disabled. (You can have a custom interrupt if the IVT and ISR are located in RAM.)

Note: Although the code on this page is Z80-only, the commands described also apply to eZ80-based calculators that also have flash memory; the flash chips they use accept the same command set. However, the Z80 series requires to write a 0 over a 0, the eZ80 series doesn't care if you write a 0 or a 1 over a 0. In both cases, the resulting bit will be unchanged. Furthermore, the eZ80 series' chips have smaller sectors.

Chip documentation

Calculators with parallel Flash use AM29F-series Flash chips, which have a common interface and are made by a number of manufacturers. For more detailed but not calculator-specific documentation, refer to File:AM29F400BT.pdf, where AM29F400BT chips were used in early 83+ revisions.

Basic Flash Commands

It takes the flash chip a long time to perform a write or erase operation. During this time, it is impossible to read data from the flash chip, because all reads will simply report a status byte.

Reset

You can reset the flash chip by writing 0F0h to 0000h.

ld a, 0F0h
ld (0), a

Reset the flash chip if a program or erase operation fails, to abort either of those, and to leave autoselect mode. The flash chip does not accept resets during write or erase operations.

Writing

The design of flash memory is such that a 0 can be written over a 1, but the reverse is not possible. Any write attempting to do this will fail. To write a 1 over a 0, see the below section. If it is attempted to write a 1 over a 0, the chip may fail to execute the operation. Therefore, it is a best practice to AND the value to be written with the value already there. This differs from the 68k series, where writing a 0 over a 0 will hurt the chip, and writing a 1 over a 0 will not change the value. On the eZ80 series, both are possible.

The write command consists of a series of four writes to memory areas mapping flash. The first two writes inform the flash chip that a command is being issued (preventing accidental writes), the next informs the flash chip what you want to do, and the final gives the address you want to write to and the data to write. If any reads or out-of-sequence writes are performed before the fourth write, the command will be aborted and the actual data write will not take place. Remember to copy flash write/erase code to RAM before execution.

The first three writes of the write sequence must be performed to addresses whose bottom 12 bits have a specific value. (TI's code writes to port 6 because they mistakenly believe 16 bits are required.) Specifically, write AA to xxxAAA, 55 to xxx555, A0 to xxxAAA, and then finally write what you want to the page and address you want.

When a byte is read while a write operation is in progress, the value returned is a status byte, where bit 7 is the inverse of what it will be when it is finished, and bit 5 will be reset during the operation and set if an error occured. To prevent a race condition inside the flash chip's circuitry, make sure to check the value again if bit 5 is set. After this, reset the chip using the appropriate command mentioned above.

Please note: this code needs to be rewritten.

writeFlashByte:
; Writes a byte to flash.  Flash must be unlocked.  Be aware that pressing CLEAR
; will abort the write.
; Inputs:
;  - B: Byte to write
;  - C: Page
;  - HL: Address to write to.  This will not be wrapped.
; Outputs:
;  - NZ on failure
; Kills:
;  - AF, BC
; Protips:
;  - Calling writeFlashByteRaw instead will skip the page changing
;  - Do push bc \ pop af afterwards to restore flags to pre-call values.  That's
;    right, documented side-effect programming! 
	in	a, (memPageAPort)	; save page
	push	af
	ld	a, c
	out	(6), a
	di
	call	writeFlashByteRaw
	ei
	pop	bc	; restore page without screwing up flags
	ld	a, b
	out	(memPageAPort), a
	ret
writeFlashByteRaw:
; Flash program sequence
	ld	a, 0AAh	; First bus cycle---unlock
	ld	(0AAAh), a
	ld	a, 55h	; Second bus cycle---unlock
	ld	(0555h), a
	ld	a, 0A0h	; Third bus cycle---write command
	ld	(0AAAh), a
	ld	(hl), b	; Fourth bus cycle---program data
; Wait for the write operation to complete
	ld	a, 0FDh		; This checks for the CLEAR key.
	out	(keyPort), a		; If pressed, it aborts.
	inc	hl
	dec	hl
programWaitLoop:
	in	a, (keyPort)
	cp	0BFh
	jr	z, abortProgram
	ld	a, b
	xor	(hl)
	bit	7, a
	jr	z, programDone
	bit	5, (hl)
	jr	z, programWaitLoop
abortProgram:
	ld	a, 0F0h
	ld	(0000h), a
	inc	a
programDone:
	ret

Erasing

The design of flash memory is such that writing a 1 over a 0 is not possible, except in large blocks known as sectors. The flash chips TI likes to use have sectors that are almost all 64 K in size, except the last, which is broken up into one 32 K sector, two 8 K sectors, and one 16 K sector (in this order). These are split and grouped into 16 K pages for memory mapping. Erase operations take a long time, during which running code from flash is impossible. If you want, you could probably make something blink or something while you're waiting.

The status byte read has the same format as when writing a byte, but bit 7 is of course guaranteed to be reset during the operation, because the target byte is always FF.

Please note: this code needs to be rewritten.

eraseSector:
; Erases a sector of flash. Note: Use eraseSectorRaw for the certificate.
; Inputs:
;  - C: Page
; Outputs:
;  - Z on fail (this is opposite of writeFlashByte)
; Kills:
;  - AF, BC, HL
	in	a, (memPageAPort)
	push	af
	ld	a, c
	out	(memPageAPort), a
	ld	hl, 4000h
	di
	call	eraseSectorRaw
	ei
	pop	bc
	ld	a, b
	out	(memPageAPort), a
	ret
eraseSectorRaw:
; Flash program sequence
	ld	a, 0AAh	; First bus cycle---unlock
	ld	(0AAAh), a
	ld	a, 55h	; Second bus cycle---unlock
	ld	(0555h), a
	ld	a, 080h	; Third bus cycle---write command
	ld	(0AAAh), a
	ld	a, 0AAh	; Fourth bus cycle---unlock (again)
	ld	(0AAAh), a
	ld	a, 55h	; Fifth bus cycle---unlock (again)
	ld	(0555h), a
	ld	a, 30h ; Do not change this value. You could superbrick your calculator.
	ld	(hl), a
; Wait for the erase operation to complete
	ld	a, 0FDh
	out	(keyPort), a
	inc	hl
	dec	hl        
eraseWaitLoop:
	in	a, (keyPort)
	cp	0BFh
	jr	z, abortErase
	ld	a, (hl)
	bit	7, a
	jr	nz, eraseDone
	bit	5, a
	jr	z, eraseWaitLoop
abortErase:
	ld	a, 0F0h
	ld	(4000h), a
	xor	a
eraseDone:
	ret

Erase Suspend

The flash chip supports suspending an erase operation in program. This allows you to read data from the flash chip again. I'm not sure why would want to do this, but

ld a, 0B0h
ld (0), a

will suspend an erase operation. Then

ld a, 30h
ld (0), a

will resume the erase operation. According to the data sheet, you can actually start writing data to another sector and resume the erase later.

Full Chip Erase

Do not use this command under any circumstances. It will fully brick your calculator by means of erasing the boot sector(s) (and everything else). (For the skeptics, this has actually been tested.)

The command itself is not included here for obvious reasons. In the odd case you would need it (you wouldn't), you can find it in the original datasheet.

Autoselect Mode

The flash chips support a set of commands known as the autoselect commands. These commands are intended to allow the flash chip to identify itself to a manufacturer and to verify that sectors are protected. However, they are also usable in-system. To use the autoselect commands, you must first unlock flash.

The basic code for an autoselect operation is

; First bus cycle---unlock
ld	a, 0AAh
ld	(0AAAh), a
; Second bus cycle---unlock
ld	a, 55h
ld	(0555h), a
; Third bus cycle---write command
ld	a, 090h
ld	(0AAAh), a
; Read autoselect code
ld	a, (address)
ld	b, a
ld	a, 0F0h ; You need to issue a reset command to exit autoselect mode
ld	(0000h), a

where address is the code for the autoselect command. Address 0 returns the Manufacturer ID; address 2 returns the device ID. Known manufacturer IDs are

Manufacturer ID
AMD 01
Fujitsu 04
EON (read from 200h) 1C
Extended code, read real code from 200h    7F
Macronix C2

Though the manufacturer ID changes from unit to unit, the device ID should be consistent:

Flash Chip Size    ID
512 K (5.0 V) 23
512 K (3.0 V) B9
1 MB DA
2 MB C4
4 MB A7

Thus, a TI-83+SE and a TI-84+SE should both have C4 for the device ID; a TI-84+ should have DA for the device ID; and a TI-83+ should have 23 or B9 for the device.

If you swap the first page of any sector into the 4000h memory bank and read from 4004h (or 6004h for the second half of 8 K pages), it will return whether or not that sector is protected by the flash chip's built-in write/erase lock. The older TI-83+SE and TI-84+/SE units did not use the lock feature on the boot sector(s), so they return 0 for all sectors. The TI-84+CSE and TI-84+/SEs manufactured from 2013 up till an unknown date (before 2016) DO, however, have their boot sectors locked. The flash chip's lock feature can only be overridden by applying 12 V to the correct pin. (Applying 12 V to the wrong pin will probably fry the chip.)

It appears that TI used to use the flash chip's locking feature on the original TI-83+, because older units read 01 for sector 1Fh. (Older units read 23 for the device ID, and newer units read B9 for the device ID. It is possible that the switch to the B9 devices occurred at the same time as the switch to the ASIC for the TI-83+.) However, since at least 2007, TI has not used the locking feature on the TI-83+. These units always read 0. Therefore, it is still possible that the ASIC supports unlocking the boot sector of these units.