Difference between revisions of "83Plus:OS:Variable Storage in the User Archive"

From WikiTI
Jump to: navigation, search
m (Forgot category)
(BrandonW said it so it must be true.)
 
(4 intermediate revisions by 2 users not shown)
Line 5: Line 5:
 
The user archive differs between the 83+, 83+SE, 84+, and 84+SE. The "archive" for programs, appvars, groups, lists, REALs, matrices, and every other data type grow upwards from page 08h. On the TI-83+, the last page of the archive is page 15h; on the TI-84+, the last page is page 29h; and on the TI-83+SE and TI-84, the last page is page 69h. You can read data from the archive using [[83Plus:BCALLs:5017|FlashToRAM]], or though paging with [[83Plus:Ports:06|port 6]].
 
The user archive differs between the 83+, 83+SE, 84+, and 84+SE. The "archive" for programs, appvars, groups, lists, REALs, matrices, and every other data type grow upwards from page 08h. On the TI-83+, the last page of the archive is page 15h; on the TI-84+, the last page is page 29h; and on the TI-83+SE and TI-84, the last page is page 69h. You can read data from the archive using [[83Plus:BCALLs:5017|FlashToRAM]], or though paging with [[83Plus:Ports:06|port 6]].
  
The flash memory is divided into sectors of groups of four pages. The flash chip can program any single bit from a 1 to a 0 at any time, but erasing from a 0 to a 1 can only be done on a per-sector basis. Each sector has a byte at the very beginning (4000h, pages 08h, 0Ch, etc.) which holds the status of that sector. The following values mean it is valid:
+
The flash memory is divided into sectors of four pages. The flash chip can program any single bit from a 1 to a 0 at any time, but erasing from a 0 to a 1 can only be done on a per-sector basis. Each sector has a byte at the very beginning (4000h, pages 08h, 0Ch, etc.) which holds the status of that sector. The following values mean it is valid:
 
* 0FCh
 
* 0FCh
 
* 0FFh
 
* 0FFh
Line 13: Line 13:
 
After the status byte for that sector, the archived data begins. The 83+ SDK has some information on this, but it's repeated here. Each variable entry begins with three bytes:
 
After the status byte for that sector, the archived data begins. The 83+ SDK has some information on this, but it's repeated here. Each variable entry begins with three bytes:
 
  Flag | sizeLow | sizeHigh
 
  Flag | sizeLow | sizeHigh
The flag byte will be 0FCh (valid) or 0F0h (deleted, ignore it). The size word can be used to skip to the next variable. After this will be the variable's VAT entry. Note that the VAT entries stored in RAM are stored backwards, but the VAT entries stored in flash are stored forwards.
+
The flag byte will be 0FCh (valid) or 0F0h (deleted, ignore it). (It may also 0FEh, meaning that the OS was still in the process of writing to it when you got control.) The size word can be used to skip to the next variable. After this will be the variable's VAT entry. Note that the VAT entries stored in RAM are stored backwards, but the VAT entries stored in flash are stored forwards.
 
  T | T2 | Version | addressLow | addressHigh | Page | Name Length | (Name)
 
  T | T2 | Version | addressLow | addressHigh | Page | Name Length | (Name)
 
The address and page of this entry points to the flag byte at the start of the entry, not the start of the variable's data. Don't forget, most data types start with a size word, which will appear directly after the name.
 
The address and page of this entry points to the flag byte at the start of the entry, not the start of the variable's data. Don't forget, most data types start with a size word, which will appear directly after the name.
Line 62: Line 62:
 
Start at page 08h and access the status byte. If it is 0FEh, skip to the next sector (4 pages). If you find any other status byte, abort.
 
Start at page 08h and access the status byte. If it is 0FEh, skip to the next sector (4 pages). If you find any other status byte, abort.
  
Once you've found a valid sector, start reading each entry by checking the status byte (0FCh for exists, 0F0h for deleted). Then read the size and add it to your current location to find the next VAT entry (it can and will span to the next page and sector (don't forget the status byte)).
+
Once you've found a valid sector, start reading each entry by checking the status byte (0FCh for exists, 0F0h for deleted). Then read the size and add it to your current location to find the next VAT entry (it can and will span to the next page).
  
 
Whenever you find 0FFh, stop and add an appropriate VAT entry and data. Make sure there's enough space left on the sector to write your data.
 
Whenever you find 0FFh, stop and add an appropriate VAT entry and data. Make sure there's enough space left on the sector to write your data.
Line 76: Line 76:
 
000h = deleted Flash application (this is part of the app header).
 
000h = deleted Flash application (this is part of the app header).
  
If there is one multipage application on the 84+SE, for example, then the first byte of page 69h is 080h, and page 68h will contain the second page of the application. THE FIRST BYTE OF THIS PAGE HAS NO MEANING. To traverse this, you must access the Flash application's number of pages on the base page (offset 401Ch) and use this to go backwards a certain number of pages.
+
If there is one multipage application on the 84+SE, for example, then the first byte of page 69h is 080h, and page 68h will contain the second page of the application. THE FIRST BYTE OF THIS PAGE HAS NO MEANING. To traverse this, you must access the Flash application's number of pages on the base page by parsing the application's header with the field search routines and use this to go backwards a certain number of pages.
  
The first page to contain 0FFh as its first byte is the first empty one. Applications are never fragmented, so when you see 0FFh, there are no more applications. Applications and archive data never occupy the same sector.
+
Determining the "last" app page is rather difficult.  If a page begins with FFh (or any other value other than 80h or 00h), it cannot be the start of an application. If a page begins with 80h or 00h, followed by 0Fh, it ''might'' be the start of an application.  Of course, since archived variables can contain any sort of data you like, there is no way to tell for sure whether you're looking at an app or an archived variable, but for most purposes, it's probably safe to assume that if it looks like an app, it is one.
 +
 
 +
(The definitive answer to "is this an app or not?" can only be found on the certificate page, which is unreadable by user programs.  At the same time, many OS routines do make the assumption that "if it looks like an app, it is one".)
 +
 
 +
Note that applications and archive data are never allowed to occupy the same sector.
 
<!--Information about adding flash apps intentionally left out.-->
 
<!--Information about adding flash apps intentionally left out.-->
 +
 +
=== Example ===
 +
The following code will walk through the list of installed applications.
 +
    ; Determine first application page
 +
    ld b,15h
 +
    in a,([[83Plus:Ports:02|2]])    ; is calculator a TI-83+ BE?
 +
    add a,a
 +
    jr nc,traverse_apps_loop
 +
    ld b,29h
 +
    in a,([[83Plus:Ports:21|21h]])  ; is calculator a TI-84+ BE?
 +
    and 3
 +
    jr z,traverse_apps_loop
 +
    ld b,69h
 +
traverse_apps_loop:
 +
    ; Check if page B is a possible starting app page
 +
    ld hl,4000h
 +
    B_CALL [[83Plus:BCALLs:501A|LoadDEIndPaged]]
 +
    ld a,e
 +
    and 7Fh
 +
    jr nz,traverse_apps_done
 +
    ld a,d
 +
    cp 0Fh
 +
    jr nz,traverse_apps_done
 +
 +
    ; Check for page count field in app header
 +
    ld a,b
 +
    B_CALL [[83Plus:BCALLs:509B|FindAppNumPages]]
 +
    sub c
 +
    cp b
 +
    jr nc,traverse_apps_done
 +
 +
    ; Page B is the start of a (possibly deleted) app
 +
    ; C is the number of pages
 +
    ; A (= B - C) is the next possible app page
 +
 +
    ld b,a
 +
    jr traverse_apps_loop
 +
 +
traverse_apps_done:
  
 
==Credits and Contributions==
 
==Credits and Contributions==
 
* Brandon Wilson, for originally writing most of this up.
 
* Brandon Wilson, for originally writing most of this up.

Latest revision as of 17:05, 23 October 2011

The SDK doesn't have much information on this. The SDK mostly claims that you can't access in data in the archive without unarchiving it; this is untrue, for you can in fact access the data using FlashToRAM. But before that can work, you need to understand how data is stored in flash.

Archive

The user archive differs between the 83+, 83+SE, 84+, and 84+SE. The "archive" for programs, appvars, groups, lists, REALs, matrices, and every other data type grow upwards from page 08h. On the TI-83+, the last page of the archive is page 15h; on the TI-84+, the last page is page 29h; and on the TI-83+SE and TI-84, the last page is page 69h. You can read data from the archive using FlashToRAM, or though paging with port 6.

The flash memory is divided into sectors of four pages. The flash chip can program any single bit from a 1 to a 0 at any time, but erasing from a 0 to a 1 can only be done on a per-sector basis. Each sector has a byte at the very beginning (4000h, pages 08h, 0Ch, etc.) which holds the status of that sector. The following values mean it is valid:

  • 0FCh
  • 0FFh
  • 0F0h

The swap sector is also stored in this area, and it can be any full 64K sector. It is identified with the byte 0FEh.

After the status byte for that sector, the archived data begins. The 83+ SDK has some information on this, but it's repeated here. Each variable entry begins with three bytes:

Flag | sizeLow | sizeHigh

The flag byte will be 0FCh (valid) or 0F0h (deleted, ignore it). (It may also 0FEh, meaning that the OS was still in the process of writing to it when you got control.) The size word can be used to skip to the next variable. After this will be the variable's VAT entry. Note that the VAT entries stored in RAM are stored backwards, but the VAT entries stored in flash are stored forwards.

T | T2 | Version | addressLow | addressHigh | Page | Name Length | (Name)

The address and page of this entry points to the flag byte at the start of the entry, not the start of the variable's data. Don't forget, most data types start with a size word, which will appear directly after the name.

Note that data can span multiple pages, but cannot cross sector boundries.

Example

This will search for a program, appvar, or group in the archive, and, if in the archive, return the amount of data in the item and location of the data. This code should work.

; Inputs:
;  - OP1: name of variable
; Outputs:
;  - A: Page data is on
;  - HL: Pointer to data
;  - DE: Size of data
;  - T1 and T2 can be found at 8003h and 8004h.
B_CALL ChkFindSym
jr c, errorNotFound
ld a, b
or a
jr z, itemIsInRAM
push de
ex de, hl
ld de, 8000h
ld bc, 30
B_CALL FlashToRAM
ld a, (8009h)
ld hl, 800Ah
add l, a ; note that you must change this to a 16-bit add if you move the above address
ld e, (hl)
inc hl
ld d, (hl)
ld a, (8008h)
pop bc
res 7, h
add hl, bc
bit 7, h
ret z
res 7, h
inc a
ret

errorNotFound:
; Oh no!
itemIsInRAM:
; Getting the data is now much easier.

Adding to Archive

Start at page 08h and access the status byte. If it is 0FEh, skip to the next sector (4 pages). If you find any other status byte, abort.

Once you've found a valid sector, start reading each entry by checking the status byte (0FCh for exists, 0F0h for deleted). Then read the size and add it to your current location to find the next VAT entry (it can and will span to the next page).

Whenever you find 0FFh, stop and add an appropriate VAT entry and data. Make sure there's enough space left on the sector to write your data.

Don't write directly to flash unless you know what you're doing.

Applications

Applications are stored at the top of the archive and grow downward. On the 83+, the top page is 15h; on the 84+, it is 29h, and on the 83+SE/84+SE it is at 69h. The following status bytes are used on each base page:

0FFh = empty. 080h = valid Flash application (this is part of the app header). 000h = deleted Flash application (this is part of the app header).

If there is one multipage application on the 84+SE, for example, then the first byte of page 69h is 080h, and page 68h will contain the second page of the application. THE FIRST BYTE OF THIS PAGE HAS NO MEANING. To traverse this, you must access the Flash application's number of pages on the base page by parsing the application's header with the field search routines and use this to go backwards a certain number of pages.

Determining the "last" app page is rather difficult. If a page begins with FFh (or any other value other than 80h or 00h), it cannot be the start of an application. If a page begins with 80h or 00h, followed by 0Fh, it might be the start of an application. Of course, since archived variables can contain any sort of data you like, there is no way to tell for sure whether you're looking at an app or an archived variable, but for most purposes, it's probably safe to assume that if it looks like an app, it is one.

(The definitive answer to "is this an app or not?" can only be found on the certificate page, which is unreadable by user programs. At the same time, many OS routines do make the assumption that "if it looks like an app, it is one".)

Note that applications and archive data are never allowed to occupy the same sector.

Example

The following code will walk through the list of installed applications.

    ; Determine first application page
    ld b,15h
    in a,(2)    ; is calculator a TI-83+ BE?
    add a,a
    jr nc,traverse_apps_loop
    ld b,29h
    in a,(21h)  ; is calculator a TI-84+ BE?
    and 3
    jr z,traverse_apps_loop
    ld b,69h
traverse_apps_loop:
    ; Check if page B is a possible starting app page
    ld hl,4000h
    B_CALL LoadDEIndPaged
    ld a,e
    and 7Fh
    jr nz,traverse_apps_done
    ld a,d
    cp 0Fh
    jr nz,traverse_apps_done

    ; Check for page count field in app header
    ld a,b
    B_CALL FindAppNumPages
    sub c
    cp b
    jr nc,traverse_apps_done

    ; Page B is the start of a (possibly deleted) app
    ; C is the number of pages
    ; A (= B - C) is the next possible app page

    ld b,a
    jr traverse_apps_loop

traverse_apps_done:

Credits and Contributions

  • Brandon Wilson, for originally writing most of this up.