B-Em VDFS

B-Em VDFS

Introduction

VDFS is an emulator-specific filing system for the BBC Micro that allows access to a subset of the filesystem of the host, i.e. the PC running the emulator. The concept is very similar to the way in which modern virtual machine software such as VirtualBox allows the guest to view parts of the host filesystem as if it were a network drive, though the implementation is rather different.

In use it is very similar to ADFS, because this is the most natural way to map the host filesystem which will be hierarchical, but with a little of NFS. It is not aimed at proving a completely authentic experience and there are no noises, no speed restrictions and no emulation of DFS-specfic rather than generalised filing system behaviour. Where it is most useful is in being able to share files fast between the host and the guest, for example when developing software on the guest where the editor or some other part of the toolchain runs on the host and then the software needs to run on the guest BBC for testing, possibly with one or more toolchain steps on the guest before that.

Implementations

The VDFS concept started life on a BBC emulator running under RiscOS. There are two implementations I am aware of for PC-based emulators: the one I wrote for B-Em, which the rest of this documentation is about, and another one for BeebEm by J.G. Harston.

Enabling and Selecting VDFS

Two things are required to be able to use VDFS in B-Em:

VDFS ROM

The VDFS ROM is supplied as part of B-Em in roms/general/vdfs.rom. This ROM is included in the default machine configurations but if you have configured a custom machine, or have removed it, then you would need to add it. For basic use, there is no requirement for it to occupy any particular slot, though on machines other than the master the slot will determine whether it can become the default filing system at startup or will need to be selected explicitly.

Settings

The setting for VDFS is under the "Disc" menu. When this is ticked, VDFS is enabled:

Choosing the Root Directory

For secutity reasons, VDFS does not allow the whole filsystem on the host to be seen from the guest. Instead one chooses a specific directory on the host that will then become the virtual root directory on the guest. This means the guest (BBC Micro) can see anything in that directory of any sub-directory thereof but not anything above that level.

This VDFS root directory is specified either by setting the environment variable BEM_VDFS_ROOT before starting b-em or by choosing "Choose VDFS Root" from the Disc menu which will then present a file chooser dialogue configured to select a directory rather than a file.

Selection on Startup

When enabled, as above, VDFS is a candidate for selection on startup as the default filing system. Whether this happens depends on the order of the ROMs in the slots and on whether keys are held down during startup. VDFS will be selected when it is either the highest priority filing system selected and no keys are held down, or when the 'S' key is held down.

On the master, the default filing system can be configured as one of the CMOS settings. The syntax is:

*CONFIGURE FILE <n>

where <n> n is the number of the ROM containing the filing system.

Selection via Command or ROM Service Call

If enabled in the settings, VDFS can always be selected with the command:

*VDFS

or by issusing a ROM service call with A=&12 and Y=&11, with &11 being the filing system number normally used by VDFS.

Depending on which priority slot the VDFS ROM is in and the FSCLAIM setting, VDFS may also be selected by commands and service calls that would otherwise select the DFS or ADFS filing systems. This is to enable VDFS to be used with programs which embed either commands or service calls to start these other filing systems without having to patch the programs concerned.

In order to step in in place of another filing system in this way, the VDFS ROM needs to be in a higher priority ROM slot than the filing system concerned so that the VDFS ROM sees the command or service call first.

Assuming this is the case, after executing:

*FSCLAIM ON

VDFS will be selected when any of:

*DFS
*ADFS
*FADFS
*VDFS

are executed or when the ROM service call with A=&12 is issued with Y=&04, Y=&08 or Y=&11, with &04 being the filing system number for DFS and &08 being the filing system number for ADFS. After executing:

*FSCLAIM OFF

VDFS will only be selected with:

*VDFS

or by issusing a ROM service call with A=&12 and Y=&11.

Using VDFS

VDFS from Programs

VDFS implements the complete set of filing system calls including OSGBPB so should work from existing programs like any other filing system, provided the program does not make assumptions about the directory structure.

It is worth noting that, as well as embedding filing system selection commands as noted above, some programs may change their behaviour according to the number of the filing system selected. The BCPL ROM is a case in point which, if it does not recognise the filing system, assumes it only implements the core filing system calls as implemented by the cassette and ROM filing systems. Unfortunately the latest filing system this ROM knows about is DFS and this can make it very slow on more modern filing systems. This could be addressed via *FSCLAIM above as that causes VDFS to report as having the filing system number of the filing system it is standing in for. In that case you would have VDFS stand in for DFS by doing:

*FSCLAIM ON
*DISC

Another solution is to patch the BCPL ROM and a patched version is available in the fstest.zip file attached to this forum post.

VDFS Commands

The following commands are implemented by VDFS:

*BACK
*CAT
*CDIR
*DELETE
*DIR
*EX
*INFO
*RENAME
*RESCAN

All of these have the same meaning as under ADFS except for RESCAN which is VDFS-specific and can be used to force VDFS to re-scan host directories if it has not picked up changes made directly on the host.

The following commands are recognised but do nothing:

*ACCESS
*BACKUP
*COMPACT
*COPY
*DESTROY
*DRIVE
*ENABLE
*FORM
*FREE
*MAP
*MOUNT
*TITLE
*VERIFY
*WIPE

Attribute Mapping

VDFS supplies attributes to programs and displays them in the catalogue in the form used for NFS. In the catalogue display this means those that apply to the current user are in capitals and those that apply to others are in lower case. For example here is a directory set up to look like the system disc for a Music 5000 system:

and here is the same directory display on a Linux host:

The NFS "current user" attributes are taken from the host file permissions that apply to the user running the emulator. The NFS "public" permissions are a composite - if anyone else on the host system is able to perform the action concerned however they get that permission, the NFS public permission is considered to be granted, so in the case of Linux this includes permissions obtained via the group mechanism.

As noted above the *ACCESS command does not do anything on VDFS and neither does the OSFILE call to set file attributes. It is simply not clear how this operation should be translated to work on the host system and would differ between Windows and Linux. If you need to change file permissions you will need to do it on the host.

The Acorn-specific LOAD and EXEC addresses are supported - these are held in .inf files on the host, one for each real file, visible in the image above. These are intended to be compatible with SWH's beeb and Acorn-aware ZIP archivers.

Filename Mapping

Acorn filenames are limited to 10 characters so host filenames longer than this are truncated before being presented to code running on the emulated BBC micro. Also, the set of characters that can be included in Acorn filenames and the set of characters that have special meanings will be different from those on the host. Looking at these two rows of characters:

# $ % & . ? @ ^
? < ; + / # = >

whenever one of the characters in the top row is found in a host filename it is translated to the corresponding one on the bottom row. If the combination of truncation and/or mapping would result in more than one host file appearing to have the same name to the guest this is resolved by adding a ~ character and a numeric suffix, truncating the name further, if necessary, to make room for the suffix. This is modelled after the way Windows deals with multiple long filenames mapping to the same 8.3 filename.

In the reverse direction, VDFS will remember the guest name it gave to each host file, though only while B-Em continues to run, so adding or removing files should not cause the mapping to become unstable. When VDFS sees a new guest name, for example when creating a new file, it performs the mapping in reverse, i.e. any character on the bottom row is translated to the corresponding character on the top row before the file is created on the host.

Internals

VDFS is implemented through co-operation between a service ROM that runs from within the guest BBC micro and a module within the emulator, vdfs.c.

The ROM receives requests from the BBC Micro MOS or user programs via the normal paged ROM service calls and by setting the filing system vectors to point to routines within this ROM when it is selected as the current filing system. As necessary, control is then passed to the emulator module.

In the original RiscOS emulator, the mechanism by which control was transferred was an undocumented 6502 instruction, i.e. the ROM would use this instruction and the 6502 processor emulator would trap to the VDFS emulator module when it went to execute this instruction. In B-Em some effort has been put into make the emulated 6502 behave as close to a real one as possible and that includes executing undocumented insructions as a real CPU would. B-Em therefore takes a slighly different approach and uses a set of four ports in the JIM (1Mhz bus) area starting at &FC5C.

&FC5C - Flags

In version 5 of VDFS, the current master version, this is simply a boolean flag which corresponds to the FSCLAIM setting, i.e. whether VDFS should initialise itself when a command or service call attempts to select ADFS or DFS.

In version 6 of VDFS this will enable individual selection or whether VDFS claims ADFS and/or DFS with bit 7 (&80) meaning claim ADFS and bit 6 (&40) meaning claim DFS

&FC5D - Filing System Number

When VDFS is the current filing system, this is set to the filing system number that caused it to initialise, i.e. if this is not &11, VDFS usual filing system number, this is the number of the filing system VDFS is pretending to be. When VDFS is not the current filing system this is zero.

&FC5E - Command

Stroring a value in this port causes the vdfs.c module to take some action. The values as used for VDFS version 5 are:

Code Action
&00 OSFSC
&01 OSFIND
&02 OSGBPB
&03 OSBPUT
&04 OSBGET
&05 OSARGS
&06 OSFILE
&10 Prepare for *CAT.
&11 Close all open files.
&40 VDFS-specific OSWORD
&D0 *SRLOAD command
&D1 *SRWRITE command
&D2 Execute SWRAM <> filing system OSWWORD.
&D3 *SRSAVE
&D4 *SRREAD
&D5 *BACK
&D6 *DIR
&D7 *LIB
&D8 *RESCAN
&FD Check for sideways RAM in specified bank.
&FE Check if VDFS is enabled.
&FF *QUIT - Request emulator to exit.

In VDFS 6 this changes to:

Code Action
&00 ROM Service
&01 OSFILE
&02 OSARGS
&03 OSBGET
&04 OSBPUT
&05 OSGBPB
&06 OSFIND
&07 OSFSC
&08 Get details of next file in catalogue./td>
&09 Check for sideways RAM in specified bank.

There are fewer command codes for VDFS 6 because the new code for ROM sevice call means more functions are implemented in the vdfs.c module and less in the ROM. In particular OS command parsing is now in vdfs.c so there is no need for a separate command code for each command.

VDFS version 6 also adds a mechanism to transfer control in the other direction. Normally, when the command port is written to the corresponding action is carried out and the emulated 6502 continues from the next instruction. With VDFS 6 the vdfs.c module may instead set the PC for the emulated CPU to some other address within the ROM to continue execution from there and to do so uses a table of addresses wthin the ROM. The first three bytes of the VDFS ROM, where the language entry would be if it were a language ROM, describe this table with the first byte at &8000 being the number of enties and thd next two at &8001 and &8002 pointing to the first entry. At the time of writing the correspondance between internal vdfs.c action codes, table entries and the associated assenmbler routine in the ROM are as follows:

Code in vdfs.c Number Assembler Label Desription
VDFS_ROM_RETURN &00 serv_done Simply return (execute RTS)
VDFS_ROM_FSSTART &01 fsstart Start VDFS when selected by command or ROM service call
VDFS_ROM_FSBOOT &02 fsboot Start VDFS when selected at system startup. *EXEC a !BOOT file if found.
VDFS_ROM_FSINFO &03 fs_info Provide filing system info to the OS on the master.
VDFS_ROM_FSCLAIM &04 fs_claim Print a message saying which filing systems are claimed.
VDFS_ROM_CAT &05 dir_cat Execute *CAT.
VDFS_ROM_EX &06 dir_ex Execute *EX
VDFS_ROM_INFO &07 pr_all Execute *INFO
VDFS_ROM_DUMP &08 cmd_dump Execute *DUMP
VDFS_ROM_LIST &09 cmd_list Execute *LIST
VDFS_ROM_PRINT &0A cmd_print Execute *PRINT
VDFS_ROM_TYPE &0B cmd_type Execute *PRiNT
VDFS_ROM_ROMS &0C cmd_roms Execute *ROMS
VDFS_ROM_HELP_SHORT &0D help_short Give short help, i.e. with no help key specified.
VDFS_ROM_HELP_ALL &0E help_all Give long help, i.e. a single '.' specified.
VDFS_ROM_HELP_VDFS &0F help_vdfs Give help when VDFS specified as help key.
VDFS_ROM_HELP_UTILS &10 help_utils Give help when UTILS specified as help key.
VDFS_ROM_HELP_SRAM &11 help_sram Give help when SRAM specified as help key.
VDFS_ROM_TUBE_EXEC &12 tube_exec Start execution in the tube processor for *RUN etc.
VDFS_ROM_TUBE_INIT &13 tube_init Initialise tube - ROM service call &FE
VDFS_ROM_TUBE_EXPL &14 tube_explode Explode character set for tube - ROM service call &FF

&FC5F - Save A

Unlike the scheme that used an undocumented instruction, writing to a port means one of the emulated processor's register has to be loaded with the value to write but some commands may need to pass values in all three 6502 registers to the routine in vdfs.c

This port solves the problem by allowing the accumulator (A) to be written here, then loaded with the command code. As soon as the command code is written to &FC5E above the vdfs.c module puts the value that was written to this port back into A before dispatching to the routine that implements the command code concerned. This means a typical invocation of an action in vdfs.c looks like this in 6502 assembler:

sta     port_a   ; &FC5F
lda     #&01
sta     port_cmd ; &FC5E
rts