Ramdrive 1.0 Technical Manual
This document explains the operation of Ramdrive 1.0 in more detail, and includes some of the more technical aspects behind its operation.
Ramdrive works by copying the OS ROM to RAM, and then installing itself in the area from 52069 to 53247, this is the area occupied by the second character set in the XL/XE, and a few empty bytes that lie before it. This does mean that you lose the second charset, however this area is unused by the OS B and little used by the OS C, making it ideal for this purpose. Ramdrive 1.0 also uses this area to store the configuration information for each ramdrive that you set up. The Ramdrive 1.0 code itself occupies 1042 bytes, and an extra 23 bytes are needed for each ramdrive you set up. If for whatever reason you want to use this area for another purpose, then you can easily move the Ramdrive 1.0 code somewhere else (if you can find somewhere else to put it that is) with the LOAD_ADDR command in the RAMDRIVE.CFG file. Since Ramdrive 1.0 copies the OS ROMS to RAM, it also means that you can modify you OS by poking value directly into the OS area, however you should be careful if doing this, since you can easily crash your system this way. Ramdrive 1.0 doesn't copy the OS to RAM until after the RAMDRIVE.CFG file has been processed, so if you do want to modify your OS with POKE or DPOKE commands in the Ramdrive configuration files, then you must do it in the RAMDRIVE.CPY file.
Ramdrive 1.0 has been designed to be flexible, and as such it has several configuration commands which can be used to set it up for your system. By default, Ramdrive comes set up to run on a 128K 130XE machine, however if this is not to your liking then you can tell Ramdrive 1.0 to set itself up for your system. The next section of this manual deals with the ways in which Ramdrive can be configured to use different extended RAM sizes.
Bank switching
The standard XE memory expansion, as used in the 130XE, consists of an extra 64K of RAM bringing the computer's total memory up to 128K. However the 6502 microprocessor at the centre of the Atari 8-bit can only access 64K of memory (RAM and ROM) at any one time. Hence the extra RAM in the 130XE is divided up into 4 16K blocks (4*16=64K). Each of these blocks can then be switched into the 6502's address space one at a time by replacing a 16K block of main RAM. These 16K blocks appear in the address space between 16384 ($4000 hex) and 32767 ($7FFF hex). By switching in different extended banks at the right time, the computer can access all 128K of RAM available to it. The extended RAM banks are switched in and out by modifying some of the bits in a special memory location known as PORTB at address 54017 ($D301). Of the 8 bits available in PORTB, 4 are used for managing the expanded RAM. Two of these are used for selecting which of the 4 extended RAM banks should be switched in, one bit is used to determine whether the 6502 should access main or extended RAM and the remaining bit is used to determine whether ANTIC accesses main or extended RAM. The layout of these bits in PORTB is as follows:
00ACBB00
Where A indicates the bit used to select if ANTIC accesses main or extended RAM, C is the bit used to select if the 6502 accesses main or extended RAM and the 2 bits marked B are used to select which extended RAM bank is to be accessed.
As far as using the extended RAM as a ramdrive is concerned we can ignore the ANTIC select bit and concentrate on the other 3. When the 6502 select bit is set to 1, the 6502 will access main RAM and when it is set to 0 it will access extended RAM when it reads from or writes to any address between 16384 and 32767. By modifying The bank select bits we can choose which of the 4 extended RAM banks will appear in this address space. If both bits are set to 0 then the first extended RAM bank will appear, if the first is set to 0 and the second to 1 then the second RAM bank will appear, and so on. Ramdrive 1.0 comes set up by default to use this method of accessing extended RAM, and hence no work is required on your part to set this up. However, in order to fully explain how the Ramdrive 1.0 commands work and how you can use them to set it up for any other type of extended RAM scheme we shall show how to set Ramdrive up for a standard 130XE. The first command we will explore is BANKS, this is used to tell Ramdrive how many extended RAM banks you have. So for the 130XE you would set BANKS to 4 as follows
BANKS 4
Another use for this command is if you want to divide your extended RAM between Ramdrive 1.0 and another program that uses expanded RAM. If for example you wanted Ramdrive to use 2 banks and your other program to use the remaining 2, then you would set BANKS to 2. In short, BANKS tells Ramdrive how many extended RAM banks it is allowed to use.
The next command we will look at is BANK_SIZE. This command tells Ramdrive how big your extended RAM banks are. This can be set to either 1,2,4,8,16 or 32K banks. In the case of the 130XE, its banks are 16K, so we would issue the command:
BANK_SIZE B_16K
This command also provides another way of sharing your extended RAM between Ramdrive and another program. If for example you wanted Ramdrive to access only the first 8K of your 16K banks and your other program to access the other 8K, you would set BANK_SIZE to 8K, hence leaving the rest of the bank free for your other program.
The BANK_WINDOW command is used to tell Ramdrive where in the memory address space the extended RAM banks will appear. This is done by specifying the address the first byte of extended RAM will appear at. In the 130XE's case this would be 16384 (or $4000 in hex), so you would have:
BANK_WINDOW 16384
Following on from the example presented with the BANK_SIZE command, if you wanted to split your extended RAM between Ramdrive and another program, with Ramdrive accessing the last 8K of your 16K blanks, you would set BANK_SIZE to be 8K as above, and then set BANK_WINDOW to be 24576 ($6000 hex).
In order to tell Ramdrive the address that is used for selecting the extended RAM banks, you would use the BANK_BITS_ADDR command. In the 130XE's case this would be 54017, so you would use
BANK_BITS_ADDR 54017
Other RAM banking schemes may use other addresses for selecting the extended RAM banks, if so this command can be used to customise Ramdrive to those schemes. The only restrictions placed by Ramdrive are that it will only recognise one address to be used for bank switching, and that the address used for selecting which extended bank is to appear (the bits labelled BB in the above description of PORTB on the 130XE) must be the same address used for selecting when the 6502 accesses main RAM and when it accesses extended RAM (the bit labelled C in the PORTB description above). If your expanded RAM banking scheme does not work this way then Ramdrive will either not work with your expanded RAM or if it does, it will not be able to use all of your expanded RAM.
The last command left to explain how Ramdrive accesses extended RAM is the BANK_BITS command. This is used to tell Ramdrive which bits at the bank switching address specified in BANK_BITS_ADDR are used for doing the bank switching. This command has two forms. One that takes 1 parameter, and one that takes 3. The 1 parameter version of the command is used when your extended RAM scheme is one that Ramdrive already knows about. These include the standard 130XE scheme, and those used by the most common 64K, 256K, 512K and 1024K XE expansions, as well as the 8K BASIC ramdrive mode, which uses the 8K of RAM under the BASIC ROM. For the 130XE you would use
BANK_BITS XE_64K
If on the other hand your expansion is not covered by one of the above, the BANK_BITS command has another mode that takes 3 parameters which can be used to specify which bits are actually used for bank switching. The first of these three parameters tells Ramdrive which bits are used to select the extended RAM banks. The bits which are used should be set to 1 in this parameter. So for the 130XE, this would be (in binary) %00001100. One word of caution is that the number of bits used to select banks specified here should be able to cover the number of banks that you have told Ramdrive you have with the BANKS command. So if you have told Ramdrive to use 4 banks, then you need to tell Ramdrive to use 2 bits to select the correct bank. If you have told Ramdrive to use between 5 and 8 banks inclusive, you would need to specify 3 bits for bank selecting here, and so on. The second parameter tells Ramdrive which bits need to be set in order to allow the 6502 to access the extended RAM banks. For each bit set in this second parameter, the corresponding bit will be set at the bank switch address. In the 130XE, extended RAM is enabled for the 6502 by clearing the 4th bit, hence no bits need to be set in this parameter, so for the 130XE this parameter would be %00000000. The third parameter specifies which bits need to be cleared in order for the 6502 to access extended RAM. A bit set to 1 in this parameter will clear the corresponding bit at the bank switch address. As noted above the 130XE uses the 4th bit to enable the 6502 to access extended RAM so you would set the 4th bit of this parameter to 1. Furthermore the bits used for bank switching (as specified by the first parameter to this command) should also be cleared, hence for the 130XE you would want to clear bits 2 and 3 as well. So the command for the 130XE would be as follows:
BANK_BITS %00001100,0,%00011100
There is no cross checking between the parameters to BANK_BITS, hence if you specify that a bit should both be cleared and set (by specifying it in both the second and third parameters) then the results will be indeterminate. Another note to make is that this command can also be used for sharing extended RAM banks between Ramdrive and other programs, so if you wanted Ramdrive to only access the 4th bank of your 130XE's extended RAM, leaving the other 3 banks for use by your other program then you would set both the bank selecting bits to 1 in parameter 2, leaving parameter 1 as 0 and parameter 3 with just bit 4 set as follows: BANK_BITS 0,%00001100,%00010000 and not forgetting of course to set BANKS to 1. This would tell Ramdrive that by setting bits 2 and 3 and by clearing bit 4, it can access the one bank of extended RAM it is allowed to use. Since in this case you would always want bits 2 and 3 to be set to 1, then you would not specify any bits in parameter 1 to be used for bank switching, otherwise Ramdrive would be free to modify these bits in order to select the correct bank.
The only other command that needs to be looked at in relation with the amount of extended RAM you have available is the DRIVE command. This is the command that actually sets up a Ramdrive. This command also has two modes, one that takes 3 parameters and one that takes 18. In both cases the first parameter is the ramdrive number. Just like real drives have a number (usually 1 through 4), so do ramdrives. A ramdrive's number can be between 0 and 9 inclusive. You should however be careful not to give your ramdrive a number already used by one of your real drives. For example if you set up a ramdrive as drive number 1 then you will not be able to access your real drive if it is also set up as drive 1. The second parameter specifies the first extended RAM bank the ramdrive can use. If you set this parameter to AUTO, then Ramdrive 1.0 will automatically decide which banks to use for your ramdrive.
Ramdrive 1.0 does this by remembering the highest extended bank that has been used so far and then adding one to this number, to get the first bank for your next ramdrive. As an example, if you set up 3 8K ramdrives numbered 4, 5 and 6 as follows on a 130XE:
DRIVE 4,AUTO,SSSD_8K
DRIVE 5,AUTO,SSSD_8K
DRIVE 6,AUTO,SSSD_8K
when Ramdrive 1.0 finds the first DRIVE command and sees the AUTO in the second parameter it will check for the highest extended bank used so far. Since no extended banks have been used up until now, it will use bank 0. Ramdrive 1.0 will then set aside enough banks for the size of the ramdrive you are setting up. In this case it is an 8K ramdrive, so only 1 bank is needed (with each bank being 16K). When Ramdrive 1.0 comes across the second DRIVE command and sees the AUTO in the second parameter it will again check the highest extended bank used so far. Bank 0 was used for ramdrive 4, so ramdrive 5 will start at bank 1, and again since it is an 8K ramdrive it will only use one bank. When the third DRIVE command is found Ramdrive 1.0 will again check for the highest extended bank used so far. In this case it will be bank 1 used by drive 5, so ramdrive 6 will start at bank 2, and as it is an 8K drive will only use one bank. One thing to note here is that only 8K of each bank is being used, leaving half of the 3 extended RAM banks 0, 1 and 2 empty. This is because a ramdrive must start at the beginning of an extended bank, there is no way of specifying that a ramdrive should start at, say, byte 8192 of extended RAM bank 2. The only way of doing this would be to use the BANK_WINDOW command as described above, in which case ALL ramdrives you set up would not use any byte below 8192 on any extended RAM bank, in effect reducing the size of your extended RAM banks to 8K.
This command gives you yet another way of sharing your extended RAM banks between Ramdrive 1.0 and other programs. If for example you wanted Ramdrive 1.0 not to use bank 0, leaving it free for other programs, you could modify the above commands as follows:
DRIVE 4,1,SSSD_8K
DRIVE 5,AUTO,SSSD_8K
DRIVE 6,AUTO,SSSD_8K
This would again set up 3 8K ramdrives numbered 4, 5 and 6. However the first DRIVE command tells Ramdrive 1.0 to set up the ramdrive 4 on bank 1. With it being an 8K ramdrive it will only take up one bank, so when Ramdrive 1.0 comes to the second DRIVE command, it will set up ramdrive 5 starting at bank 2 and then ramdrive 6 starting at bank 3, hence leaving bank 0 free. The exact same thing could have been done with the following commands:
DRIVE 4,1,SSSD_8K
DRIVE 5,2,SSSD_8K
DRIVE 6,3,SSSD_8K
however this would involve extra work for you since you would have to calculate how many banks each ramdrive would need, and then ensure that two ramdrives are not trying to use the same bank. In general it is easier to use the AUTO command in parameter 2 and let Ramdrive 1.0 worry about how many banks are needed for each ramdrive and which banks to allocate to which ramdrive. However if for whatever reason you do need to do this manually then this parameter will allow you to do so. For drives that need more than 1 bank, then the banks are allocated sequentially. So if for example ramdrive 5 was a 32K drive, hence needing 2 banks, then banks 2 and 3 would be allocated to it in the first 2 examples.
Another thing to note is that Ramdrive 1.0 will not allow you to use more banks in your ramdrives than you have told it to use with the BANKS command. So if you have told Ramdrive 1.0 that you have 4 16K banks for it to use, then you can't set up a 90K single sided single density drive (which would need 6 16K banks or at least 96K extended RAM), neither could you set up more than 4 8K ramdrives (since each 8K ramdrive uses one 16K bank, and you only have 4 16K banks). If you do try and exceed the number of banks available then you will get the following error message:
ERROR NOT ENOUGH FREE BANKS
If you see this message and know you have more extended RAM banks available, then increase the value of the parameter to the BANKS command, otherwise you will have to use a smaller (or fewer) ramdrive(s).
The last parameter for the 3 parameter version of the DRIVE command specifies the size and type of ramdrive to set up. Currently the following options are available:
SSSD - single sided, single density, 90K ramdrive (720 sectors of 128 bytes each)
SSED - single sided, enhanced density 130K ramdrive (1040 sectors of 128 bytes each)
SSDD - single sided double density 180K ramdrive (720 sectors of 256 bytes each)
DSDD - double sided double density 360K ramdrive (1440 sectors of 256 bytes each)
SSSD_8K - single sided, single density 8K ramdrive (64 sectors or 128 bytes each), this is the only ramdrive you can use if you're using the 8K RAM under the BASIC ROM in your XL/XE
SSSD_64K - single sided, single density 64K ramdrive (512 sectors of 128 bytes each), this is the same as DOS 2.5's ramdisk.
SSSD_128K - single sided, single density 128K ramdrive (1024 sectors of 128 bytes each)
SSSD_256K - single sided, single density 256K ramdrive (2048 sectors of 128 bytes each)
SSSD_512K - single sided, single density 512K ramdrive (4096 sectors of 128 bytes each)
SSSD_1024K - single sided, single density 1024K ramdrive (8192 sectors of 128 bytes each)
Which type of ramdrive you chose to use will depend on the amount of extended RAM you have, i.e. if you only have 64K extended RAM, then you won't be able to use anything bigger than the SSSD_64K ramdrive. It will also depend on your DOS. Not all DOS's can use all of the above drives. For example with DOS 2.0s you can't use any drive bigger than the SSSD drive (90K), with DOS 2.5 the biggest drive you can use is the SSED (130K) drive. However there is nothing to stop you having more than one ramdrive under these DOS's, (RAM allowing) so for example if you have 256K of extended RAM, you could have 2 90K ramdrives under DOS 2.0s. MyDOS on the other hand can handle drives up to 16 Megabytes in size, so RAM allowing, you could use any of the above ramdrives with it.
If none of the above ramdrives suit your needs, then you can use the 18 parameter version of the DRIVE command to set up your own custom ramdrives. The first 2 parameters are the same as for the 3 parameter version of this command, and have already been described. The remaining 16 parameters and how to use them are now explained.
The third parameter to this version of the command determines how the ramdrive will behave. Only the low 4 bits of this parameter are used at present. If bit 0 is set then the ramdrive will support enhanced density, if it is clear then an error will result if you try to format this drive in enhanced density. If bit 1 is set then it will recognise the SIO read configuration block command, if it is clear then it will not. If bit 2 is set then the configuration block for this ramdrive will be read only, any attempt to write to the configuration block will fail, if it is 0 then the configuration block can be written to. This bit should be set in conjunction with bit 1, if bit 1 is not set then configuration block writes will always fail, regardless of the value in bit 2. If bit 3 is set then sectors 1 to 3 inclusive will be 128 bytes long, even if the disk has been set up as a DD, QD or OD density disk. If this bit is clear then sectors 1 to 3 inclusive will be the same size as the rest of the sectors on the disk. Setting this bit on DD, QD and OD ramdrives will waste space on your ramdrive. Taking the DD example, where sectors are 256 bytes in size, then 256 bytes will be allocated for all the sectors on the disk, including sectors 1-3, however any accesses to sectors 1-3 will only use 128 bytes, hence wasting 128 bytes per sector (384 bytes in total). However this allows for full compatibility with existing programs, since on most Atari drives sectors 1-3 will always be 128 bytes in size, even if the disk has been formatted in double density. By clearing this bit you will not waste any space on DD, QD and OD ramdrives, but it may cause incompatibilities with most existing programs, which will expect these three sectors to be only 128 bytes long.
The fourth parameter to this command was included to allow the 8K ramdrive to work under DOS 2.5 and other DOS's. An 8K ramdrive can have a maximum of 64 128 byte sectors. However DOS 2.0, 2.5 and several other DOS's use sectors 360 to 367 inclusive to store the VTOC and directory information. These sectors are clearly out of the range available on the 8K ramdrive (sectors 1 to 64 inclusive), so if DOS 2.5 tried to read or write its VTOC or any of its directory sectors on the 8K ramdrive it would return an error making the ramdrive unusable. However this parameter allows you to relocate the VTOC and directory sectors to be anywhere on you ramdrive without DOS knowing about it. Hence you could have your VTOC and directory in sectors 1 to 9 inclusive, while DOS would think they are still at sectors 360 to 367. The way this works is if you try to access a sector outside the available sectors on your ramdrive (for example trying to read sector 360 on a 64 sector ramdrive), then the value specified in this parameter will be subtracted from the sector you asked for, and then that sector number (if valid) will be accessed. So if you set this value to 359 on a 64 sector ramdrive, and then tried to access sector 360, Ramdrive 1.0 would detect that sector 360 is outside the range of valid sectors (1 to 64) and subtract 359 from the sector you asked for. In this case this would give you sector 1 (360-359=1), which would then be returned to your program. As described, this feature allows you to use the 8K ramdrive with most DOS's, however it should be used with caution, as under this scheme you will have 2 sector numbers referring to one sector on your ramdrive, i.e. on an 8K ramdrive, with this parameter set to 359, sector 1 can be accessed by requesting either sector 1 or sector 360, which if not used with care could lead to your ramdrive being corrupted. In the 8K ramdrive's case, the provided RAMDRIVE.CFG and RAMDRIVE.CPY files mark sectors 1 to 9 inclusive in the VTOC as being used, hence DOS will not try to use them for any other purpose, furthermore it will also mark all sectors above 64 as used so that these aren't accessed either. In general, if you don't need to use this feature, then leave this parameter as 0.
Parameters 5 through 8 inclusive are the 4 bytes that will be returned when the ramdrive receives an SIO status command, by setting these parameters you can customise the status information of the drive to your own needs. Parameter 5 will be returned as status byte 1, parameter 6 as status byte 2 and so on. Bit 3 in status byte 1 is used as the write protect bit by both ramdrives and real drives. Hence if this bit is set then the drive will be write protected, and if it is clear then it will be unprotected. This bit will be set up automatically whenever the ramdrive is write protected/unprotected, and hence you do not have to worry about it. Also if bit 5 is set then it is a double density ramdrive, and if bit 7 is set it is an enhanced density ramdrive. Again these bits are used in this way by most Atari drives, and are handled automatically by Ramdrive 1.0, hence you do not need to worry about them.
Parameters 9 through 18 make up the ramdrive's configuration block, and will be returned whenever the read configuration block SIO command is received (but see bit 2 in parameter 3 also). These parameters are used to calculate the size of the ramdrive and how much extended memory it needs.
Parameter 9 specifies the number of tracks on the ramdrive. Unlike a real disk, ramdrives do not have tracks as such, however this parameter is used when calculating the size of the ramdrive.
Parameter 10 is the second byte in the configuration block, and is ignored by Ramdrive 1.0. It has been included for compatibility reasons.
Parameter 11 specifies the number of sectors per track for the ramdrive, this parameter is used to calculate the size of the ramdrive.
Parameter 12 specifies the number of sides the ramdrive has. Again ramdrives do not have sides as such, but this is used in calculating the ramdrive's size. A value of 0 specifies a single sided ramdrive, 1 specifies a double sided ramdrive. In theory you could have up to a 256 sided ramdrive, whether such a ramdrive has any practical uses however is another matter.
Parameter 13 specifies the density of the disk. The value stored here is used to set up bit 5 in status byte 1, when the ramdrive is formatted. If this is 0 then the ramdrive will be single density, if it is 4 it will be double density. Other values will produce indeterminate results. This parameter is NOT used to calculate the size of the ramdrive sectors however (parameter 14, below, is used for that instead)
parameter 14 specifies the size of the sectors on the ramdrive. This parameter can take one of 4 values:
SD - single density, 128 byte sectors
DD - double density, 256 byte sectors
QD - quad. density, 512 byte sectors
OD - Oct. density, 1024 byte sectors.
This value is used to calculate the size of the ramdrive. Note, that even though Ramdrive 1.0 supports Quad. (512 bytes) and Oct. (1024 bytes) density sectors, I know of no DOS that supports sectors of this size, hence unless you write your own programs to use sectors of this size, they will not be of much use to you.
Parameters 15 through 18 make up the last 4 bytes of the configuration block and are ignored by Ramdrive 1.0, they have been included for compatibility reasons only.
Ramdrive 1.0 uses the following formula in order to calculate the size of a ramdrive, and hence how much extended memory needs to be allocated to it. The number of sectors per track (parameter 11) is multiplied by the number or tracks on the disk (parameter 9) the result is then multiplied by the number of sides (parameter 12) this results in the number of sectors on the disk. Then this is multiplied by the number of bytes in a sector (parameter 14) to give the size of the ramdrive in bytes. From here the number of banks needed is calculated from the bank size (specified with the BANK_SIZE command) and a check is made see if enough extended banks are available. If so then the drive is allocated.
So for a standard single sided, single density disk, the number of tracks would be 40, the sectors per track would be 18, the number of sides would be 0 (i.e. 1 side) and the number of bytes per sector would be set to SD (128 bytes), resulting int 40*18*1=720 sectors. 720*128=92160 bytes (or 90K). If the extended RAM banks are 16K in size, this would result in 6 banks being allocated to the ramdrive (96K worth), resulting in 6K of unused space on the last extended bank. Unfortunately there is no way of accessing this unused 6K of RAM.
The SIO Commands
Ramdrive 1.0 works by replacing the SIO call at 58457 (SIOV) with a call to the Ramdrive code. In this way Ramdrive can trap all SIO calls before they get passed on to the operating system. This lets Ramdrive check if the SIO call refers to a ramdrive or not. If the call doesn't refer to a ramdrive then the call will be passed on to the OS by calling the address previously stored at SIOV. Since all DOS's and drives work in the same way through the SIO, by installing Ramdrive into the SIOV address we can make a ramdrive appear as a real drive to all programs. This means that most existing programs should be able to work with Ramdrive 1.0, this includes sector editors as well as DOS's. However since Ramdrive 1.0 needs to modify the SIOV vector, which is located in the OS ROMS, it must first copy the ROM area into RAM and then modify the RAM. This is why Ramdrive 1.0 needs to use the 16K of RAM found under the OS ROMs. The drawback of this is that Ramdrive will not work with any other program that also uses this RAM for its own purposes. Amongst the programs that will not work with Ramdrive 1.0 are most versions of SpartaDos, DOS XE and Turbo Basic.
Ramdrive 1.0 works by checking all SIO calls, and if any of these refer to a ramdrive, then the appropriate response will be generated. Ramdrive 1.0 recognises the following SIO commands: Read (82), Write -verify- (87), Put -no verify- (80), Status (83) and Format (33). If bit 0 is set in parameter 3 of the DRIVE command, then the ramdrive will also recognise the Format Enhanced (34) command. If bit 1 is set in parameter 3 of the DRIVE command, then the Read Configuration (78) command will be recognised by the ramdrive, and if bit 2 is clear and bit 1 is set in this parameter then the Write Configuration (79) command will be recognised by the ramdrive in question. These commands all work in the expected way, either returning the requested information from the ramdrive or by writing the information to the ramdrive. The only exception is that there is no difference between the Write with verify and the Put without verify commands, as these are both interpreted as a Put without verify command. Given that the ramdrive is writing to RAM instead of to floppy, the chances of an error are minimal, hence a Write with verify command would only serve to slow the ramdrive down.
In addition to the above commands, Ramdrive 1.0 also provides three new SIO commands which are only recognised by ramdrives. Sending one of these commands to anything other than a ramdrive will result in an error. These new commands are Read Address (65), Read Ramdrive (67) and Write Ramdrive (68). The Read Address SIO command will return 4 bytes, the first two of which will be the address of the drive table (as defined by the DRIVE_TABLE command), in low byte, high byte format, and the 3rd and 4th bytes will be the address of the first byte of the first ramdrive's set-up data. This command has been provided so that your programs can directly access the ramdrive set-up data, if needed. However due to the possibility that you may corrupt the ramdrive set-up data it is probably best to avoid this command and use the next two instead.
The Read Ramdrive command returns 23 bytes of information which describe how the ramdrive has been set up. In fact this is the data that was used to set up the ramdrive with the 18 parameter version of the DRIVE command. The bytes returned are mapped as follows:
byte 1 = ramdrive number. (1st parameter to DRIVE command)
bytes 2 and 3 = total number of sectors on ramdrive, in low byte, high byte order. (used internally)
byte 4 = first bank number used by ramdrive. (2nd parameter to DRIVE command)
byte 5 = compatibility options. (3rd parameter to 18 parameter DRIVE command)
bytes 6 and 7 = number to subtract if sector is out of range, in high byte, low byte order. (4th parameter in 18 parameter DRIVE command)
bytes 8 to 11 = drive status bytes in same order as returned by Status command. (parameters 5-8 to DRIVE command)
bytes 12 to 23 = drive configuration block in same order as returned by Read Configuration command. (parameters 9-18 to DRIVE command)
This command will work even if the Read Configuration command is not recognised by the ramdrive, so always providing you with a way to read the data if needed.
The Write Ramdrive command performs the opposite to the Read ramdrive command, it will take 23 bytes of data and use them to configure a ramdrive. The ramdrive being referred to must already exist, and will be reconfigured with the new set-up. The order and meaning of the bytes is the same as of the Read Ramdrive command. This command will always work, even if the Write Configuration command is not recognised by the ramdrive.
The command values for the above 3 commands, have been selected so as not to conflict with any other SIO commands. However, if for whatever reason these values don't suit your needs, they can be changed with the READ_CMD, WRITE_CMD and ADDR_CMD commands in the RAMDRIVE.CFG file. These commands all take one parameter, and will tell Ramdrive 1.0 to use these values as either the Read Ramdrive, Write Ramdrive or Read Address commands respectively. If you do change these values, then you should be careful that the new values do not conflict with any other SIO commands. There is no checking carried out to ensure that the values specified are unique, and if they do conflict with other SIO commands supported by Ramdrive 1.0 then results will be indeterminate.
The procedure followed by Ramdrive 1.0 to determine whether a command is directed to a ramdrive or not is as follows. Upon receiving the SIO call, Ramdrive 1.0 will check if the value at 768 (DDEVIC) is 49, if not, then the call will be passed on to the OS. If it is 49, then Ramdrive 1.0 will check if this is a Read Address command (65), and if so, will return the appropriate information back to the caller. If not, then it will read in the value found at 769 (DUNIT). If this is not in the range 0 to 9 then the call will be passed onto the OS. If it is between 0 and 9 inclusive, then it will read the value stored at that location in the drive table. Hence, if the drive table is set up as follows:
0,8,2,3,4,5,6,7,1,9
and the value at 769 is 1, then Ramdrive will take the value stored at position 1 in the drive table, which in this case will be 8. Ramdrive will then check to see if this drive (drive 8 in this example) is a ramdrive. If it isn't then the call will be passed onto the OS. If it is, then the command will be handled by Ramdrive 1.0 in the expected way. It is in this way that Ramdrive 1.0 handles the renumbering of both ramdrives and real drives. To further illustrate this point, lets say that you had 2 real drives, numbered D1: and D2:, and that you wanted D2: to answer to all SIO calls directed at D1:, and D1: to answer all SIO calls directed at D2:, leaving all other drives unchanged. To do this you would set up a drive table in Ramdrive 1.0 as follows:
DRIVE_TABLE 0,2,1,3,4,5,6,7,8,9
Then when Ramdrive finds that an SIO call is directed at drive 1, it will look at position 1 in its drive table and find 2. It will then check to see if drive 2 is a ramdrive, and since it isn't, this call will be passed onto the OS as a call to D2:, which will then respond to the SIO call and return to Ramdrive 1.0 when finished. After this happens, Ramdrive 1.0 will restore the original value in 769 back to 1 and return to the calling program. So in effect drive 2 will act as if it were drive 1, and drive 1 as if it were drive 2. All this will happen without having to change the switches at the back of your drive. Since both ramdrives and real drives are handled in the same way, a ramdrive can respond to SIO calls made to D1: for example. This allows you to boot from a ramdrive if you desire. This is also the way the SELECT+number keypress combinations works. By switching the drive table around, when Ramdrive sees one of these keypresses, it allows you to renumber ramdrives and real drives on the fly. The only thing you must be careful about is that the drive number assigned to a ramdrive (as specified in the first parameter to the DRIVE command) does not conflict with the number of one of your real drives. If it does then you will not be able to access your real drive as long as Ramdrive 1.0 is active. If you do need a ramdrive to act as say drive 1 and you real drive 1 to act as say drive 8, then you should give your ramdrive a unique number like 3 (assuming you don't already have a drive 3) and then set up the drive table as described above to make ramdrive 3 respond to SIO calls made to drive 1, and real drive 1 respond to calls to drive 8. The drive table can be set up by using the DRIVE_TABLE command in RAMDRIVE.CFG, or by using SELECT+number keypresses after Ramdrive has been set-up. The OPTION+number keypress also works through the drive table, so pressing say OPTION 4 will write (un)protect the drive currently answering to D4:, which could in fact be any drive on your system. Only ramdrives can be write (un)protected in this way of course.
When using SIO calls to ramdrives, you must set up the values in DSTATS (771) and DBYTLO/HI (776/777) correctly. If the number of bytes specified in DBYTLO/HI is not 4 for the Status or Read Address commands, 12 for the Read or Write Configuration commands, 23 for the Read or Write Ramdrive commands or the sector size for the Read, Write or Put sector commands then Ramdrive 1.0 will return an error 139. If the value in DSTATS is not set to 64 for commands that return data (Read Address, Read Configuration, Read Sector, Status and Format) and 128 for commands that send data (Write Configuration, Write Ramdrive and Write/Put Sector) then an error 139 will occur. If DSTATS is set to any other value (including 0) then an error 139 will occur. This is a slight departure from real drives which accept a value of 0 in DSTATS. The Format commands never return any bad sectors and hence will never return any data, and the values in DBYTLO/HI will be ignored. If a ramdrive receives a command it does not support then an error 139 will occur.
Running Ramdrive 1.0 under other operating systems
Ramdrive 1.0 has been configured to run under the C version of Atari's operating system. This is the OS found in all standard XL's and XE's. If however, you need Ramdrive 1.0 to run under another version of the OS, such as revision B, which was found in most 400 and 800 computers, then you can do so by using the ALT_OS command. The way to do this would be to first install the B OS in you computer by running a translator disk. Then, include the ALT_OS command in your RAMDRIVE.CFG file and finally load Ramdrive 1.0. You should now be able to use Ramdrive 1.0 under the B OS. If you wanted to use Ramdrive 1.0 with another version of the OS, such as with the A version, or with a custom version, then you need to use the second version of the ALT_OS command, which takes five parameters.
The first parameter is the address where the operating system's keyboard interrupt handler code should be changed to call the Ramdrive 1.0's keyboard handler. For the C OS this will be 49293 and for the B OS 59215, or use OS_C or OS_B respectively for this parameter. Users of other operating systems will have to either work out the appropriate address, or use NONE in this parameter. If the latter option is taken then you will not be able to use any of the SELECT+number, OPTION+number, warmstart or coldstart keypresses. The Ramdrive 1.0 key interrupt code assumes that the 6502's X register contains 8, and that the X register's original contents will be on the stack. Here is part of Ramdrive 1.0's key interrupt handling code:
KEYBCD:
TYA
PHA
CPX #8
BEQ TRAPKY
EXITKY:
PLA
TAY
PLA
TAX
JMP (652) ; GO TO KEYBOARD INTERRUPT
TRAPKY:
. ; CONTINUE PROCESSING
.
The C OS's interrupt handler has been changed from:
49281 LDA 512,X
49284 STA 652
49287 LDA 513,X
49290 STA 653
49293 PLA
49294 TAX
49295 JMP (652)
to:
49281 LDA 512,X
49284 STA 652
49287 LDA 513,X
49290 STA 653
49293 JMP KEYBCD
Where KEYBCD is the address of Ramdrive 1.0's key interrupt handling code, as shown above.
The second parameter is the address of the internal to ATASCII translation table. The C OS stores this address at KEYDEF, locations 121 and 122. However to avoid problems that could be caused by a user changing the default table, the table is referenced directly in ROM rather than going through KEYDEF. This means that even if you change the keyboard definition table on your XL/XE, the keypresses used by Ramdrive 1.0 will not change. For the C OS this will value will be 64337 and for the B OS 65278. If you don't fancy remembering these then use OS_C or OS_B respectively for this parameter instead.
The third parameter is the address of the OS's keyclick routine. For the C OS this is 63875 and for the B OS it is 64728. Ramdrive 1.0 will call this routine when any of the SELECT+number or OPTION+number keypresses are used. You can disable the keyclick heard when these keypresses are used by pointing this to an RTS command. You could also change the default keyclick to something else, such as flashing the screen to indicate that the keypress has occurred by writing your own code and then passing its address into this parameter.
The fourth parameter tells Ramdrive 1.0 whether or not it should modify the OS's warmstart handling code, this should only be used with the C OS. When the C OS sees a warmstart, it will run a checksum on its ROM area, and if this doesn't match up with what it expects to see, then it will perform a coldstart. But because the OS has been changed to RAM this code will check the RAM instead, and since this has been modified by Ramdrive 1.0, the checksum will not match up, which will result in a coldstart. In order to avoid this you can set this parameter to OS_C to indicate that you are using the C version of the OS and that you want Ramdrive 1.0 to made the corresponding changes to the OS's warmstart code. The B OS doesn't have this checksum hence no changes need to be made, so set this parameter to NONE. You should only set this to OS_C if you are using the C OS or a slightly modified version of it. One other thing to note is that if you are using the B OS that has been installed with the translator disk in your XL/XE, then pressing the RESET key will always result in a coldstart. This is because as soon as you press RESET the OS ROM is switched back in, and then the original warmstart code will check in RAM 829 - 831 (PUPBT1-3) for specific values. However since you are running the B OS the values in these locations will not be what the C OS expects and hence it will force a coldstart.
The fifth and final parameter to this command can be either COPY or NO_COPY. If it is COPY then the OS will be copied from ROM to RAM by Ramdrive 1.0, if it is NO_COPY then Ramdrive 1.0 will assume you have already installed the appropriate operating system in RAM. If you use NO_COPY then you MUST have already set up an alternate operating system in RAM, otherwise your system will crash.
Reset handling
Because Ramdrive 1.0 uses the RAM under the OS ROM (see above) handling of the RESET key can cause problems. When the RESET key is pressed the OS ROM is automatically switched on, hence disabling Ramdrive 1.0, what's more there is no way of avoiding this through software alone. Because of this 2 ways of handling the RESET key are provided. The first of these is to avoid using it at all. Two new keypresses have been provided to create a warmstart and a coldstart without losing your ramdrives. By pressing the OPTION and HELP keys together a warmstart will be generated, similar to that which occurs when the RESET key is pressed, except that your ramdrives will remain active. By pressing the SELECT and HELP keys together a coldstart will be generated, which is similar to switching your computer off and on again, except that you will not lose your ramdrives. This allows for you to reboot and retain your ramdrives, or even to reboot from your ramdrive (by setting it to D1: and coldstarting). The HELP key pressed along with SELECT or OPTION is the default set-up for both the cold and warmstart keypresses, however this can be changed with the RESET_KEY command in the RAMDRIVE.CFG file.
The second way to overcome this problem is to trap the RESET key. Ramdrive 1.0 allows you to do this with the TRAP_RESET command in the RAMDRIVE.CFG file. By using this command Ramdrive 1.0 will set up a routine that when RESET is pressed will switch the OS ROM back to RAM, hence giving you back your ramdrives. This however will only work with the C OS, as the B OS will force your computer to coldstart (as describe in the previous section). There are a few problems with this approach however. First you must find 9 free bytes of RAM in order to store this routine and these should be below 49152 (C000 hex) as this area will be switched back to ROM. One obvious place is page 6, however since many other programs also use page 6 for their own code this can cause conflicts. Another place is locations 590 to 618 which are unused in the C OS, but again might cause conflicts if other programs use these bytes for their own purpose.
Once you have found some free RAM to store the routine in, you must tell Ramdrive if you want to use the CASINI (locations 2 and 3) or DOSINI (locations 12 and 13) to store the address of the reset handling routine to be called by the OS. DOSINI is used by DOS so it is best to avoid it, leaving you with CASINI. Then you need to tell the OS which vector to use (either CASINI, DOSINI or both). If you are using DOS and your own reset routine then you will probably want to use the BOTH option.
If at any time you do accidentally lose your ramdrives through pressing the RESET key, they you can recover them by running the RAMDON.OBJ file included with Ramdrive 1.0. If on the other hand you want to switch your ramdrives off for whatever reason, then run RAMDOFF.OBJ, switching them back on again is also achieved by running RAMDON.OBJ.
Zero page usage
Ramdrive 1.0 uses locations 48, 49 and 54 in page zero. These locations are defined for use by the SIO routines and hence should not cause problems with any other code. These locations are not saved when the Ramdrive 1.0 code is called, hence any values stored here will be lost.