Format of Flash and ROM SSD cards


This document describes information about the structure of existing types of Flash and ROM SSDs. It does not apply to RAM cards as they use FAT16. It does, however, appear to apply to the ROM in the 3-Link pod and the SSD ROM used to ship the Spreadsheet.

The term "erased flash card" is one that was partially formatted, after which the format was stopped, and then reformatted. This causes the contents of the start of the flash card, which is normally preserved by the formatting process (see Psionics file FILEIO) to be lost.

All trip values are offsets from the start of the card. The term "NULL" means the value 0xFFFFFF.

Filesystem Header

Flash and ROM cards always begin with:

Offset Length Description
0 2 0xF1A5 ('Flas')
2 4 unique ID of SSD
6 2 unknown (only ever seen 1)
8 3 unknown (only ever seen 1)
11 3 pointer to the root directory entry
14 8 volume name
22 3 volume extension
25 4 count of times flash card has been formatted, or 0xFFFFFFFF for ROMs
29 (Flash only) 2 size of the card in 256 byte units (i.e. 0x1000 = 1MB)
31 (Flash only) 2 unknown (only ever seen 0xFFFF)
33 (Flash only) or 29 (ROM only) Until \0 Identity String

The unique ID is placed there when the SSD is first created, and is preserved even when the SSD is formatted. There is no obvious pattern to the IDs. Note that different 3-Link pods have different unique IDs.

If the first byte of the volume name is 00, the volume name is not in offsets 14 to 24, but is instead found in a special file record within the root directory.

The identity string is terminated by a zero byte or a 0xFF byte. The identity strings seen to date are:

  • PSION 1.0 01/80
  • PSION 1.0 06/80
  • PSION 1.0
  • Copyright (c) Psion Plc 1991

The first two were seen on flash cards, the third on an erased flash card, and the last on both the 3-Link pod ROM and the spreadsheet SSD ROM.

The rest of the flash card is divided into records (unused portions of the card are full of 0xFF bytes).

The root directory entry is a filing system record. The directory name is ROOT.

File and folder entries

Filesystem records represent entries in directories: other directories, files, and volume names. A filing system record is 31 bytes if it represents a file, and 26 bytes otherwise:

Offset Length Description
0 3 Pointer to the next entry in same directory
3 8 Entry name
11 3 Entry extension
14 1 Flags
15 3 Pointer to first entry record
18 3 Pointer to alternate record
21 1 Entry properties
22 2 Time code
24 2 Date code
26 (File only) 3 Pointer to start of first data record
29 (File only) 2 Length of first data record

Flags and Properties

The flags are as follows:

Bit 0 1
0 entry deleted entry still valid
1   properties, time, and date valid
2 directory file or volume name
3   no entry record (so NULL at offset 15)
4   no alternate record (so NULL at offset 18)
5   no more entries in same directory (so NULL at offset 0)
6 all entries seen so far have this bit set to 1
7 all entries seen so far have this bit set to 1

The first entry record is:

  • for files: first continuation record of file; if the pointer is NULL, the file only contains one data record
  • for directories: filing system record of first directory entry; if the pointer is NULL, the directory is empty
  • for volume names: all entries seen so far have a NULL pointer

If the alternate record exists, then most of the data in the record pointing to the alternate record should be ignored, and replaced by the corresponding data in the alternate record. The alternate record is:

  • for files: a continuation record; ignore the first entry record and the data record in the original record
  • for directories: alternate records are not used
  • for volume names: alternate records are not used

The entry properties are:

Bit 1
0 Read-only
1 Hidden
2 System
3 Is a volume name
4 Is a directory
5 Modified

Time and Date Codes

The time code is: 0x800 * hour + 0x20 * minute + second / 2

The date code is: 0x200 * (year - 1980) + 0x20 * month + date

File Records

A file is represented by a linked list of records. The first record is the filing system record, or its alternate, and the remaining records are all continuation records. A continuation record is 17 bytes:

Offset Length Description
0 1 Flags (as above)
1 3 pointer to next continuation record
4 3 pointer to alternate continuation record
7 3 pointer to data record
10 2 length of data record, or 0xFFFF if it is unknown and the file is still open
12 1 entry properties
13 2 Time code
15 2 Date code

Note that bits 5, 2, and 0 of the flags will always be set, and that bits 4 and 3 refer to offsets 1 and 4 respectively. In addition, it is possible for bit 3 to be clear but for there to be no next continuation record.

To examine all the data in a file, start at the filing system record, and then proceed as follows for each record in turn:

If flag bit 4 is set, go to the alternate record and repeat this step. Otherwise the next part of the file is given by the data pointer and length within this record.

After using the data: if flag bit 3 is clear and the next continuation record pointer is not null, go to that record, starting by examining flag bit 4. Otherwise the end of file has been reached.

As files are modified, the records on the flash card become out of date. For example, data that has been overwritten will remain on the card. In particular, the properties, time, and date bytes of records will remain even when they are not valid (as indicated by flag bit 1). Also note that a change to a file may cause several continuation records to be written at the same time. In these circumstances, only one of these will have the correct properties, time, and date, and the others will be written without them, and with some other record overlapping these 5 bytes.

Reading flash cards

On later versions of EPOC16, flash cards can be read with FilLocReadPDD (see Psionics file SYSCALLS). If this is not available, the following code can be used to read flash cards. The left four columns give individual bytes; the right column is the bytes reorganised as long words.

EB 3A 55 E8 E8553AEB
95 00 83 EC EC830095
0E 8B F4 8D 8DF48B0E
7E 28 BA 21 21BA287E
0A CD 85 83 8385CD0A
C4 0E 8B D8 D88B0EC4
B4 02 CD 85 85CD02B4
89 46 00 89 89004689
5E 02 CD 8F 8FCD025E
8C 46 32 B4 B432468C
00 CD 88 80 8088CD00
E4 0F 89 46 46890FE4
30 9C FA 1E 1EFA9C30
07 9D 5D CB CB5D9D07
83 FB 04 72 7204FB83
05 B8 FC FF FFFCB805
EB 51 8B F0 F08B51EB
55 E8 4F 00 004FE855
88 5E 20 FF FF205E88
36 12 00 8D 8D001236
46 04 A3 12 12A30446
00 FF 36 20 2036FF00
00 80 26 20 20268000
00 00 E4 14 14E40000
C4 7E 30 26 26307EC4
FE 45 0D 1E 1E0D45FE
07 8B FA B0 B0FA8B07
00 FF 5E 00 005EFF00
98 8B D8 C4 C4D88B98
7E 30 26 FE FE26307E
4D 0D 9C FA FA9C0D4D
1E 07 9D 8F 8F9D071E
06 20 00 80 80002006
3E 20 00 00 0000203E
74 02 E6 14 14E60274
8B C3 8F 06 068FC38B
12 00 5D CB CB5D0012
58 FF E0 E8 E8E0FF58
FA FF 05 06 0605FFFA
00 8B E8 C3 C3E88B00
00 00 00 00 00000000
00 00 00 00 00000000
00 00 00 00 00000000
00 00 00 00 00000000
00 00 00 00 00000000
00 00 00 00 00000000
00 00 00 00 00000000
00 00 00 00 00000000
00 00 00 00 00000000
00 00 00 00 00000000
4C 4F 43 2E 2E434F4C
54 59 31 00 00315954
00 00 00 00 00000000

If this code is placed at location bin%, then to initialise the code, call:

USR (bin% + 2, 0, 0, 0, 0)

Then, to copy date from the flash card:

rc% = USR (bin%, ADDR (loc&), drive%, length%, ADDR (buffer))

copies length% bytes into the buffer, starting from address loc& on card drive% (0 is A:, 1 is B:, 2 is C:, etc.). A returned value of 0 indicates success.