Low Level Filesystem Access: Difference between revisions

From Bitchin100 DocGarden
Jump to navigationJump to search
 
(12 intermediate revisions by 2 users not shown)
Line 45: Line 45:
| 1 for invisible file
| 1 for invisible file
|-
|-
| 2-1
| 2
| Reserved
| Reserved
|-
| 1
| For DO files, true indicates "opened"
|-
|-
| 0
| 0
Line 54: Line 57:
Notice that no entry exists for filesize. To determine filesize, either of two techniques may be used. By comparing the various start addresses, one can determine the next file's starting address. The two start addresses may simply be subtracted.
Notice that no entry exists for filesize. To determine filesize, either of two techniques may be used. By comparing the various start addresses, one can determine the next file's starting address. The two start addresses may simply be subtracted.


However, the filenames in the directory are not, in the simplest sense, in order by start address, so one must search the entire directory to find the next file up. The ending address of the top file is stored at FBB2+. This is not strictly true: for each given file type (BA, DO, CO) valid directory entries are always in exactly the same order as the actual files in memory. It is only when they are considered as a mixture of different types that order differs.
However, the filenames in the directory are not in order by start address, so one must search the entire directory to find the next file up. The ending address of the top file is stored at FBB2+.


Another way to determine file size is by examining the files themselves, since the file itself always contains enough information to determine its size. With BA and DO files, you must scan the file, beginning at the start address, to locate the end-of-file marker. For DO files, the EOF characters is $1A (26 decimal). For BA files, it is a three character sequence, 00H,00H,00H.
Another way to determine file size is by examining the files themselves, since the file itself always contains enough information to determine its size. With BA and DO files, you must scan the file, beginning at the start address, to locate the end-of-file marker. For DO files, the EOF characters is $1A (26 decimal). For BA files, it is a three character sequence, 00H,00H,00H.
Line 139: Line 142:
Upon exiting the routine, the HL register points to the TOP address of the new file (the address at which new characters would be added), and DE points to the address of the directory file flag, located somewhere in the directory starting at F962.
Upon exiting the routine, the HL register points to the TOP address of the new file (the address at which new characters would be added), and DE points to the address of the directory file flag, located somewhere in the directory starting at F962.


The routine '''CHKDC''', called at 5AA9, examines the directory to determine if a specified filename is present in the directory as a valid file. Prior to the call, DE should point to the first in a series of memory addresses (RAM or ROM) containing a filename in ASCII followed by a null.
The routine '''CHKDC''', called at 5AA9, examines the directory to determine if a specified filename is present in the directory as a valid file. Prior to the call, DE should point to the first in a series of memory addresses (RAM or ROM) containing a filename in ASCII followed by a null. Note that CHKDC modifies ALTLCD.
 
Rather than CHKDC, you may prefer to call the alternative FINDFL routine at $20AF. Instead of a NUL terminated string, you must supply a space-padded string with the extension right-justified as is normal when using the FILNAM buffer. One particular benefit is that unlike CHKDC, FINDFL does not poke around in ALTLCD.


([[User:Jhoger|Jhoger]] 22:39, 4 April 2009 (PDT) note: I've found that I need to call '''LNKFIL''' before calling '''CHKDC''' if the file I want to access was recently created by SAVEM)
([[User:Jhoger|Jhoger]] 22:39, 4 April 2009 (PDT) note: I've found that I need to call '''LNKFIL''' before calling '''CHKDC''' if the file I want to access was recently created by SAVEM)
Line 155: Line 160:
The routine '''MAKHOL''', called at 6B6D, inserts a specified number of spaces in a file. Everything is moved up in memory to accommodate the spaces. These spaces may later be changed as desired. Prior to the call, BC must contain the number of spaces to be inserted, and HL must point to the address at which to insert the spaces. HL and BC are preserved, which is handy. If there was insufficient room in RAM, the routine returns with the carry flag set.
The routine '''MAKHOL''', called at 6B6D, inserts a specified number of spaces in a file. Everything is moved up in memory to accommodate the spaces. These spaces may later be changed as desired. Prior to the call, BC must contain the number of spaces to be inserted, and HL must point to the address at which to insert the spaces. HL and BC are preserved, which is handy. If there was insufficient room in RAM, the routine returns with the carry flag set.


The routine '''MASDEL''', called at 6B9F, deletes a specified number of characters from a file. Prior to a call, BC must containt the number of characters to be deleted, and HL should point to the address at which to begin deleting. HL and BC are preserved.
The routine '''MASDEL''', called at 6B9F, deletes a specified number of characters from a file. Prior to a call, BC must contain the number of characters to be deleted, and HL should point to the address at which to begin deleting. HL and BC are preserved.
 
The routine '''PRSNAM''' parses a filename pointed to by HL, length in E, and puts the result in FILNAM.
 
The routine '''SRCNAM''' searches the directory for the name stored at FILNAM. On exit, HL points to the entry and A contains the directory flag value. Z is set if file is not found.


== LNKFIL ==
== LNKFIL ==
(In progress, not reliable yet)


LNKFIL starts at $2146. It is used to correct the file descriptor table (directory) pointers after adding or deleting file data following a call to MAKHOL or MASDEL.
LNKFIL starts at $2146. It is used to correct the file descriptor table (directory) pointers after adding or deleting file data following a call to MAKHOL or MASDEL.
Line 170: Line 177:


# The file section pointers must be accurate
# The file section pointers must be accurate
# The order of files in the directory must match the order of files in RAM
# The directory entries, though out of order and never actually sorted, if sorted by start address MUST ALWAYS result in an identical ordering to the order of actual files in RAM.


LNKFIL is dependent on the file section pointers:
LNKFIL is dependent on the file section pointers:
Line 187: Line 194:
To maintain accuracy of section pointers, follow the discipline of only using MAKHOL or MASDEL to wedge open space or remove file bytes, respectively, rather than attempting to do it in some ad hoc fashion.
To maintain accuracy of section pointers, follow the discipline of only using MAKHOL or MASDEL to wedge open space or remove file bytes, respectively, rather than attempting to do it in some ad hoc fashion.


To avoid corrupting the RAM filesystem, make sure to call LNKFIL before looking up a file entry if there is any chance that the filesystem has been modified without a fixup by LNKFIL. Also, upon allocation of a new directory entry, ensure that you wedge open the correct spot relative to other files of the same type to maintain the order.
To avoid corrupting the RAM filesystem, make sure to call LNKFIL before looking up a file entry if there is any chance that the filesystem has been modified without a fixup by LNKFIL. Also, always add a file to the end of a given file section. Basically, call MAKHOL with the value of the pointer to the subsequent section.


== How RAM File Creation Works ==
== File Creation ==


(Steve Adolph)
(Steve Adolph)
Line 195: Line 202:
There are a number of pointers in high memory that are used to demarcate the
There are a number of pointers in high memory that are used to demarcate the
area used for
area used for
basic files
 
text files
* BASIC files (BA)
the three scratchpads
* Text files (DO)
machine language files
* Machine language files (CO)
* The three scratch pads (Suzuki, Hayashi, RickY)


These pointers need to be modified according to what you need to
These pointers need to be modified according to what you need to
Line 207: Line 215:
To create a file you need to
To create a file you need to


* wedge open the file space at a precise location, depending on the file type and the pointer values...placement is critical because of a fundamental assumption in the directory management
* Find an unused slot in the directory table
 
* Wedge open space in the filesystem for the new file; the hole must be opened between files or at the beginning or end of the memory region set aside for the given file type (BA, DO, CO). The order of files within a given memory region/file type must be the same as files in the directory for the given file type.


* load all the appropriate data into that memory hole, representing the actual file data
* Load all the appropriate data into that memory hole, representing the actual file data


* create a directory entry with the right stuff in the entry to connect with that file
* Complete the directory entry


* run the magic '''LNKFIL''' ($2146) routine that re-assigns all the directory links and connects them to the right files again
* Run the '''LNKFIL''' ($2146) routine that walks all files and updates the directory's start pointers


Deleting a file is kinda similar.
Deleting a file is similar.


The fundamental assumption is that the order of the files must be
The fundamental assumption is that the order of the files must be
maintained within each file type.  That way the linker can deduce
maintained within each file type.
which file directory entry is associated with a specific file.
 
IE the next .BA directory entry must be associated with the next found
file in the .BA area.  and so on.


[[Category:Model T Developer Reference]]
[[Category:Model T Developer Reference]]

Latest revision as of 15:10, 14 April 2009

RAM File System

(Significantly extended from "Published RAM File Handling Routines" in "Inside the TRS-80 Model 100" by Carl Oppedahl)

File List/Pointer Cache

User files reside in RAM starting at the lowest installed RAM address, with BA files at the bottom, followed by DO files and CO files. The directory is located in high memory from $F962 to $FA8B. The directory is terminated by a sentinel value $FF byte. Thus there are 297 bytes in the table itself; dividing by 11 yields 27 slots. The format of the filename information is given in table 18.1.

Table 18.1
Byte Description
0 Directory flag (see table 18.2)
1-2 Cached file start pointer
3-10 Eight-byte file name


Table 18.2
Bit Description
7 0 if a killed file
6 1 if a DO file
5 1 if a CO file
4 1 if located in ROM
3 1 for invisible file
2 Reserved
1 For DO files, true indicates "opened"
0 Internal use only (known to be used by LNKFIL)

Notice that no entry exists for filesize. To determine filesize, either of two techniques may be used. By comparing the various start addresses, one can determine the next file's starting address. The two start addresses may simply be subtracted.

However, the filenames in the directory are not in order by start address, so one must search the entire directory to find the next file up. The ending address of the top file is stored at FBB2+.

Another way to determine file size is by examining the files themselves, since the file itself always contains enough information to determine its size. With BA and DO files, you must scan the file, beginning at the start address, to locate the end-of-file marker. For DO files, the EOF characters is $1A (26 decimal). For BA files, it is a three character sequence, 00H,00H,00H.

For CO files, there is no end-of-file character as such, but the length of the file is determined by adding the value of the third byte to the product of 256 times the fourth byte, plus six.

Keep in mind that the cached file start pointer is not necessarily up-to-date at any given time. Some operations do not update it, even BASIC language operations like SAVEM can leave a stale file start pointer. The LNKFIL routine must be used to assure that the pointers are up-to-date.

Suzuki, Hayashi and RickY

Note the difference between the number of slots you can see on the screen, 24, and the number of directory entries, 27. That means there are 3 hidden entries.

If you are experimenting with a Model 100 (as apposed to T102), sooner or later you will stumble across the NUL-prefixed names Suzuki, Hayashi and RickY in the directory.

Hayashi ($F9A4) and RickY ($F9AF) are .DO files. Hayashi is the PASTE buffer. RickY is the current BASIC line when in EDIT mode.

Suzuki ($F999) is the location of the BASIC program, if any, that has not yet been SAVEd and therefore does not have a name. (It is the file you sometimes see listed as BASIC*.) Sometimes you select BASIC from the main menu and find that some lines are still present from the last time you were in BASIC; these lines were hiding in Suzuki.

Suzuki and Hayashi take up memory, of course, like any other files. Suzuki can be emptied by entering BASIC and typing NEW. Hayashi can be emptied by copying a zero-length selection to the PASTE buffer. RickY should only exist while the EDIT command runs.

On the T102, these names were removed. Reportedly, programmers embedding their name in the ROM was considered bad form by Tandy.

DO Files

A DO file's first character is that which would be returned if you accessed it with TEXT or with BASIC's OPEN and INPUT statements. The file ends with the $1A described above.

BA File Format

A BA file in RAM is set up as a sequence of lines, each with the following form:

2 bytes Address of the line number to follow (little endian)
2 bytes Current line number (little endian)
Numerous bytes Program line in tokenized form
1 byte Null (00H)

The file ends with two more nulls (00H), making the last three characters nulls.

CO File Format

The format of a CO file is as follows:

2 bytes Address to load file to (little endian)
2 bytes Number of bytes to load (little endian, six fewer than the size of the RAM file, because of these six address bytes)
2 bytes Transfer (start) address
many bytes Contents of file

Accessing Files

BASIC's PEEK statement can be used to examine the file contents without the danger of altering the file. The use of POKEs with files, however, is discouraged unless you know precisely what you are doing. If you must POKE, keep the following in mind.

  • If you find that CHKDC or similar call does not find the file where it actually is, a call to LNKFIL may be required to update the cached start pointers.
  • POKE only within the files, not elsewhere in RAM. In particular, do not POKE to addresses at or above 62960 (F5F0).
  • If you create an end-of-file (EOF) marker within a DO file, you must delete any characters from there up to the beginning of the next file. Use MASDEL, described below. To grow a file, use MAKHOL.
  • If, within a BA file, you tamper with any of the file format addresses described above in memory, such as the BASIC address of the following line number, the program will no longer function properly.

Published ROM Calls for Manipulating RAM Files

Most of the following routines can be used only to manipulate DO files in RAM.

The routine MAKTXT, called at 220F, creates a DO file in the RAM directory with the name specified in the buffer at FC93 through FC98. If the file already exists, the routine returns with the carry flag set.

Upon exiting the routine, the HL register points to the TOP address of the new file (the address at which new characters would be added), and DE points to the address of the directory file flag, located somewhere in the directory starting at F962.

The routine CHKDC, called at 5AA9, examines the directory to determine if a specified filename is present in the directory as a valid file. Prior to the call, DE should point to the first in a series of memory addresses (RAM or ROM) containing a filename in ASCII followed by a null. Note that CHKDC modifies ALTLCD.

Rather than CHKDC, you may prefer to call the alternative FINDFL routine at $20AF. Instead of a NUL terminated string, you must supply a space-padded string with the extension right-justified as is normal when using the FILNAM buffer. One particular benefit is that unlike CHKDC, FINDFL does not poke around in ALTLCD.

(Jhoger 22:39, 4 April 2009 (PDT) note: I've found that I need to call LNKFIL before calling CHKDC if the file I want to access was recently created by SAVEM)

Upon return, the Z flag is set if no such file was found. If the file was found, HL points to the directory entry.

A complementary routine, GTXTTB, called at 5AE3, finds the TOP address of the file assuming its location in the directory is known. If you provide the address of the directory entry in HL, it returns the TOP address of the file.

The routine KILASC, called at 1FBE, kills a DO file. Prior to the call, DE must be set to the starting address of the file, and HL must be set to the address of the directory entry. Everything above it in user memory (CO files and other DO files) is moved down to fill in the space.

The routine INSCHR, called at 6B61, inserts one character in a DO file, Prior to the call, HL points to the address at which to insert the character, and A contains the character to be inserted. Everything above in user area (all CO files and some DO files) is moved up one position.

If there is no more room in RAM, the routine returns with the carry flag set.

The routine MAKHOL, called at 6B6D, inserts a specified number of spaces in a file. Everything is moved up in memory to accommodate the spaces. These spaces may later be changed as desired. Prior to the call, BC must contain the number of spaces to be inserted, and HL must point to the address at which to insert the spaces. HL and BC are preserved, which is handy. If there was insufficient room in RAM, the routine returns with the carry flag set.

The routine MASDEL, called at 6B9F, deletes a specified number of characters from a file. Prior to a call, BC must contain the number of characters to be deleted, and HL should point to the address at which to begin deleting. HL and BC are preserved.

The routine PRSNAM parses a filename pointed to by HL, length in E, and puts the result in FILNAM.

The routine SRCNAM searches the directory for the name stored at FILNAM. On exit, HL points to the entry and A contains the directory flag value. Z is set if file is not found.

LNKFIL

LNKFIL starts at $2146. It is used to correct the file descriptor table (directory) pointers after adding or deleting file data following a call to MAKHOL or MASDEL.

Each file in RAM has an entry in the directory. Along with the name and a flags byte, each entry has a pointer to where the file starts in RAM. Various file operations add, delete, grow, and shrink files in RAM. Many operations, however, do not update these pointers, and leave them to be fixed up later, by calling LNKFIL. It is not clear at what times the system will call LNKFIL.

When LNKFIL is called, it walks all files in RAM and updates the pointers in the file descriptor table to match.

For LNKFIL to operate properly, aside from the filesystem not being corrupted, two conditions must be met:

  1. The file section pointers must be accurate
  2. The directory entries, though out of order and never actually sorted, if sorted by start address MUST ALWAYS result in an identical ordering to the order of actual files in RAM.

LNKFIL is dependent on the file section pointers:

File Section pointers:

FBAEH -  Pointer to the start of the DO files (2)
FBB0H -  Pointer to the start of CO files (2)

Subsequent pointers:

FBB2H -  Pointer to the start of variable table (2)
FBB4H -  Pointer to the start of array table (2)
FBB6H -  Pointer to the start of the systems unused memory (2)

To maintain accuracy of section pointers, follow the discipline of only using MAKHOL or MASDEL to wedge open space or remove file bytes, respectively, rather than attempting to do it in some ad hoc fashion.

To avoid corrupting the RAM filesystem, make sure to call LNKFIL before looking up a file entry if there is any chance that the filesystem has been modified without a fixup by LNKFIL. Also, always add a file to the end of a given file section. Basically, call MAKHOL with the value of the pointer to the subsequent section.

File Creation

(Steve Adolph)

There are a number of pointers in high memory that are used to demarcate the area used for

  • BASIC files (BA)
  • Text files (DO)
  • Machine language files (CO)
  • The three scratch pads (Suzuki, Hayashi, RickY)

These pointers need to be modified according to what you need to insert or delete. For example, if you add a .CO file, then you don't need to modify the pointers that deal with the lower file space. (Jhoger 20:27, 6 April 2009 (PDT): I think you would still need to call MAKHOL to avoid smacking up BASIC variable region) But, adding a .BA moves all the pointers.

To create a file you need to

  • Find an unused slot in the directory table
  • Wedge open space in the filesystem for the new file; the hole must be opened between files or at the beginning or end of the memory region set aside for the given file type (BA, DO, CO). The order of files within a given memory region/file type must be the same as files in the directory for the given file type.
  • Load all the appropriate data into that memory hole, representing the actual file data
  • Complete the directory entry
  • Run the LNKFIL ($2146) routine that walks all files and updates the directory's start pointers

Deleting a file is similar.

The fundamental assumption is that the order of the files must be maintained within each file type.