IDEAL turns your hard disk into a huge collection of "virtual floppies" that can either be accessed by name, or by "inserting" them into 8 virtual drives. It is fully compatible with the TI floppy disk format, and therefore has the same limitations: only 1440 sectors and 127 files per disk, at most 76 clusters per file, 256 byte per sector, etc.
You'll find some improvements on the TI format though. First of all, I integrated most of the new features introduced in the Horizon Ramdisk operating system (a good part of my code is shamelessly lifted from ROS 8.14 and from the TI-controller card ROMs, but why re-invent the wheel?). Thus, you'll find extra opcodes to delete a record, to load an assembly, Basic or cartridge file, an autostart feature, and the possibility to place a file data buffer in CPU memory instead of VDP memory.
IDEAL lets you create directories and subdirectories. In fact, a directory is nothing more than an empty file that points to another virtual floppy. This lets you organise your virtual floppies in a hierarchical manner, while remaining compatible with a floppy disk controller (although of course, directories won't be more than empty files if you copy them to a real floppy).
IDEAL provides you with the possibility to encrypt a file, or a whole virtual floppy, using the Blowfish algorithm. You also have a direct access to the encryption engine, so you can encrypt your own data.
Optionally, IDEAL will time-stamp each file and/or disk with a creation date and a date of last modification. You can also access the clock directly to set the time or an alarm, and to retrieve the current date and time, either as numbers or as pre-formatted text strings. IDEAL version 1.1 through 1.3 support the RTC65271 and the bq4847 clocks. It should also work for the bq4842 and bq4852 but I haven't tested these. (Version 1.0 was meant for my prototype card, it only supports the RTC65271 and the bytes in the IDE data bus are inverted with respect to version 1.1).
The standard catalog function works just as with the TI floppy controller, but an extended catalog is also provided that returns extra information on the files (such as the time stamps) and lets you perform some file management functions. It also lets you edit a floppy sector-wise from Basic.
Finally, IDEAL has the capability of configuring itself, so you can tailor it to your needs and preferences.
Editing the floppy collection
Accessing the clock
Direct hard-drive access
Modifications to the TI format
Installing IDEAL involves the following steps
File Type Usage IDEAL/A ... IDEAL/M Program IDEAL operating system to be loaded into the SRAM IDEAL/Z Program Bootstrap (resides in the RTC65271 clock RAM) IDELOAD Program System loader (loads IDEAL + boostrap + config) IDE-LD2/O DF80 Patch for the above, for non-standard cards IDE-LD2/S DV80 Source for the patch IDEAL/GK Program German 128K Gram-Karte access routine IDEAL/PG Program P-Gram+ card access routine IDE_GC/S DV80 Demo: sources for IDEAL/GK and IDEAL/PG NEWCFG TI-Basic Configures IDEAL (Do CALL FILES(1) before OLD) SETIME TI-Basic Sets the time and date NOLOAD Program Placeholder file for Mini-IDEAL IDEDIAG Program Hardware diagnostic program (see manual for details) CONFIG TI-Basic Demo: Reads the system configuration FLOP TI-Basic Demo: Embryonic virtual-floppy manager TRASH TI-Basic Demo: Recovers deleted floppies CAT TI-Basic Demo: Extended disk catalog BLOW TI-Basic Demo: Direct access to the encryption engine CLOCK TI-Basic Demo: Access the real-time-clock DSR INTS TI-Basic Demo: Setting clock interrupts SECTORS TI-Basic Demo: Direct access to hard-drive sectors RESTORECFG TI-Basic Demo: Restoring a lost configuration VAR2FIX TI-Basic To copy a DV80 file into a DF80 (for IDE-LD2/O)NB Don't try to run the IDEAL/x files with an EA5 loader: they must be loaded into the card SRAM and only IDELOAD knows how to do this properly.
Installing the IDE card
First pick up a CRU address for the card. There should not be any other card with this CRU in your system. A convenient CRU to use is >1000, so that the IDE card will be scanned before the floppy disk controller (whose CRU is >1100). If you don't know what CRU addresses are available in your system, you can load my Module Explorer program, press Ctrl-7, then Fctn-3 to enter the Header Analyser. The arrow keys let you travel among the installed cards and their subprograms, DSRs, etc.
Note: if you're planning to use the "autostart" feature to launch a program at power-up time, you should pick a CRU address higher than that of any card that has a power-up routine in its DSRs. Otherwise, because IDEAL will abort the power up sequence when launching the desired program, the other cards may not be initialized properly. Exemple of such cards are the floppy disk controller card (CRU >1100), the RS232 card (CRU >1300), the German Gram-Karte (selectable CRU), and my USB-SM card (selectable CRU).
Once you decided on the CRU address, set its second digit on the rotary that's at the bottom left of the card. For instance, if you picked CRU >1200, you would set the encoder on '2'.
Below the encoder, you'll find a 4-switches DIP switch. It is meant for use with the RTC65271 clock chip:
Connect your hard drive(s) to the card via a standard IDE cable. Then carefully insert the card in the PE-box. If your drive doesn't have its own power supply, you can connect it to the floppy disk power supply. However, I noticed that there is not enough power to support both my floppy drive and my hard drive: when the floppy kicks in, the hard drive stops spinning! Thus, it may be better to remove the floppy drive altogether. Another possibility is to modify the PE-box power supply, so that it provides more current. But this is another endeavour...
Now, power-up the system: first the PE-box (and hard-drive), then the console. If your drive takes a few seconds to spin up, it's a good practice to wait till it's ready before you turn the console on. Then flip the main switch on the card, so that it becomes active. With a TI-99/4A, pull it all the way back, with a Geneve use the middle position.
N.B. If you have a Gram device, you may want to first replace the file IDEAL/G with the one corresponding to your Gram card: just rename IDEAL/GK for the german 128K Gram Karte, or IDEAL/PG for the PGram card. The original IDEAL/G file contains both routines, but calls the one for the Gram Karte. If you have a different Gram device, you will need to write a custom routine if you want IDEAL to handle it (which is optional anyhow). See below for a description of the required routine.
Now load the program IDELOAD using Editor/Assembler option 5, or with a similar loader (such as Funnelweb). The program first prompts you for the CRU of your IDE card. Enter the value that you set with the endoder on the card, i.e. the second digit of the CRU address. Provided the card is found and the hard-drive answers properly (you must have a drive plugged in at that time), IDELOAD will ask whether you want to load IDEAL, the bootstrap and/or the configuration. Finally, you must enter the number of the drive where the files are to be found (normally, this will be DSK1). At any time, you can press F9 (back) to go back to the previous step. Loading begins after you entered the drive number.
If you elected to load the configuration, or if you loaded IDEAL, IDELOAD will check the RTC65271 clock memory (if you have this clock chip, that is) for valid configuration data, and ask you whether you want to keep it. If you decline, or if none was found, the program checks a reserved area on the hard drive, where a backup of the configuration is kept. If a valid configuration is found there, you again have the choice to use it or not. If you don't, or if none was found, the programs asks you if you want to load the configuration from the file IDEAL/M. The latter option is not offered if you have just loaded IDEAL, since in this case the configuration has already been loaded from file anyhow.
The bootstrap is the file IDEAL/Z. It's a small program that resides into the clock memory and loads IDEAL from your hard drive when you power-up your system. Of course, this implies that you have copied (or intend to copy) IDEAL on your hard-drive. Loading the boostrap into the clock is only meaninfull with the RTC65271 clock.
Once loading is completed you have the option to leave the bootstrap in control. This means that the next time you hit <quit>, the bootstrap will attempt to load IDEAL from the hard drive. Obviously, you should only select this option if you have already copied IDEAL on the hard drive (i.e. if you are reinstalling the system). Answer by Y or N to exit, or press <back> to return to the drive number prompt. If you are using the Editor/Assembler cartridge, you may get an "Error 00" message after exiting the program. Just ignore it: I forgot to clear the GPL status byte before exiting. You won't see this message with Funnelweb.
If you made changes to my schematics and are using different CRU bits, you will need to patch IDELOAD so that it modifies the system accordingly. See below for details.
Alternatively, you can run the TI-Basic program SETIME that will walk you through the process.
Create a new virtual floppy either with a disk manager "format" command or by using the IDE.FLOPPIES pseudo-file:
OPEN #1:"IDE.FLOPPIES", INTERNAL, FIXED 128, APPEND PRINT #1:"IDEAL",360 CLOSE #1 CALL CD.5..IDEALN.B. The CALL loads the virtual floppy into a virtual drive called DSK5 (by default IDEAL comes with drives DSK4, 5, 6, 7, 8, 9, A and B installed).
Now use a disk manager to copy the IDEAL disk to DSK5.
IDEAL will be automatically reloaded in the following circumstances:
Alternatively, you can update the configuration yourself via the file IDE.CONFIG, which is what NEWCFG is doing anyway. Refer to the corresponding section below.
In any case, the parameters that you should set are:
Now you are ready to roll... A few more technical details follow, but on first reading you can just skip ahead to the "Overview" section.
1) If you have a battery-backed SRAM, the configuration info should be safe at any time, even when the PE-box is turned off. Unless of course the battery runs out...
2) If you're using the RTC765271 clock chip, the configuration will automatically be saved into it after any change. When you reload IDEAL (either with IDELOAD, or through the boostrap), the configuration is copied from the clock memory into the SRAM. This level of backup is not available with the other clock chips (but those battery-back the SRAM instead).
3) An additional backup is maintained on the hard-drive itself, in a reserved area that is not part of your virtual floppy collection (namely, hard-drive sector 0). This backup is updated each time you CLOSE the file IDE.CONFIG after a modification. If you reset the computer before closing the file, any change you made will be saved into the clock RAM but not on disk!
Note: With the RTC65271, this backup is only used if a valid configuration cannot be found in the clock memory when IDEAL is loaded. To invalidate it and use the disk backup instead, use the CLOCK DSR to alter page 55 in the clock memory:
100 OPEN #1:"CLOCK", INTERNAL, FIXED 128, RELATIVE 110 PRINT #1, REC(100+55): "0123456789abcdef0123456789abcdef" 120 CLOSE #1Then force a system reload by holding down Ctrl-Enter while you reset the TI-99/4A.
4) If you feel that you need an additional level of backup, you can save the configuration present in the hard drive onto a floppy. This implies that sector-wise access of the hard drive is enabled (you can always turn it off later).
100 OPEN #1: "IDE.SECTORS", INTERNAL, FIXED 129, RELATIVE 110 PRINT #1, REC 0: 0,0 120 INPUT #1: PART1$ 130 INPUT #1: PART2$ 140 INPUT #1: PART3$ 150 INPUT #1: PART4$ 160 CLOSE #1 170 OPEN #2:"DSK1.BACKUP",INTERNAL, FIXED 129, OUTPUT 180 PRINT #2: PART1$ 190 PRINT #2: PART2$ 200 PRINT #2: PART3$ 210 PRINT #2: PART4$ 220 CLOSE #2To restore a lost configuration from such a backup just reverse the process, then invalidate the clock memory and force a reload as described above.
5) If everything fails and you have lost your configuration without any up-to-date backup, you will need to re-enter your favorite options using the IDE.CONFIG pseudo-file. By accessing record 22 of the same file, you can also trigger a scanning routine that will inspect your hard drive for virtual floppies and (hopefully) return your collection root and trash lists endpoints. These values can then be passed to record 5 to restore your configuration.
Here are the SRAM pages used by IDEAL:
Page 0 Page 1 Page 2 >4000+-----------------+ +-----------------+ +-----------------+ | Registers | | xxxxxxxxxxxxxxx | | xxxxxxxxxxxxxxx | >4000+-----------------+ +-----------------+ +-----------------+ | Entry points | | CLOCK DSR | | Char patterns | | Config data | | RAMBO manager | | for LD | | Common | | ISR | | | | subroutines | | | | | >5000+-----------------+ +-----------------+ +-----------------+ | Sub >10 >14 >15 | | Opcodes 0 to 4 | | Autostart | | Dir-files subs | | 8 and 9 | | LD DSR | | | | | | Opcodes >A to >C| | | | | | Sub >11 >12 >13 | | Buffers (>5B00) | | | | Custom subs | +-----------------+ +-----------------+ +-----------------+
Page 3 Page 4 Page 5 Page 6 >4000+-----------------+ +-----------------+ +-----------------+ +-----------------+ |xxxxxxxxxxxxxxx | | xxxxxxxxxxxxxxx | | xxxxxxxxxxxxxxx | | xxxxxxxxxxxxxxx | >4100+-----------------+ +-----------------+ +-----------------+ +-----------------+ | not used | | Number Pi | | Encryption | | not used | | | | for Blowfish | | key | | | >5000+-----------------+ +-----------------+ +-----------------+ +-----------------+ | Floppy collec | | Configuration | | Blowfish | | Trash management| | management | | management | | encryption | | IDE.TRASHx | | IDE.FLOPPIES | | Catalog | | IDE.BLOWxxx | | IDE.CONFIG rec22| | | | Extended cat | | | | | | Buffers | | Buffers | | | | | +-----------------+ +-----------------+ +-----------------+ +-----------------+
Next page Next page Next page >4000+-----------------+ +-----------------+ +-----------------+ | xxxxxxxxxxxxxxx | | xxxxxxxxxxxxxxx | | xxxxxxxxxxxxxxx | >4000+-----------------+ +-----------------+ +-----------------+ | not used | | not used | | not used | | | | | | | >5000+-----------------+ +-----------------+ +-----------------+ (more pages) | Buffering subs | | Buffering subs | | Buffering subs | (if needed ) >5400+ Opened files | | Opened files | | Opened files | | buffers | | buffers | | buffers | | (5 files) | | (5 files) | | (5 files) | | | | | | | +-----------------+ +-----------------+ +-----------------+Notes: Version 1.3 has nothing in page 1 below >5000. Instead, the clock routines are in the last SRAM page. The low part of the page is used to emulate XRAM pages, the high part contains the clock routines and the clock registers (which map at >5FF0-5FFF).
As you can see, Blowfish encryption is the most memory-hungry feature. So if you have no use for it, you can save a page and a half.
If you decide that your floppy collection is complete for now, you can remove the collection manager and the trash manager. This means that you will not be able to rename a floppy since it would require rearranging the collection.
If you are satisfied with the current configuration and have no need for the catalog function, you can also remove page 4.
You can reclaim the lower part of page 1 if you don't use RAMBO mode, nor call the CLOCK DSR (time stamping still works though). Similarly, if you don't use LD nor the autostart feature (or only to launch programs that set up their own character patterns) you can reclaim the lower part of page 2.
Finally, you can decrease the number of opened files, so as to use less pages to buffer them. Opened files buffers are always in the pages immediately following the system. There is room for 5 files per page.
Once you have made up your mind as to what you want to keep, you can remove some of the IDEAL/x files. Each time you remove such a file, replace it with a copy of the file called NOLOAD renamed as IDEAL/x. Here is the list of system files:
IDEAL/A Page 0 high (required) IDEAL/B Page 1 low IDEAL/C Page 1 high (required) IDEAL/D Page 2 low IDEAL/E Page 2 high (required) IDEAL/F Page 3 high IDEAL/G Gram Card-specific routines (in page 2) IDEAL/H Page 4 low IDEAL/I Page 4 high IDEAL/J Page 5 high (page 5 low is filled on the fly) IDEAL/K Page 6 high IDEAL/L Buffer pages (required) IDEAL/M Page 0 low (required, must be last file)To avoid crashes, you should edit your system configuration and indicate which features have been disabled (record 20 in IDE.CONFIG). Obviously, if you disable the configuration feature, you should do this before removing the file!
If you ever need the full-fledge IDEAL, you can always load it from a floppy with IDELOAD.
To this end, edit IDE-LD2/O with a text editor. It's a non-compressed DF80 file, with all the parameters needed by IDELOAD. Modify them according to your hardware. The file is commented for your convenience.
Remember that CRU bits are off at power-up time, so any function that you want to be the default should be active-low. For active-low bits, enter the string:
9yyyyB1E0xB1D0xFWhere x is the bit number, >1D0x is the code for SBO and >1E0x is the opcode for SBZ. (9yyyy is the loading address, leave it unchanged).
For active-high bits, just invert the two commands:
9yyyyB1D0xB1E0xFIf you did not implement a bit, replace both commands with NOPs (opcode >1000):
9yyyyB1000B1000FOnce done, save the file back in DF80 format. If your text editor won't let you do this (e.g. Funnelweb's), save it as DF80 and use the TI-Basic program VAR2FIX to convert it to DF80.
Alternatively, you can edit the source file IDE-LD2/S and assemble it.
In any case, once you have set up the proper bit values, the procedure is the following:
Note the similarity with the DSK.DISKNAME.FILENAME syntax used by the floppy disk controller. In fact, the latter will also work with the IDE card, but only if its CRU address is set as >1000. This is because the floppy controller, which is the second card scanned (its CRU is >1100), returns an error if it does not find DISKNAME in one of its drives. Of course, if you don't have a floppy controller installed, there won't be any problem with using DSK.DISKNAME.FILENAME, no matter what the CRU of the IDE card is.
Alternatively, a virtual floppy can be "inserted" into a virtual drive. There are eight such drives, with names in the format DSKn, where n is a number from 1 to 9, or a letter from A to Z. Once a virtual floppy is inserted, it can be accessed as if it were in a real drive:
OPEN #1:"DSK9.FILENAME",INPUTA difference with the standard TI floppy controller is that, if the file already exists, you don't need to specify its type when opening it: if the record size is 0 (which it will be in Basic if you do not specify a record length), the size and file type are supplied from disk. Note however that Basic requires a comma after the filename in OPEN, so you'll need to supply at least one parameter (like INPUT in the example above).
Another difference is that you can now open fixed files in append mode.
Inserting a floppy in a virtual drive is the only way you can make it available to the standard sector-access subprograms (subprograms >10 to >15). As most disk managers exclusively use these subprograms (e.g. DISKU), this feature will come handy with them.
OPEN #1:"DSK9.",INTERNAL, FIXED 38, INPUT
or, using the disk name:
OPEN #1: "DSK@.DISKNAME.", INTERNAL, FIXED 38, INPUT
In addition, IDEAL offers a more sophisticated catalog access, see below.
1) With the disk name:
CALL CD.9..DISKNAME TI-Basic or Assembly CALL CD".9..DISKNAME" Extended-Basic DELETE "CD.9..DISKNAME" AnyThe double-dot syntax tells the system that you are not trying to access a file called DISKNAME on the floppy currently in DSK9, but rather to insert the floppy called DISKNAME into the drive DSK9.
Note that CD can be considered both as a subprogram, called with CALL from Basic or DSRLNK with offset >000A from assembly, and as a device, accessed with any file operation (such as DELETE) in Basic or DSRLNK with offest >0008 in assembly.
The advantage of the later is that you can use string variables: DELETE A$ is legal in Basic, whereas CALL A$ is not. In addition, Extended Basic truncates the diskname at the first non-digit character (the dot and the < sign are ok, though), so to make it work you will need to enclose the path in double quotes... which will not work in Basic! The device solution always works.
Note that any file operation will do, DELETE is just convenient because it does not take any file number in Basic. And don't worry, nothing will be deleted: no other action than inserting the floppy will be taken whatever file operation you use.
2) By following a directory path:
If the virtual floppy currently in the virtual drive contains a directory pointer file, you can follow it to access the corresponding disk. This will automatically insert the floppy the directory file is pointing at, in place of the current floppy. For instance:
CALL CD.9.MYDIR or DELETE "CD.9.MYDIR" or OPEN #1:"DSK9.MYDIR",INTERNAL,FIXED 1,INPUTwill insert into DSK9 the floppy pointed at by the file MYDIR, currently in DSK9.
3) Finally, how to insert a floppy into a virtual drive when working within a disk manager program, like DISKU?
The problem here is that DISKU does almost everything with the sector-access subprogram >10, which does not take any filename. Exceptions are Viewing and Deleting files. So here is the technique: 1) Create a file with the name of the disk you want to insert, preceded with a dot (e.g. ".MYDISK"). 2) Delete it. It won't be deleted (to do this you must rename it first), but the drive will now contain the required disk.
Alternatively, you can just follow a directory path by attempting to View the corresponding directory file. DISKU will OPEN it, which automatically inserts the target disk into the drive. You'll get an error message because DISKU tries to READ, then CLOSE the file, which cannot be found any more since the disk just changed. Acknowledge the error and press <redo> to update the listing: you should see the content of the new disk.
CALL CD.Z.. or CALL CD.Z. or even CALL CD.ZThis will not delete anything: the virtual floppy remains in your collection. It just means that it cannot be accessed via DSKZ any longer.
In Extended Basic, these will only work if the drive number is a digit. To make it work with a letter, you must type:
CALL CD".Z.." or CALL CD".Z." or CALL CD".Z"A file operation can be used in the same manner:
DELETE "CD.9.." or DELETE "CD.9." or DELETE "CD.9"Caution: if you have opened files in this drive, you must close them BEFORE removing the floppy, otherwise the most recent changes may be lost (of course, this may be precisely what you are trying to do).
1) Use a disk manager to format a virtual drive: an empty virtual floppy with the required size and name will be added to your collection. If there was a floppy in this drive before, it is simply returned to the collection; it won't be overwritten by the formatting operation.
2) Edit your collection by opening the file IDE.FLOPPIES in append mode, and create a new record containing the new disk name and its size in sectors:
100 OPEN #1:"IDE.FLOPPIES", INTERNAL, VARIABLE 128, APPEND
110 PRINT #1:"DISKNAME",360
120 CLOSE #1
3) Use the Basic program FLOP, which calls IDE.FLOPPIES for you. Select "Add a floppy" from the menu and supply a unique name and a size (360, 720 or 1440 sectors). Note that the "List floppies" option will start after the newly created floppy, in alphabetical order. To start from the beginning, press <enter> to stop the listing and ask for the listing again.
100 OPEN #1:"IDE.FLOPPIES", INTERNAL, VARIABLE 128, APPEND
120 INPUT #1, REC I:A$
130 IF A$="DISKNAME" THEN 200
150 GOTO 120
200 PRINT #1, REC I:"",-1
210 CLOSE #1
NB. There is a faster way to locate the proper record, see below. Also, there is a way to recover floppies deleted by mistake.
To a regular disk manager, subdirectories appear as empty Int/Fix 1 or Int/Var 1 files. Only IDEAL recognizes them as directory pointers and uses them accordingly.
OPEN #1: "DSK7.DIRECTORY.FILENAME"
Where FILENAME is a file located in the virtual floppy pointed at by the pointer file named DIRECTORY. To make things clearer, I'd suggest that you always give your pointer files the same name as the floppy they are pointing at. In fact IDEAL can do this automatically for Int/Fix 1 directory files: whenever you rename a floppy, all the files pointing to it are also renamed (unless a file with this name already exists, in which case the pointer file becomes Int/Var 1). When you remove the floppy from your collection, all pointer files leading to it are deleted or, if protected, marked as invalid (they become Int/Fix 2 or Int/Var 2).
If the target floppy itself contains pointer files, you can specify a whole directory path:
When you create a pointer file pointing to a floppy, this floppy remember the current directory as its "parent" (if you create more than one pointer to a given floppy, you can choose which one will be the parent). You can walk back to the parent directory by using "<" as a subdirectory name (which means that "<" is not a valid diskname in your collection):
This looks for the file "filename" in the parent of the disk currently in drive DSKA, i.e. a disk that contains a pointer file pointing at the current disk.
And of course, you can combine all these in fairly cryptic pathes like this one:
Let's see; this will delete the file FILENAME, in the virtual floppy pointed at by SUBDIR, which is a pointer file located on a floppy pointed at by DIRECTORY, which itself is located on the grand-parent of the floppy named DISKNAME. I'd be quite careful before I start using such a complicated path though...
CALL CD.7.DIRECTORYThis only works in Basic and Assembly. You need quote marks in Extended Basic:
CALL CD".7.DIRECTORY"Alternatively, you could use DELETE in the same way, in either language:
DELETE "CD.7.DIRECTORY"Either will insert the floppy pointed at by DIRECTORY into DSK7(and nothing will be deleted). The file DIRECTORY must be present in the virtual floppy currently inserted in DSK7.
Alternatively, you have the option of specifying the name of the floppy to be inserted:
CALL CD.8..DISKNAME or DELETE "CD.8..DISKNAME"Note the double-dot syntax, it indicates that DISKNAME is a virtual floppy, not a pointer file.
Finally, you can make combinations:
CALL CD.B..DISKNAME.<.DIRECTORY.SUBDIRIn the above example, < indicates the parent directory of DISKNAME, i.e. a virtual floppy that contains a pointer file pointing at DISKNAME. On this parent disk should be another file called DIRECTORY pointing at another disk. On that other disk should be a file called SUBDIR pointing at yet another disk, which is the one that will ultimately be inserted. You don't have to make it so complicated though...
DELETE "DSKG.DIRFILE"Don't worry, this will not delete the floppy pointed at, only the file that points at it.
Never attempt to delete pointer files "manually" with sector edition: only the DELETE opcode knows how to maintain proper linking between all directory files that point at the same disk. Beware of disk managers that may try to do it in this waym rather than calling opcode >07.
OPEN #1:"DSK5.FILENAME..DISKNAME", INTERNAL, FIXED 1, OUTPUTNote the double-dot syntax: it tells IDEAL that you are not really trying to create a regular IF1 file, but rather a pointer file that points to the target floppy named DISKNAME. If you chose to make it a Fixed file, IDEAL will automatically substitute DISKNAME for the filename (which may cause an error if a file with this name already exists).
It is not allowed to overwrite an existing directory, even to point it at the very same disk. If the file you are creating already exists, you will get a write protection error (code 1), even if the file was not protected. To modify a pointer file, you must first delete it, then create it anew.
Opening the pointer file as OUTPUT will cause the disk it resides on to become the parent directory of the target disk. If you open the file as UPDATE (the default), and the target disk already has a parent, it will keep it. Note that you can set an option while configuring IDEAL that forbids you to change the parent directory. When this flag is set, a given disk can only have one Int/Fix 1 directory file pointing at it: its parent. This forces you to arrange your disks in a tree-wise manner, as on a PC, although no provision is made to avoid circular references. You can define extra Int/Var pointer files pointing at this disk, but only if automatic update has been disabled for Int/Var files (see below).
Finally, using SAVE instead of OPEN will also work to create a pointer file, but only OPEN lets you specify file options: if you use SAVE the default type is always Int/Fix 1, and the parent directory will not be changed if it already exists.
If you remove the target floppy from your floppy collection, all pointer files pointing at it will be deleted. If a pointer file is protected and cannot be deleted, it is changed into a Int/Fix 2 file and unprotected. This feature is mandatory for Int/Fix pointer files and optional for Int/Var files: these may be automatically deleted or not, depending on an option flag that you set when configuring IDEAL.
CAUTION: Dynamic update relies on the fact that a given pointer file will always be at the same location on your hard drive. Therefore, do not copy a pointer file from a disk to another: it could not be properly updated. Instead, create another pointer on the second disk, using OPEN or SAVE as described above. For the same reason, do not use a disk manager that rearranges files on disk when making your safety backup: use a sector-copy program instead. Always use DELETE to delete pointer files (rather than poking sectors 0 and 1) and never, ever doctor the information you will find at bytes >20-2D in the FDR of a pointer file.
This becomes even more of a problem when a pointer file is located on an encrypted floppy and you did not turn decryption on. This pointer file won't be updated but, which is worse, it cannot even be read and prevents IDEAL from walking the pointer chain any further. One way to avoid this problem is to always turn encryption on before renaming/deleting disks and/or pointer files. Another is not to place on an encrypted disk any pointer file pointing to a non-encrypted disk .
Any attempt to access encrypted files or floppies without enabling Blowfish deciphering results in a file error. Using an incorrect password will return gibberish and may even crash your program. Furthermore, if you write something with an incorrect password, you'll never be able to read it again! So my advise is: just after you enter your password, make an attempt to read something that you know for sure was encoded with this password. If you can't read it, you made a typo!
To enter your password, type:
CALL IDE.BLOWON.PASSWORD in Basic, or Assembly CALL IDE".BLOWON.PASSWORD" in Extended Basic DELETE "IDE.BLOWON.PASSWORD" in any languageAny file operation will do, but DELETE is quite convenient because it does not affect the file buffers in Basic. A CALL can also be used, but the advantage of a file operation is that you can pass a string variable: DELETE A$. Besides, the CALL syntax is different in Extended Basic.
PASSWORD should be a string of upto 56 characters.
The Blowfish routine will then create the encryption key from the number Pi and your password, which will take about 3 seconds. From this point on, Blowfish encryption is active. Any file or directory that was encrypted will be automatically decrypted. Any new file (or virtual floppy) that you create will be encrypted with the current password.
If at any time you want to change passwords, just repeate the above operation. Caution: make sure than any opened file has been closed before you change password or erase your key. Otherwise, any data still in memory cannot be saved back on disk.
Note that, for proper security, your password should never be spelled out in a Basic program as in the examples above (these assume interactive keyboard entry). If you want to enable Blowfish encryption from a program, use something like:
100 PRINT "ENTER YOUR PASSWORD" 110 INPUT PW$ 120 DELETE "IDE.BLOWON."&PW$ 130 PW$=SEG$("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",1,LEN(PW$))Line 130 serves to overwrite your password in the Basic string space, so that a collegue cannot retrieve your password by peaking the VDP memory while you went for a cup of coffee. It is not necessary if you reboot your computer once you are done.
DELETE "IDE.BLOWOFF" or CALL IDE.BLOWOFFAlternatively, you can turn encryption off, but leave decryption on (i.e. newly created files and floppies won't be encrypted, but previously encrypted files will be accessed in an encrypted fashion):
DELETE "IDE.BLOWOUT" or CALL IDE.BLOWOUTYou can turn full encryption back on with:
DELETE "IDE.BLOWON" or CALL IDE.BLOWONAgain, make sure all opened files are closed before you turn encryption off.
Note that the password can also be passed with BLOWOUT and BLOWOFF, in the same way it is with BLOWON. However, when passing a password with an Extended Basic CALL, you must use double quotes because of a bug in the way Extended Basic calculates the size of unquated strings: CALL IDE".BLOWOUT.PASSWORD"
For proper security, it is critical that you remove the key from memory once you are done with accessing encrypted data. In addition, IDEAL will also wipe out any unciphered data that may remain in the opened file buffers. This is especially critical if you are using a battery-backed SRAM that will retain buffer contents and encryption key even after power was turned off. To erase the current key, just perform any file operation on IDE.BLOWAWAY:
DELETE "IDE.BLOWAWAY" or CALL IDE.BLOWAWAY
IDE.BLOWPLAIN can be a file of any type you want, as long as the maximum record length is 248 or less. Larger records result in a 256-byte ciphered string, which is illegal in Basic (It's ok if you work from assembly, but be aware that a 256-byte string has a size byte of >00). IDE.BLOWCIPHER should be an INTERNAL, FIXED 249 file. Smaller record lengths may be ok, as long as they can accomodate all data passed to BLOWPLAIN, rounded up to the next multiple of 8, plus 1 byte for string size.
The password should be specified with IDE.BLOWOFF.password as explained above. That is, assuming that you don't want to turn on encryption for your hard-drive. Otherwise, you may just as well use BLOWON to set the password.
To encode data, write them to BLOWPLAIN and retrieve the coded version from BLOWCIPHER. This will be a single string, upto 248 characters in length. NB: It is critical that BOTH files are opened before you write anything to one of them (otherwise you'll get an end-of-file error).
DELETE "IDE.BLOWOFF.THIS-IS-MY-PASSWORD" RUN
100 OPEN #1:"IDE.BLOWPLAIN",INTERNAL,VARIABLE 80 110 OPEN #2:"IDE.BLOWCIPHER",INTERNAL,VARIABLE 249 120 PRINT #1:"This is a test",1234,Y,B$ 130 INPUT #2:CODED$To decode previously coded data, perform the opposite operation: write the ciphered string to BLOWCIPHER and read back the plain data from BLOWPLAIN.
140 PRINT #2:CODED$ 150 INPUT #1:A$,X,Y,B$Note that, because Blowfish always operates on 8-byte values, it may have padded the end of the record with spaces. You shouldn't notice it in Basic (that trims trailing spaces), but be aware of it when working from assembly.
If you have battery-backed SRAMs, always close BLOWPLAIN when done: this will wipe out any plain text that may remain in the card buffers.
If you encrypt a file on a non-crypted disk, a flag bit is set in its FDRs to indicates that the file is encrypted (the FDR is a sector that contains all the file information). The FDR itself is not encrypted, only the sectors that make up the file. These sectors are completely encrypted, irrespective of whether the data occupies the full sector or if there are "junk" bytes in the end.
Since they consists of only a FDR, directory pointers are never encrypted (unless they reside on an encrypted disk, of course).
OPEN #1:"DSK9.",INTERNAL, FIXED 38, INPUT
Record 0 returns disk informations, the following records return information on each file, in alphabetical order. The first empty record returns an empty string and 0 values. Attempts to access records beyond this one result in an end-of-file error.
OPEN #1:"DSK9.",INTERNAL, VARIABLE 128
or, from assembly language
OPEN #1:"DSK9.",INTERNAL, VARIABLE 120
The second form returns all numbers in the form of integers, instead of floating point numbers. These are more convenient for assembly language programs. Strings are still prefaced with size bytes, though.
Technical note: Actually, you can open the catalog as a file of any type. For instance, if you want to access it as a relative file, Basic will force you to open it as a FIXED file. Any file type is accepted, only the record length matters: 38 opens the regular type catalog, 39 to 120 opens the extended catalog and passes numbers as integers, 121 to 128 passes them as floating point numbers. Finally, a record size of 129 or higher is used for sector-wise access (see below). If you don't specify any record size, it defaults to 128.
When opened as "extended", the catalog returns many additional variables (although you don't have to input all of them, if you don't need them all).
Record 0 returns disk information:
INPUT #1, REC 0:NAME$,FILES,SECTORS,FREE,TIMEC,DATEC,TIMEM,DATEM,FLAGS,RES
The next records return information on the files, in the order they appear in the catalog (which should be alphabetical):
The time stamps have the following form:
DATE = (YEAR*512) + (MONTH * 32) + DAYOFMONTH
TIME = (HOURS * 2048) + (MINUTES *32 ) + (SECONDS / 2)
Where YEAR = 0 to 99, MONTH = 1 to 12, DAYOFMONTH = 1 to 31 (for any month), HOURS = 0 to 23, MINUTES = 0 to 59, and SECONDS = 0 to 58.
Note that note that, in order to pack the time in a single word, it is specified in 2-second increments.
A TIMEM value of 65535 is understood as a command for IDEAL not to update the time stamps for this file/floppy. You also have the option to globally disable stamping of all floppies and/or all files when configuring your system.
NAME$: you can change the name of a file but you cannot rename the disk (for this use IDE.FLOPPIES, see below). Caution, the name should be unique: if another file with the same name already exist a "file error" is issued. Leave this string empty to keep the same name.
SECTORS: You can decrease or increase the number of sectors on disk. However, you should not exceed the number of sectors indicated in the FLAG word (this is the maximum space reserved on the hard disk for this floppy).
DATEx and TIMEx: You can always change a date and time, even that of creation. If you set the date of last modification to 65535 (>FFFF), neither the date nor the time will be updated when the file is modified. If you set a value a zero, the current value, as read from the clock, will be used instead. This works for both the disk and the files.
TYPE and RECLEN: You can change the file type and record length, but be carefull: this may well render the file unusable. Negative TYPE values result in protecting the file, positive values do not affect the protection status unless the value is out of range (e.g. TYPE = 99) although it is probably more convenient to use the FLAG bits to change the file protection. Here are some examples of modifications:
FLAGS: You can modify the following flags: Disk protected, File protected, Archive bit for either disk or file.
The disk iteself also contains an archive bit which is modified only if the disk catalog is modified. Which means that if you write to a file, the directory archive bit won't necessarily be changed (it may if you changed the file size, which modifies the sector bitmap).
Note: From assembly language, it is more convenient to use subprogram >10 to perform sector access.
To access a floppy sector-wise, open its catalog as an INTERNAL, FIXED 129 file. Each sector maps to two records in the file, in numeric order. Each record contains a single 128-byte string that corresponds to half a sector.
100 OPEN #1: "DSKV.",INTERNAL,FIXED 129,RELATIVE
110 INPUT #1, REC 2: SEC1A$
120 INPUT #1, REC 3: SEC1B$
Sector numbering starts from zero, so records 0 and 1 correspond to sector 0, records 2 and 3 to sector 1, etc. The above program reads the content of sector 1 into the strings SEC1A$ that contains the first 128 bytes in the sector, and SEC1B$ that contains the last 128 bytes.
You can modify these strings at will, then write them back at the same, or another location. If the string you write is smaller than 128 characters, only that many bytes are modified and the end of the half-sector remains unchanged.
The file can also be opened as a SEQUENTIAL file, but don't forget that each read/write operation moves to the next record. So if you PRINT back a string just after you INPUT it, you will actually write it to the next record!
You can open the file as either RELATIVE or SEQUENTIAL mode. Relative files are easier to work with, but they are limited to 32767 records in Basic and to >FFFE records in assembly, so if you have more floppies you won't be able to access all of them. A sequential file is more cumbersome, but has no limitations on the number of floppies. Note that IDE.FLOPPIES has a special mechanism to jump to any record via record 0 (see below), that works with both sequential and relative files.
100 OPEN #1: "IDE.FLOPPIES",INTERNAL,FIXED 128, RELATIVE
Note: You can set a security option bit while configuring your system, so that the collection cannot be modified by writing to IDE.FLOPPIES. This will prevent malicious programs from messing with your collection. While this bit is set, you can read from IDE.FLOPPIES, but not write to it. Also you cannot use a disk manager to rename a virtual floppy, nor to create a new one. Trying to do so will result in an I/O error #5.
INPUT #1, REC X: NAME$,SECTORS,TIMEC,DATEC,TIMEM,DATEM,FLAGS,RES
INPUT automatically moves to the next record each time it's called so you can easily travel a sequential file, or a relative file without a REC clause, by just repetedly reading its records.
The record structure is the same as described above. Any parameter that you omit or leave as 0 remains unchanged. To keep the same name, you can pass it as an empty string.
PRINT #1, REC 12: "",356
This changes the apparent disk size (as it appears on its catalog, on sector 0) to 356 sectors.
The one thing that you cannot change is the physical size of the floppy as determined by the flag bits, i.e. the amount of space it takes on the hard disk. If you really want to do this, you must delete the floppy and create another with the proper size.
PRINT #1, REC 0: "MYDISK"
If the name does not exist, a "file error" is issued.
Searching for an empty string jumps to the end of the file, so you can add new floppies to your collection.
You can also read back the record number corresponding to the searched floppy, from record 0. Be aware that doing so rewinds the file, so the next record accessed will be record 1.
INPUT #1, REC 0: A$,R
or, for sequential files
INPUT #1: A$,R
A$ will contain the string you passed with the PRINT statement above (if any). R contains the record number that corresponds to this floppy, or 0 if the floppy wasn't found.
N.B. None of this can be done with the trash files.
CAUTION: every time you create, delete or rename a floppy, your collection is rearranged in alphabetical order. Thus, you should never assume that a given record will access the same floppy after an addition/deletion than it did previously. In addition, as your collection grows, you may notice a delay of a few seconds, and a lot of disk activity while the collection is rearranged.
To recover a floppy from the trash, you must first locate it. The most recently deleted floppy is in record 0, the oldest one at the end of the file: this is the one that will be recycled next. Each record consists in only one string of at most 10 characters, which contains the name of the deleted floppy.
Once you found the record containing your floppy, just write a new name (or the same one) to its record. This will automatically return the floppy in your collection, provided the disk name does not already exist in the collection, in which case a file error would be issued.
90 REM Recover a 360-sector floppy named HERE-IT-IS 100 OPEN #1:"IDE.TRASH1", INTERNAL, FIXED 80, UPDATE, RELATIVE 110 I=-1 120 I=I+1 130 INPUT #1,REC I:NAME$ 140 IF NAME$<>"HERE-IT-IS" THEN 120 150 REM we found it in record I. Let's recover it (with same name) 160 PRINT #1,REC I:NAME$ 170 REM we could use ON ERROR in case the name already exists, to pick a different name 180 CLOSE #1You can also open the file as sequential: every read operation moves forward to the next record. A write operation accesses the record that was read last (or record 0 if the file was just open).
90 REM Recover a 720-sector floppy named THAT-ONE 100 OPEN #1:"IDE.TRASH2", INTERNAL, FIXED 22, UPDATE, SEQUENTIAL 110 RESTORE #1 120 INPUT #1:NAME$ 130 IF NAME$<>"THAT-ONE" THEN 120 130 REM we found it. Let's recover it with a different name. 140 PRINT #1:"NEWNAME" 150 CLOSE #1
100 OPEN #1:"CLOCK", INTERNAL, FIXED 128, RELATIVEMost variables can be modified by just writing the new values to the appropriate record. Note that you must write all elements in a record, even if you leave some unchanged. Illegal values are ignored, so it is a convenient way to leave an element unchanged (alternatively, read it first and write back what you read).
There is no need to close the file when done, but it won't hurt to do it:
500 CLOSE #1
110 INPUT #1,REC 0:WEEKDAY,DAY,MONTH,YEAR1,YEAR2
120 INPUT #1, REC 1: HOURS,MINUTES,SECONDS,SETTINGS,CALIBRATION
130 INPUT #1,REC 2:HOUR,MINUTE,SECOND,INTF,ACTION,VECT,REC,SCRAD,DAY
The clock can trigger TI-99/4A interrupts, either at defined intervals or when the alarm goes off. Of course, interrupts will only be effective if the program currently running has enabled them (with a LIMI 2 instruction). Basic and Extended Basic do so, but some assembly programs may not.
Reading INTF lets you know what happened, writing to it lets you specify which kind of interrupt is allowed.
Four actions can be taken when an alarm occurs: the screen can blink 3 times (this uses the copy of VDP register 1 stored at >83D4), a beep can sound 3 times, the time or the date can be displayed on screen in one of the formats specified in records 4 to 11, or a call can be made to a program of yours. Any combination of these actions is allowed.
To display the time or the date, select the format desired from those described for the records below and use this record number for the REC value. For instance, use 8 to display the time as "6:55 pm". Tip: using records 100-227 accesses the RTC65271 clock RAM, which allows you to display a preset message on screen. Just place the message (with a leading size byte) in the appropriate clock page by writing it to the corresponding record and puts this record number in REC. Be carefull not to overwrite the bootstrap program in the first clock pages.
If you call a program it MUST be in memory when the interrupt occurs, otherwise the system will crash mercilessly. The program is entered with a BLWP after then interrupt service routine has returned. Once done, you can return to the interrupted program with a simple RTWP.
In addition, IDEAL uses alarms to put a drive to sleep after a given period of inactivity. The sleep algorithm triggers an interrupt every minute and counts them until the specified number of minutes has elapsed. Any disk operation resets the counter. If you are using the alarm for any other purpose, you should clear bit 128 in the ACTION word so as not to mess up the count (unless you happen to have set an alarm every minute).
Finally, turning the console off, then back on disables all interrupts. This was done so that the computer won't lock up if an interrupt fires when IDEAL is not loaded to acknowledge it. With the RTC65271 clock, you have the option of opening DIP-switch #2 so that interrupts are NOT disabled upon power-up. Use at your own risks...
140 INPUT #1,REC 3:PERIOD,INTS,ACTION,DATA
The same actions as for an alarm interrupt can be specified. However, since the maximum interval is half a second, there is no point in blinking the screen, nor beeping when such an interrupt occurs. Most likely you will only want to call a program at this point. Just be aware that answering an interrupt takes time. So if you set interrupts at too short a period, the computer will end up spending most of its time servicing interrupts!
150 INPUT #1,REC 4:DATE$,DAY$
160 INPUT #1,REC 5:DATE$,DAY$
170 INPUT #1,REC 6:DATE$,DAY$
180 INPUT #1,REC 7:DATE$,YEAR$,DAY$
190 INPUT #1,REC 8:TIME$
200 INPUT #1,REC 9:TIME$
210 INPUT #1,REC 10:TIME$
220 INPUT #1,REC 11:TIME$
You can get a dump of all clock registers by accessing record 12:
230 INPUT #1,REC 12:R0TO63$,R64TO127$
You can write to this record to place new values in the clock RAM registers. Registers 0 to 13 are reserved for clock registers, so the first 14 characters of R0TO63$ will be ignored. Register 14 of the RTC65271 is used by IDEAL to store the first two digits of the year (20), so make sure you leave this 15th character intact. By contrast R64TO127$ is copied entirely, which may result in modifying the clock registers if you have only 64 registers. For this reason, you must always pass two strings when writing to record 12: the second string should be empty unless you are sure you have a clock chip with more than 64 registers.
240 A$=SEG$(R0TO63$,1,15)&CHR(67)&SEG$(R0TO63$,17,64) 250 PRINT #1, REC 12: A$,""This example puts the number 67 into register 15 (the 16th character in the string) and leaves the other registers unchanged.
The bq4847 has only one extra register, which must always be zero. Thus R0TO63$ is read as a 15-byte string and cannot be written to. Similarly, the bq4842 and bq4852 have no extra registers, so this string is 16-byte long and cannot be modified either. In both cases, the second string R64TO127$ is not used.
140 PRINT #1,REC 13:PERIOD,UNITS,ACTION,DATA
To prevent the watchdog from firing, a program must constantly write to record 13 before the grace period is expired.
N.B. The watchdog timer is automatically disabled after power went off.
300 INPUT #1, REC PAGE+100: A$
Technically, only the RTC65271 has onchip RAM, the other clock chips emulate this feature by placing data into the SRAM. With the bq4847 clock, there is only room for 14 pages (records 100 to 113), with the bq4842 and bq4852 clocks you can have 120 pages (records 100 to 219).
You can also write to these pages, but be carefull as IDEAL reserves the first pages of the RTC-65271 for its own use (they contain the system configuration and the boot sequence that loads IDEAL into the card SRAM). Before writing anything, check the fourth byte in page 0: it contains the number of the first free page (or zero if all pages are used). Feel free to update this byte as you reserve pages for your own use.
310 INPUT #1, REC 100:A$ 320 PAGE=ASC(SEG$(A$,4,1) 330 PRINT #1, REC PAGE+100:MYFIRSTPAGE$If the string you write is shorter than 32 bytes, the remainder of the page remains unchanged.
100 OPEN #1:"IDE.CONFIG",INTERNAL, FIXED 128, UPDATE, RELATIVEAlternatively, you can open it as Int/Fix 120, in which case all numbers will be passed as integers (or 32-bit long integers for LBAs). This is usefull when working from assembly, so you don't have to deal with floating point numbers.
Technical note: actually, the file type is not checked, only the record size is. A record size of 128 or above uses floating point numbers, any size under 128 uses integers. Basic stupidely prevents you to open variable files as relative, so you must either use FIXED, or open the file as SEQUENTIAL. There is no such limitation if you work from assembly.
You can modify some of these values by writing to the desired record. Note that some records are read-only.
Once you are done, don't forget to close the file: it's at this point that the configuration is saved on disk. When you write to the file, the changes are only saved into the SRAM and the RTC65271 clock XRAM, if you have this clock chip.
500 CLOSE #1By the way, saving the configuration to the hard drive is something that you may want to do from time to time, just is case the clock battery would run out... To this end, you must open IDE.CONFIG, write to it at least once (e.g. to enter your password), the close it.
110 INPUT #1:PASSWORD$, LOCK, VERSION, PARTITION, VIRDRIVE
To access a locked file, all you need to do is to write your password to record 0. The file is temporarily unlocked, until you close it. If you want to unlock it permanently, set LOCK as 0.
To change your password you must write twice to record 0: first write the old password and set LOCK as 1, then write the new password and set LOCK as you like.
110 INPUT #1:PATH$,DRIVENB,LBA
110 INPUT #1,REC 5: SYSPATH$,MAXLBA,SLAVELBA,ROOTLBA,TOPLBA,SYSLBA,F360,F720,F1440,L360,L720,L1440
MAXLBA and SLAVELBA let you define the size of your master and slave drive respectively. This space will be available for the floppy disk collection. If you wanted to reserve space for other purposes on the drive, you could set either parameter to less than the actual hard disk size. If you have no slave drive, just set SLAVELBA as 0, so that the floppy collection won't be expanded on the slave drive once the master is full.
With SYSPATH$ you indicate the location of the IDEAL system files, so they can be loaded at power-up time. It must be in the form of a diskname, a dot, and the name of the first system file. When you write to SYSPATH$, the corresponding SYSLBA is automatically computed or a "file error" is issued if the disk does not exist (but the presence of the system files on this disk is not verified).
TOPLBA and ROOTLBA are internal pointers to your floppy disk collection. F360 through L1440 are internal pointers to the three lists of deleted floppies. All are automatically updated when you edit the collection. WARNING: it is very risky to modify these pointers yourself, as this could completely mess up your collection. The only time they should be written to is when trying to restore your configuration frmo record 22, after it was accidentally lost (assuming you had no configuration backup).
110 INPUT #1: NAME$,DRIVENB,LBA,SIZE
110 INPUT #1:NAME$,DRIVENB,FLOPPYLBA
200 INPUT #1:RTCNAME$
130 INPUT #1:FULLNAME$,ONOFF,XBFULLNAME$,CRU
The existance of FULLNAME$ and XBFULLNAME$ is only verified when they are actually used, so you won't get an error if you enter the name of a file that does not exist (yet).
240 INPUT #1:OPTIONS, SLEEP, OPENED, MAXOPEN
1 = Time-stamp virtual floppies.
2 = Time-stamp files.
4 = Allow sector-wise access.
8 = Recycle deleted floppies to create new ones.
16 = Wipe encryption key upon reset.
32 = Allow only one Dis/Fix directory file per disk (the parent).
64 = Do not delete Dis/Var directory files when target disk is deleted.
128 = Do not allow modifications to the floppy collection (i.e. write-protect IDE.FLOPPIES).
256= Put inactive drives to sleep.
512 = RAMBO mode not allowed (even if supported by the hardware).
1024= Encryption not supported.
2048= Floppy collection manager and trash manager not supported.
4096= Configuration manager, extended catalog and sector-wise access not supported.
8192= CLOCK DSR not supported (but time stamping still is).
Flags "1" through "128" are self explanatory and have been discussed in the relevant sections anyhow.
By setting the "256" flag, you can cause the drives to be put to sleep after a given number of minutes of inactivity. The number of minutes can be set with the SLEEP value. The sleeping algorithm makes use of the clock alarm to trigger an interrupt every minute, and decrease a counter. When the counter reaches zero, the "sleep" command is sent to the drives. Accessing any DSR or CALL on the card resets the counter to the SLEEP value, thereby delaying the moment to put the drives to sleep. Once a drive is asleep it may take several seconds to wake up, so the next drive operation could appear hanged up, but don't worry: the command will complete as soon as the drive is ready. N.B. Modifications to this flag only become effective when you reset your TI-99/4A.
The flags "512" through "8192" let you disable some parts of IDEAL, so that you can save memory or loading time, by using a truncated version of IDEAL. I'd recommend that you use the full-fledge version, but it's up to you.
250 INPUT #1:CONFIG,SRAM,RAMBO,REGBIT,SWBIT,FIXBIT,RAMBOBIT,WPBIT,RSTBIT,IRQBIT
1 = has battery-backed SRAM.
2 = has XRAM in clock.
4 = clock can send interrupts.
8 = RAMBO mode supported by hardware.
Once scanning is completed, record 22 returns the following values:
910 INPUT #1:ERROR,ROOTLBA,TOPLBA,F360,F720,F1440,L360,L720,L1440ERROR: returns the error status. See below.
These values can be written into record #5 to restore a lost configuration. Make sure you first check the error code, then the individual LBA pointers for validity. A missing pointer is returned as zero.
>0001: Disk read error (fatal, aborts scanning)
>0002: Multiple canditates for F360
>0004: Multiple canditates for F720
>0008: Multiple canditates for F1440
>0010: Multiple canditates for L360
>0020: Multiple canditates for L720
>0040: Multiple canditates for L1440
>0080: Can't find F360 or L360 (or both). No error issued if no deleted file of this size was found.
>0100: Can't find F720 or L720 (or both). Ditto.
>0200: Can't find F1440 or L1440 (or both). Ditto.
The scanning algorithm checks the "protected" area of sector 0 for each virtual floppy. First and last deleted files are detected by the lack of a "previous" or "next" link. The root of the active collection is the floppy with the highest number of children in its left subtree, if there is a tie the one which is heavy on the right wins. The routine stops scanning when this area doesn't match the expected format (be aware that string of >00 does match the format...). As a result, scanning may be aborted if a damaged disk was encountered.
You have several options to modify the scanning strategy, by writing to record 22 prior to reading it:
900 PRINT #1: TOTAL,FIRSLBA,LASTLBATOTAL: indicates the number of virtual floppies that the routine should search. For instance, if you know you have less than 300 floppies in your collection, use 300. If zero, this parameter will be disregarded.
When both TOTAL and LASTLBA are specified, scanning stops when the first of the two limits is reached. If TOTAL and LASTLBA are both zero, scanning continues until an invalid format is detected, which is the default situation if you do not write to record 22 at all.
To access your drives, open the file IDE.SECTORS as a INTERNAL, FIXED 129 file in Basic or Extended Basic. In assembly, use a record size of 130: this will cause numeric values to be passed as 32-bit long integers, rather than as floating point numbers.
100 OPEN #1: "IDE.SECTORS", INTERNAL, FIXED 129, RELATIVEIDE.SECTORS is a pseudofile that contains only five records. Record 0 is used to set the sector number, and records 1 through 4 each contain a 128-byte string corresponding to a quarter of the selected sector. Oh yes, I forgot to mention it, but hard drives have 512-byte sectors.
To read a hard-drive sector, you would do:
110 PRINT #1, REC 0: LBA1,LBA2 120 INPUT #1: PART1$,PART2$,PART3$,PART4$Then you can write the strings back. The address won't change unless you write a new one to record 0. (In case you forgot what it was, you can read it back from record 0).
130 PRINT #1:PART1$,PART2$,PART3$,PART4$If one of the strings contains less than 128 bytes, or if you don't write back all four strings, the remaining bytes in the sector are unchanged.
You don't have to explicitely close this file, but it won't hurt doing it:
200 CLOSE #1
For your convenience, if you pass a negative number in LBA1 it will be ignored and LBA2 is assumed to contain an address in the slave drive, to which the corresponding bias will be added (thus LBA2 should be in the range 0 to 268,435,455). If LBA1 is positive, LBA2 will be ignored.
Finally, if both LBA1 and LBA2 are negative, the address is bumped up to the next sector. This is usefull to walk the drive sector by sector:
140 PRINT #1, REC 0:-1,-1When working from assembly, you can avoid dealing with floating point numbers and use long integers (32-bit words) instead. To this end, just open the file as INTERNAL, FIXED 130. This tells IDEAL that all LBAs should be passed to and from record 0 as long integers.
It is also possible to use the DSK.DISKNAME.FILENAME syntax, but this may not work if the TI disk controller is installed: this stupid controller returns an error if it does not find the disk in drives 1-3. Thus DSK.DISKNAME only works properly when the IDE card is called before the TI disk controller, i.e. when its CRU is >1000.
As a remedy to this unfortunate situation, an extra DSR called DSK@ is provided. It is completely equivalent to DSK and should be used in the same way: DSK@.DISKNAME.FILENAME. Since the TI controller does not contain DSK@ it won't interfer with the search.
An extra DSR called DSK* lets you access files on the same drive that was last used (by either a DSR or a call). This is usefull when a program must load data files: by using the DSK*.FILENAME syntax, you ensure that the data files will always be loaded from the drive the program was on.
The standard opcodes defined by Texas Instruments are all implemented:
Several improvements, introduced with the Horizon Ramdisk, have been included:
In addition, the following extra opcodes were defined by the Horizon Ramdisk, and are also supported by IDEAL:
These serve to load and run a program. They are called automatically by the LD DSR, but you can also use them from your assembly programs.
DELETE "LD.n.filename" from any language CALL LD.n.filename from TI-Basic or assembly CALL LD".n.filename" from Extended BasicDELETE is used here as an exemple. Actually, any file operation will do (e.g. OPEN, OLD, SAVE, RUN, and DELETE).
Alternatively, you may use the disk name:
RUN "LD.@.diskname.filename" CALL LD.@.diskname.filename CALL LD".@.diskname.filename" (Extended Basic only)The @ sign in place of a drive number instructs LD to look for a vitual floppy in your collection (by analogy with DSK@).
CALL HAOSwitches autostart on: each time you reboot your TI-99/4A the selected program will be called in place of the "Texas Instruments Home Computer" colorfull screen.
CALL HAO.diskname.filenameSame as above, but lets you change the file that should be called when booting. Note that you must specify a diskname (not a DSKn drive) and a filename with no subdirectories inbetween. Beware that it will not work in Extended Basic (not even with quote marks), so always use TI-Basic to change the name of the auto-start file.
CALL HAFSwitches autostart off. Note that CALL HAF.diskname.filename can also be used.
CALL HABSwitches autostart on for only one time: when you do a hard reboot (i.e. turn the PE box power off ). This is usefull if you want to load a cartridge in your GRAM card at power-up time: obviously there is no need to reload it each time you press the <quit> key! On the other hand, if power is turned off, the cartridge will likely be wiped out of the GRAM card, and you'll need to reload it. Since IDEAL will also be reloaded in such a situation, it will automatically load your cartridge.
Here also, CALL HAB.diskname.filename is legal.
Note: the autostart file can also be set with the configuration manager (see above).
Opcode >0A loads a program file in EA5 format, i.e. that starts with a 6-byte header in the form:
>0004: loading address
If flag is not >00xx, loading continues with a file having the
same name but for the last character that is incremented (e.g. MYFILE1
Execution normally starts at the beginning of the first file.
Bank is used to load a program into the IDE card SRAM banks. It should contain the bank number, plus 32 (because banks 1 through 31 are reserved for GRAM cards). Note that, when execution begins, the last bank is on, not the first one!
Size specifies the number of bytes to load. It can be ignored, depending on the PAB (in which case the whole file is loaded).
Address is the address where to load the program. It can be superceeded by the PAB.
Some parameters in the PAB have unusual meanings:
|>0008||(not used)||Name size|
PAB+0: Contains the opcode (>0A)
PAB+1: Should be 0. It will contain error flags if an error occurs.
PAB+2: Address where to start execution. >0000: at the beginning of the first file. >FFFF: load but don't execute.
PAB+6: If this word contains 0 (or >8000) no size checking will occur. Otherwise, the file will only be loaded if its size (as specified in the file FDR) is smaller or equal to this value. The >8xxx bit has a special meaning: when set, the number of bytes is taken from SIZE, the second word in the file. When the bit is reset, this word is ignored and the whole file is loaded.
Note that execution cannot return to the caller once Extended Basic is done...
If IDEAL does not find Extended Basic, but you have a GRAM card and you have the Extended Basic cartridge stored somewhere on the hard disk, the program will load the cartridge into the GRAM card and the proceed with launching the XB program. For this to happen however, you must use IDE.CONFIG to declare the location of the XB cartridge (see above).
Only a few bytes in the PAB are actually used with opcode >0B:
|>0008||(not used)||Name size|
PAB+0: Contains the opcode (>0B)
PAB+1: Should be 0. It will contain error flags if an error occurs.
If flag is not >00, loading continues with another file. The
second file has the same name than the first one, with an extra "1". For
the following files, the "1" is incremented. So the sequence of names would
be: MYFILE, MYFILE1, MYFILE2, etc.
Bank specifies the GRAM area into which the file should be loaded. Note that this information is redundant, since the address is already part of the header. Alternatively, bank can specify a page in the cartrige RAM space (>6000-7FFF). Standard cartridges and GRAM cards have only two RAM pages but the german GramKarte allows for 16. In general the lower part (>6000-6FFF) is identical in each bank, but there may be exceptions...
Size specifies the number of bytes to load.
Address it the address (in GRAM or RAM) where to load the data.
option corresponds to byte 4 in the GRAM, which is normally zero. If it contains >A5 the GRAM device will be turned off after loading. If it contains >5A only the RAM banks in the GRAM card will be turned off after loading.
Here is a summary of the valid values for "bank":
>01: GRAM at >6000
>02: GRAM at >8000
>03: GRAM at >A000
>04: GRAM at >C000
>05: GRAM at >E000
>06: GRAM at >0000 (caution: conflicts with console GROMs)
>07: GRAM at >2000 (ditto)
>08: GRAM at >4000 (ditto)
>09: RAM bank 1 (>6000-7FFF)
>0A: RAM bank 2 (normally only >7000-7FFF, but some device may allow >6000-7FFF).
>0B: RAM bank 3 (only on some devices)
>18: RAM bank 16
Some parameters in the PAB have a special meaning:
|>0008||(not used)||Name size|
PAB+0: Contains the opcode (>0C)
PAB+1: Should be 0. It will contain error flags if an error occurs.
PAB+2: If this word contains >98xx, this value is used as a GRAM base. Otherwise, the current GRAM base stored at >83FA is used. If >83FA does not contain a valid >98xx value, the default base >9800 is used.
If you have another GRAM device than the above, you can write yourself a new version of this subroutine and IDEAL will use it to control your device. This routine should be assembled as an AORG segment, to reside at addresses >5900-5B00. As it is called by a BLWP instruction the first two words (at >5900 and >5902) should be the workspace and the routine address. You can place your workspace in the same memory area, between >5904 and >5B00. I would advise you to use the RAG linker to generate the final "program" file, since the TI loader cannot load a DF80 file at >5900. Be aware that your routine will not be able to call DSRs or other routines in the gram-card ROM since these would conflict with the IDE card DSR space.
The default gram-card CRU, as set with IDE.CONFIG, can be retrieved from the caller's R1 with a MOV @2(13),R12 but this is entirely optional: you could "hard-wire" the CRU inside your code if you want to (for instance if you have several gram-cards).
IDEAL will call your routine for various purposes. The reason for the call is found in the caller's R0, that you can retrieve with a MOV *R13,R0.
Here is a sample Gram-card routine, that handles the German 128K Gram
*==================================================== * User-defined GRAM card routines for GramKarte * Common entry point, loading code in *R13 *---------------------------------------------------- * CRU bit Meaning * ------- -------- * Bit 0 1=DSR on * Bit 1 1=banks on * Bit 2 GRAM-enable 2 * Bit 3 0=GRAM on * Bit 4 0=write-protect banks * Bit 5 1=overwrite console GROMs * Bit 6 1=use default bank (DIP-switch selected) * Bit 7 0=switch banks 1=access banks *==================================================== AORG >5900 GCARD DATA WREGS,GKARTE vectors (MUST be right here) * GKARTE INCT R14 always ok: skip JMP upon return MOV @2(R13),R12 get default CRU MOV *R13,R11 get loading code JLT GKDONE >FFxx = done CI R11,>0008 check if RAM-bank or GRAM JH GKBNK bank * Load in GRAM SBZ 3 turn GRAM on CI R11,>0006 is it in console space ? JL GK1 no SBO 5 yes: override console GROMs * DECT R14 alternative: skip this file GK1 RTWP * Load in banks GKBNK SBZ 1 bank read ok SBZ 4 bank write-protected SBZ 6 no default bank SBZ 7 bank switching enabled AI R11,-9 adjust bank # SLA R11,1 MOV R11,@>6000(R11) switch SBO 7 bank switching disabled SBO 4 bank write-enabled RTWP * Done with loading GKDONE SB R11,R11 keep only clue code CI R11,>00A5 code for "card off" JNE GK2 SBO 1 banks off SBO 3 GRAM off SBZ 4 write-protect banks SBZ 5 console GROMs in charge RTWP GK2 CI R11,>005A code for "banks off" JNE GK3 SBO 1 banks off SBZ 4 and write-protected RTWP GK3 SBZ 4 normal case: write-protect banks SBZ 7 enable switching RTWP * WREGS BSS 32 our workspace END
When a floppy is "inserted" into a virtual drive, its protection status is read by the drive and comes into effect. However, you have the option to temporarily override this status and set a different protection, just for this drive:
CALL WO.n sets write protection on for drive n
CALL WF.n turns write-protection off for drive n
Note that this does not affect the write-protection status of the floppy in your collection, nor does it affect other drives that may be accessing the same floppy. (Yes, you can load the same floppy in several drives. But this is quite risky if more than one drivehas write permission...)
If you insert a new floppy in the drive, the protection status of that floppy will come into effect. In other words, whatever command arrives last is the one that prevails.
CALL DN.o.nwhere o is the old drive number and n the new number (e.g. CALL DN.8.5 renames DSK8 as DSK5).
An error will occur if a drive with that number already exists in the IDE card, but IDEAL cannot check for the presence of such a drive in the floppy disk controller card, nor in a Ramdisk card. In case of conflicting drive names, the card with the lowest CRU address is the one who will be accessed.
CALL HAO turns autostart on
CALL HAF turns autostart off
CALL HAB only autostarts at boot time (i.e. once, after power went off).
Either of these can also be used from TI-Basic (or assembly) to change the program to be started at power-up time:
CALL HAO.diskname.filenameThe selected program may be an assembly program in EA5 format, an Extended Basic program (in which case the Extended Basic cartridge may be automatically loaded in your GRAM card, if needed), or a cartridge dump in GramKracker format. Note that cartridges are loaded, but not executed, unless they contain a power-up routine or a foreign language translation routine.
CALL CD.n..diskname from TI-Basic or assembly CALL CD".n..diskname" from Extended BasicThis will "insert" the virtual floppy named "diskname" into drive DSKn. Note the double-dot syntax that signals a disk name.
CALL CD.n.directory from TI-Basic or assembly CALL CD".n.directory" from Extended BasicThis will insert the disk pointed at by a directory file located on the disk currently inserted in DSKn. This time, there is only one dot after the drive number, which indicates a directory path.
This will insert the parent of the current vitual floppy in DSKn. A virtual floppy has a parent if at least one directory file points to it. If there is more than one, the first one you created is the parent unless you specified it otherwise. This allows you to organise your floppies in a tree-wise manner, as on a PC:
DISK1 +-HERSTUFF------->DISK5 | +-LETTER1 | +-LETTER2 | +-MYDIR---------->MYDIR +-OTHERFILE +-GAMES----->GAMES | +-CHESS | +-HANGMAN | +-NUDIES---->DISK4 +-CLAUDIA +-ELLE +-SOPHIEFor example, assume the virtual floppy named GAMES is currently inserted in drive DSKZ and you want to access the file called LETTER1. You could do something like:
OPEN #1: "DSKZ.<.<.HERSTUFF.LETTER1", DISPLAY, VARIABLE 80Of course, you could also do it this way:
OPEN #1: "DSK@.DISK5.LETTER1", DISPLAY, VARIABLE 80or this way:
OPEN #1: "DSK@.DISK1.HERSTUFF.LETTER1", DISPLAY, VARIABLE 80
|>834C||Drive #||0: write
|>834E||Data buffer address|
IDEAL stores some information at the end of sector 0 (bytes >EE-FF) that is used to manage the floppy disk collection. Since these data are critical for proper operation, subprogram >10 does not let you modify them.
If you have set the time-stamping option while condiguring IDEAL, bytes >14 through >1B may be automatically modified upon writing sector 0. The current time and date are written to bytes >18-1B (last modification stamp) unless bytes >18-19 contain >FFFF. If bytes >14-15 contain >0000, the same values are also written to bytes >14-17 (creation stamp).
Subprogram >10 can tell whether sector 0 is encrypted or not, but it cannot do it with other sectors. So it just assumes that, if encryption is on (DELETE "IDE.BLOWON"), the whole disk must be encrypted: it decodes any sector you read and encodes anything you write. If that's not what you wanted, turn encryption off (e.g. DELETE "IDE.BLOWOFF").
Additionally, if encryption is set with DELETE "IDE.BLOWOUT", subprogram >10 will use encryption or not (both to read and write), according to what was determined the last time sector 0 was read. This lets you turn encryption on and off from within a disk manager: first read sector 0, then the sector you want to access. As it turns out, DISKU's sector editor always reads sector 0 (to determine what the maximum sector number is) before it lets you edit another sector, so if you use DISKU encryption is always turned on/off appropriately after calling BLOWOUT.
To sector-edit encrypted files on a non-encrypted disk, you will need to force encryption with DELETE "IDE.BLOWON". This will of course cause all non-crypted sectors of the disk (except sectors 0+1) to appear scrambled!
If you try to access an encrypted disk (as determined by a flag in sector 0) but no password has been entered yet, you will get a disk error. If you have entered the wrong password, no error is issued but you'll read only garbage. Note that, as long as you write back exactly what was read, no data will be lost. Problems only arise when you modify a sector and save it with the wrong password...
|>834C||Drive #||>A5 flag|
|>8350||Density (1/2)||# of sides (1/2)|
Density (1 or 2) and number of sides (1 or 2) are combined so as to
choose among 3 possible sizes:
SS/SD: 360 sectors (90K)
SS/DD and DS/SD: 720 sectors (180K)
DS/DD: 1440 sectors (360K).
Byte >834D should contain >A5 if you wish to pass a diskname in the buffer pointed at by >834E. The name must be exaclty 10 characters in size, so pad the string with trailing spaces if necessary. If this name already exists in your floppy collection, a "file error" is issued. If the first character in the name is not printable (ascii 33-127) the filename is considered invalid and IDEAL will coin a dummy filename in the form "!xxxx" where xxxx is an arbitrarily chosen hexadecimal number. This also happens if the flag byte >A5 is not found in >834D. This is generally the case when you use the "format" command of a disk manager: it creates a noname disk and then names it by modifying sector 0.
|>834A||# of sectors per disk|
If encryption is on (i.e. DELETE "IDE.BLOWON") the new disk
will be automatically encrypted with the current password. This will not
occur if encryption is set as "output-only" (i.e. DELETE "IDE.BLOWOUT").
|>834C||Drive #||0: unprotected
The filename must be a left-justified, 10-char string. Add as many trailing
spaces as necessary.
|>834E||New name ptr|
|>8350||Old name ptr|
Filenames must be 10 character strings, with as many trailing spaces
as necessary. Beware that no check is made to ensure that the new name
is a valid filename!
|>834C||Drive #||# of sectors|
|>8350||Info ptr (>83xy)||-|
# of sectors: 0 = Get file info (fills the structure below, using data
from the file's FDR)
<>0 = Read this number of sectors (starting from the first sector indicated in the structure below).
|>83xy||VDP buffer address|
|+2||First sector #|
|+4||File type||Recs / sector|
|+6||EOF offset||Rec lenght|
|+8||# of rec||-|
|>834C||-||# of sectors read|
Result of get file info (# of sectors=0):
|+4||File type||Recs / sector|
|+6||EOF offset||Rec lenght|
|+8||# of rec||-|
|>834C||Drive #||# of sectors|
|>8350||Info ptr (>83xy)||-|
# of sectors: 0 = Create file (using info in the structure below to
create the FDR)
<>0 = Write this number of sectors (from the first sector indicated in the structure below).
|>83xy||VDP buffer address|
|+2||First sector #|
|+4||File type||Recs / sector|
|+6||EOF offset||Rec lenght|
|+8||# of rec||-|
|>834C||-||# of sectors writen|
The IDE card has its own memory chip and uses it both to store the DSR and to buffer opened files. Therefore it is not necessary to constantly jungle with VDP memory usage, and subprogram >16 and FILES are not implemented in IDEAL.
There is a way to specify how many opened files you allow, when configuring your system with IDE.CONFIG. By default, this number is 15, so at any given time you can have upto 15 files opened on the hard-drive.The absolute maximum value depends on the size of your SRAM.
Returns the total number of pages available in all Rambo devices.
Important note: if you have an Horizon Ramdisk and an IDE card, you should run this subprogram this way before you select a given page. It will let IDEAL bias the page number by whatever pages there are on the Ramdisk (e.g. if there are 100 pages in the Ramdisk, page 101 is the first one in the IDE card).
|>834C||Page #||CRU value|
Selects a given Rambo page. Returns the CRU of the Rambo device in >834A and the CRU value used in >834C. Note that Rambo pages are not selected through the CRU with the IDE card, so the value returned in >834C can only be used to turn Rambo mode on, NOT to switch pages: always use subprogram >B0 for this.
Turns off Rambo mode.
Bytes Contents >14-15: Time of creation. >16-17: Date of creation. >18-19: Time of last modification. >1A-1B: Date of last modification. >EE : Flags (>10=archive, >02=encrypted, >04=720 sectors, >08=1440 sectors, >20=protected). >EF : Node balance (>FF=heavy left, >00=balanced, >01=heavy right, >80=deleted). >F0-F1: Number of items in the left subtree. >F2-F5: LBA of left subtree(>0000 0000 if none). >F6-F9: LBA of right subtree (ditto). >FA-FD: LBA of parent directory (ditto). >FE-FF: Sector # for FDR of pointer file on parent directory.N.B. Sector 1 follows the TI format with no modification: it lists the sector numbers for the FDR of all files, in alphabetical order. The list must finish with a >0000, thus there can be only 127 files on a given disk.
Bytes Contents >0A : Flags (>10=acrchive bit, >02=Encrypted, >08=directory pointer). >14-15: Time of creation. >16-17: Date of creation. >18-19: Time of last modification. >1A-1B: Date of last modification.
Bytes Contents >20-23: LBA of the current disk (i.e. of sector 0). >24-27: LBA of sector 0 for previous link. >28-29: Sector number for previous link. >2A-2D: LBA of sector 0 for next link. >2E-2F: Sector number for next link. >30-31: Number >0000 (used to detect when it's encrypted).Revision 1. 7/28/00. Preliminary, not for release. Revision 2. 5/28/01. Ok to release (about time!). Revision 3. 8/25/01. Minor modifications to "Getting started". Revision 4. 4/14/04. Modified for the new version of the IDE card, and bug fixes. Revision 5.7/6/04. Final polishing. Ok to release. Revision 6. 9/14/04. Added info on errors with IDELOAD, corrected typos. Revision 7. 10/17/04. Corrected floppy creation example. Added IDEDIAG.