The OZMON Manual CONTENTS P1 Ch.1 Installing OZMON. Format of commands and parameters. P5 Ch.2 Detailed information on each command. P14 Ch.3 Details on using the various I/O streams. P20 Ch.4 Entry points to OZMON routines. OZMON memory map. P22 OZMON error message list. (C)1984 G.J.Armitage 8 Menzies Pde Lalor 3075 1 Chapter 1 Introduction to OZMON Before using OZMON it must have been fitted to your BBC computer either by yourself or someone who knows what they are doing. OZMON is stored on an Erasable Programmable Read Only Memory chip (EPROM). This means that it is present whenever the computer is turned on and does not need to be loaded from disc or tape. The chip itself is fairly fragile so handle it with care when inserting it into the computer. Installing OZMON The OZMON chip may be plugged into any of the spare "Sideways ROM" sockets inside the computer. If you are using one of those 'multi-mode' sideways ROM extension board then ensure the socket you put OZMON into is configured for a 2764 type EPROM. The following details are for those not using external ROM boards. To get inside the computer first remove the four FIX screws, there are two at the back and two under the keyboard at the front. Remove the computers cover and place it somwhere safe (Not where someone could sit on it!). You now have to remove the circuit board containing the keyboard to enable access to the ROM sockets. It is held in place by two small screws on the left and right ends of the board. Before unscrewing the keyboard assembly carefully unplug the cable connecting it to the main PCB, this plug and socket arrangment may require some wiggling to loosen it. Now unscrew the keyboard and lift it away from the case. Then unplug the loudspeaker cable from the main PCB and place the entire keyboard assembly in a safe place. In the bottom right corner of the main PCB is the sideways ROM area. If you have a machine fitted with only DFS and BASIC (or NFS and BASIC) you will probably have a ROM already fitted in the socket on the extreme right. This is ROM socket 15 and is usually reserved for the main filing system. BASIC is allocated the lowest priority socket, socket 12, and it is 3 sockets to the left of socket 15. Note that there are in fact two ROMs on the left, the extreme left one is the BBC MOS chip and is not a sideways ROM. OZMON must occupy a lower numbered socket than BASIC. Since OZMON is a language ROM the MOS would use it as the main language after RESET or CNTRL-BREAK, instead of BASIC, if it was placed in a higher numbered ROM socket. Its position relative to any filing system ROMs is irrelevant. For most people this means BASIC must be shifted UP from socket 12 and OZMON put in its place. Be very careful how you handle the chip when putting it in the socket. Usually EPROMs come with their pins 3mm wider than the holes on the sockets for some strange reason, so use either an I.C. insertion tool or some very delicate bending and pressing to get the pins in. 2 Getting OZMON going OZMON does not allow access to its functions from BASIC through '*' commands, like some other utility ROM's, because this would require the OZMON ROM to take some private workspace from BASIC above the area taken by the filing systems. Instead OZMON has been designed to take up absolutely no memory when not in use, and even when in use it only uses part of the memory reserved by Acorn for languages (Pages 6 and 7 and Zero page locations 0 to &2F). Therefore its buffers and workspace are unlikely to conflict with user machine code requirements. OZMON is entered, like a language, with: *OZMON Once OZMON has been entered a soft BREAK will merely reboot it, a hard BREAK is required to return to BASIC (or execute *BASIC). The OZMON prompt changes depending on the currently active filing system. If you are using DFS then the currently selected drive and directory are shown: >*OZMON OZMON :0.$) or :2.B) etc. If you are not using DFS then the prompt is merely a bracket: >*OZMON OZMON ) Try the following commands to test this out: >*OZMON OZMON :0.$)*TAPE )*DISC :0.$)*ROM )*DISC :0.$)*DIR B :0.B)*DRIVE 2 :2.B)*BASIC BASIC > 3 OZMON responds to two types of service calls through the service entry point at &8003, A=4 (Unrecognised command) and A=9 (The *HELP extension). *HELP OZMON produces a brief list of the OZMON commands and the format of data required. OZMON commands are all single letter stems, somtimes followed by an extra letter to change options, and always followed by some data. Data may be either string or numeric, with variations as to how the data is entered in either mode. String data may either be in inverted comma's (e.g. "string") or a string of characters at a predefined address terminated by a CHR$13 (e.g. $&9C0 , etc). Numeric data may be expressed in hex (preceded by a "&"), in binary (preceded by a "%"), and in decimal. Very simple arithmetic is possible, you may add or subtract two numeric values to provide the final value the command is to use.Three errors may be generated with respect to the parameters:'Bad parameter', 'Bad Binary', and 'Bad Hex'. The functions "?" and "!" provide single and double byte peeks respectively. Some examples should clarify the situation. The 'N' command takes a single numeric argument and prints it in decimal: N &FF Would print "255" N &190 Would print "400" N %110 Would print "6" N %1001 Would print "9" N %111001 Would print "57" N &90-23 Would print "121" N %11+&9F Would print "162" N &E00-90 Would print "3494" N ?&C255 Would print PEEK &C255 N !&20E Would print the two byte value at &20E and &20F OZMON also provides seventy 'variables' numbered @0 through to @69. These variables may be used whenever numeric data is called for, thus: N @2 Would print the value in @2 N @30-&20 Would print the value in @30 minus &20 In commands requiring more than one argument the data must be separated by a "/". A space may also be used when separating numeric data but when numeric data follows a string then a "/" is essential. Using the 'V' command the following would occur: )V 65/" Ozmon "/66/10/13 A Ozmon B )V 70/32/48/10/13 F 0 )V 70 32 48 10 13 F 0 )V 65 " string "/66 10 13 A string B )V 65 " string " 66/10 13 A string ) 4 Notice that in the last command the numeric following the string was ignored, but the numerics following the next valid seperator were interpreted correctly (The CHR$10 and CHR$13). In the *HELP OZMON list lower case letters indicate numeric arguments are required, "---" indicates that numeric or string arguments are allowed as determined by the particular command. Multiple statement lines are allowed, each command must be seperated by a colon (":"). Thus the following is valid: )V "This is &E00 in decimal:":N&E00 This is &E00 in decimal:3584 ) Memory:which one is it ? OZMON has a very flexible method of memory accessing, allowing you to switch between RAM editing, to FILE editing, to Disc SECTOR editing on DFS systems, all using the same commands. Accessing Sideways ROMs is also made simple, the 'R' command is used to enable transparent access to any Sideways ROM during disassembly or memory dumps, etc. Thus it is very simple to investigate the workings of other ROMs. The transparent access also allows you to jump directly to subroutines in other ROMs (see the 'G' command). The virtual memory feature of OZMON is controlled by the 'I' and 'O' commands and is discussed in detail in chapter 3. Brief Memory Map &0000 -> &001F:General zero page workspace and command scratch pads. &0020 -> &002F:IO scratch pads, mainly for FILE or DISC accesses. &0600 -> &0630:String buffer or general workspace. &0631 -> &06FF:Reserved for pointers and labels. &0700 -> &077F:Key board buffer. &0780 -> &07FF:Reserved for vectors, do not use at all. 5 Chapter 2 OZMON commands. Short list of commands: A : Enter single pass assembler L : List machine code (Disassemble) D : ASCII and hex dump V : Send strings and bytes direct to VDU drivers R : Select ROM to be 'paged in' for all memory accesses M : Move block of memory C : Compare two blocks of memory S : Search block of memory for match F : Fill block of memory with source string H : Convert data to hex N : Convert data to decimal B : Convert data to binary ? : Single byte immediate poke command @n: Assign value to variable 'n' P : Set status bytes for OZMON functions I : Redirect input stream for memory reads O : Redirect output stream for memory writes G : Call machine code routine (Single step or full speed) E : Enter screen editor mode 6 ASSEMBLE mode A sss This command puts OZMON into the single pass assembler at address 'sss'. In this mode OZMON prompts you with an address and the current value at that location.The machine code is entered one mnemonic per line, each command is immediatly assembled and poked into memory. Labels may be used, simply entering the label identifier (@2, @12, @n ,etc) will assign to it the address of the location currently being edited. Exiting this mode is achieved by starting a line with a ".". For example: )A&900 0900:00 > lda#65 0902:00 > ldx#20 0904:00 > @2 0904:00 > jsr&FFEE 0907:00 > dex 0908:00 > bpl @2 090A:00 > rts 090B:00 > . ) Notice that the single pass assembler overrides the use of the labels as numeric data. It is important to note that if you have enabled different memory streams (Chapter 3) for reads and writes then the prompt may be misleading, it will have read the 'data currently at that location' byte from a different stream. Apart from standard mnemonics three other commands are accepted: 'EQU', 'ORG', and 'PUT'. 'EQU' takes a string of parameters (like 'F' and 'S' commands) and pokes them into memory starting at the address prompted. For example: )F &900/15/0 )A &900 0900:00 > EQU "Hello"/13/"BBC"/13/255 090B:00 > . )D &900/15 0900:48 65 6C 6C 6F 00 42 42 Hello.BB 0908:43 0D FF 00 00 00 00 00 C....... ) 'ORG nnn' sets the prompt address to 'nnn' whereas 'PUT nnn' sets the secondary address pointer to 'nnn' (this has no visible effect in single-pass mode). If you refer to the routine OZASSEM in chapter 4, 'ORG nnn' sets &7,8 and &9,A to 'nnn' whereas 'PUT nnn' sets only &9,A to 'nnn'. ERRORS: The single pass mode generates 'Invalid label' and three messages that do not cause a drop back to command mode. These are: Bad mnemonic : The three character stem is not a valid mnemonic. Bad addressing mode : Incorrect addressing mode for the given stem. Branch out of range : A branch instruction is trying to go more than 128 bytes. 7 DISASSEMBLER L sss/lll/ The Machine code List command disassembles the block from 'sss' of length 'lll'. The optional argument 'rrr' is the relocation address. If provided then all relative branches will be adjusted. Note that this does not relocate absolute addresses, it is only provided to allow easier disassembly of code on files or code not stored at its correct execution address. When relocating the disassembler prints the relocated address followed by the physical address before each mnemonic.The disassembler has various options associated with the format of its output. These are controlled by status byte 3 (set with P3/n). The default format is : with a blank line after all RTS, RTI, and JSR instructions and all mnemonics in lower case. The options are: Bit 0:Set to suppress after mnemonics. Bit 1:Set to suppress ":". Bit 2:Set to supress blank lines after RTS, RTI and JSR. Bit 6:Reset-lower case , Set-upper case mnemonics. ERRORS:None. DUMP memory D sss/lll/ Dump block of memory starting at 'sss' of length 'lll' to the screen in standard hex and ASCII format. The optional parameter 'ww' sets the width of each line of the dump in bytes. This is to enable very wide dumps to printers, etc. The default is 8 bytes per line. The dump format is :< bytes in hex > < bytes in ASCII > The characters printed in the < bytes in ASCII > field are affected by the setting of status byte 2 (P2/n). Each byte is ANDed with 'n' before being printed, this enables dumps to printers that react badly to bit 7 being set. (Usually 'n' will be 255 or 127). Status byte 2 also acts on the < ASCII > field during disassembly in the same way.The parameter causes the ASCII field to be suppressed and the parameter causes the Hex field to be suppressed: DH sss/lll/ww Hex dump only. DA sss/lll/ww ASCII dump only. ERRORS:None. 8 Extended VDU command V ---/---/-- etc The 'V' command enables you to send any sequence of bytes to the VDU drivers. The source string may include data in any valid OZMON format, i.e string constants may be mixed with numeric constants and variables. The only limit on the number bytes sent is the size of the keyboard buffer. Some examples of this command were given in chapter 1. Note that the numeric constants could have been entered in hex or binary as well. ERRORS:None. Select Paged ROM R ii/ This command controls the transparent access to sideways ROM's by OZMON. Whenever memory accesses take place in the region &8000 to &BFFF OZMON will read or write to the ROM socket selected by the most recent 'R' command. When R ii is executed the value 'ii' is used to identify the new 'currently selected ROM'. OZMON checks to see if there is a valid ROM present in that socket and signals an error if not. If a valid ROM is present its title and I.D. byte will be printed. If ii>15 then the names and socket numbers of all active ROMs will be printed out. If the optional parameter 'oo' is provided then OZMON will READ from socket 'ii' but all memory WRITES will go to socket 'oo'. No check is made on socket 'oo' for a valid ROM because it will usually be Sideways RAM. If ii>15 then 'oo' must not be provided. If 'ii' points to an empty ROM socket ( i.e A socket that the MOS has marked as empty ) then 'oo' will be ignored, the error message will appear, and both reads and writes will go to socket 'ii' ERRORS: No valid ROM present. 9 MOVE block of memory M fff/ttt/lll The block move command reads the block starting at 'fff' through the current input stream and transfers it to the block at 'ttt' through the output stream. The block is of length 'lll'. With the default streams (Processor RAM) this command is just a standard block move but it can also be used to transfer data (albeit slowly) between different devices. When the IO streams are data files this command can move data from one file to another (since the IN and OUT streams may refer to different files). The MOVE command has been specially designed to intelligently deal with situations where the destination block partly overwrites the original block. It will move data either Top->Down or Bottom->Up in order to avoid data corruption. If three numeric parameters are not provided an error will be signalled. ERRORS: Not enough parameters. COMPARE two blocks of memory C fff/ttt/lll This command compares two blocks of length 'lll', one at 'fff' the other at 'ttt'. When it detects a mismatch it prints the address of the mismatched bytes in both blocks. The optional 'S' causes the function to stop at the first mismatch. If three numeric parameters are not provided an error will be signalled. ERRORS: Not enough parameters. Memory SEARCH S sss/lll/---/---/-- The 'S'earch command provides a flexible search function. It may be set to search for any string and/or sequence of bytes up to 48 characters long. It searches the block of length 'lll' starting at 'sss' for a matching sequence of bytes to the source string provided and prints the address of each match found. The optional 'S' causes the function to stop after the first match. Some examples will serve to illustrate the different formats the source string may take: S &C000/&4000/"BBC Computer" will search for the string "BBC Computer" (N.B. This string does not end in CHR$13). S &1900/&2EF/0/"OSCLI"/13 will search for the string CHR$0+"OSCLI"+CHR$13 S &E00/&4F0/&EF/%101/13 will search for the string CHR$&EF+CHR$5+CHR$13 (Note the ability to use different numeric formats.) ERRORS: Too many parameters. Not enough parameters. 10 Memory FILL command F sss/lll/---/---/-- etc 'F'ill allows the user to fill a specified block of memory with multiple copies of any specified sequence of bytes up to 48 bytes long. The format of the source string is identical to that for the 'S' command. For example: F &7C00/&400/"Mode7" will fill a mode 7 screen with the text "Mode7" F &E00/&1000/0/1/2/3 will fill the block from &E00 to &1E00 with copies of the sequence CHR$0+CHR$1+CHR$2+CHR$3. The fill command is in fact slightly more complexed than this. It has some extra facilities controlled by status flag 0 (Set with P0/n). Depending on the value of this status flag the bytes in the string will be POKEd, ANDed, ORed, or EORed into the destination block. The values and their effects are as follows: P0/0 : POKE directly P0/1 : AND with byte already there P0/2 : OR with byte already there P0/3 : EOR with byte already there Specifically the byte at the address to be filled is read from the current input stream, status byte 0 is checked and acted upon, and the resulting byte is poked into the location through the output stream. Because of this when you have different IN and OUT streams activated only the 'POKE directly' mode will work correctly. The use of functions other than direct poke may not seem immediatly useful but it can be of use when altering data tables. If, for example, you wanted to reset Bit 7 of every fourth byte the following commands would be used: )P0/1 )F&2F00/&100/255/255/255/127 )P0/0 Bytes 1, 2, and 3 are unaffected whereas the fourth byte in the sequence has its top bit reset, just what we wanted. The reverse of this is to set bits. Assume for some reason the first bytes must now have Bit 6 and Bit 0 set you would do: )P0/2 )F&2F00/&100/%100001/0/0/0 )P0/0 ERRORS: Too many parameters. Not enough parameters. 11 Hex, Decimal, and Binary conversion N nn or N "n" Takes parameter and prints it in decimal. If it is a string then the ASCII code of the first character is printed. H nn or H "n" Takes parameter and prints it in hexadecimal (MSB->LSB). B nn or B "n" Takes parameter and prints it in 16 bit binary (MSB -> LSB). Single byte pokes ?nn/dd This command sends a single byte 'dd' through the output stream to address 'nn'. Assigning values to labels @n/dd The command '@' sets label 'n' to hold the value 'dd'. Error 'Invalid label' if 'n' doesn't have a value from 0 to 69. Setting status bytes P ss/ff Most OZMON commands have some aspect of their operation controlled by status bytes. These are set and altered with 'P' which sets flag 'ss' to value 'ff' where 'ff' is any numeric value. Here is a run down of the status bytes and the commands they affect: P0/n Memory FILL command P1/n 'G' (CALL) and 'GS' (Single Step) commands P2/n All ASCII fields (DUMP,LIST,etc) P3/n Disassembler P4/n Disc sector stream handler If ss > 7 then the current values of all the status bytes will be printed out in hex and binary. A hex dump of OZMON's I/O variables (&6E0 to &6EF) is also printed out. ERRORS:None. 12 CALLing routines and executing in Single Step Mode G sss/// The primary function of this command is to CALL a machine code routine starting at 'sss'. The extra parameters are optional and set the A, Y, and X registers on entry to the routine. If they are not provided the registers are set to zero. On exit from the routine the processor registers values will be printed out if Bit 0 of status byte 1 is set. In keeping with the transparent memory accessing of sideways ROM's the 'G' command will switch in the currently selected ROM before jumping to 'sss', which may actually point into the ROM itself. There is no need to jump into other ROM's via RAM based routines, OZMON does it for you. On entry of another ROM the system variable at &F4 is set to that ROM's socket number. ( If seperate Read and Write sockets have been activated then 'G' jumps into the READ or 'ii' ROM, see the R command for explanation ). In addition to normal execution of routines the 'G' command also has a Single Step Execution mode. The optional character 'S' after the 'G' sets OZMON into single step mode. In step mode each command is disassembled, printed onto the screen, executed, and the resulting register contents displayed. OZMON then waits for the space bar to be pressed before going onto the next instruction. The disassembly format is identical to the normal disassembly function and all status bytes relevant to the disassembler will affect output in this mode as well (e.g. suppressing data or addresses, etc). Various Step Mode options are set by status byte 1 (P1/n): Bit1 : SET:Execute all JSR's full speed,RESET:Execute in single step mode. Bit2 : Same as Bit1 but only for JSR&FF00 to &FFFF (The OS routines). This bit is ignored if Bit1 is set. Bit3 : SET:Print registers after each instruction,RESET:suppress registers. Bit5 : SET:Wait for space bar between instructions,RESET:Don't wait. ERRORS: Not enough parameters. Stack error. Illegal Op-code. Finished. 13 Screen Editor E ssss The screen editor clears the screen and then prints an ASCII/HEX dump of memory from 'ssss' to 'ssss'+127. A cursor then appears in the top left corner of the HEX field. You are now able to enter new data into memory by typing the appropriate Hex-digits on the key board. As you alter the HEX field the ASCII field will also change. The cursor will move 'forward' one nibble after every hex digit is entered but you may also move the cursor, without altering data, with the grey arrow keys. The cursor wraps around from one line to the next and from top to bottom. Alternatively you may enter data directly into the ASCII field. Pressing and the '@' key simultaneously toggles the cursor between the HEX and the ASCII fields. The cursor now moves forward one character at a time. The 'delete' key has the same function as the left-arrow. As you alter the ASCII field the HEX field also changes. The 'escape' key is used to exit the screen editor. Since this editor is designed to operate with the slow FILES and Disc sector streams as well as RAM it cannot continually update every byte in the ASCII/HEX dump on the screen. Thus it only updates every byte whenever the cursor passes over it. This means that the display will be static even when you are editing sections of memory you know to contain constantly changing interrupt driven timers, etc (e.g. MOS workspace). The operation of the IO2 stream also produces some odd results with this editor. Suppose you were editing a file shorter than 128 bytes long or the 'E' commands 128 byte window extends outside the files size. When the screen is first set up all bytes outside the file are set to &FE. If you were to now poke a byte outside the files old size the file would be extended and padded with zeros up to its new length. However, because the editor doesn't constantly update the screen, the &FEs between the files old end and its new end are still there. They will only change to &00 as the cursor moves across them, as mentioned above, so don't panic. ERRORS: I/O streams not the same. 14 Chapter 3 Using the IN and OUT streams All OZMON commands that read or write (or both) to memory locations do so through two 'ports', the input stream and the output stream. The default stream for input and output is the processor RAM, so for all intents and purposes all commands work just like in any other Monitor/Editor. But OZMON's editing abilities can be further expanded by installing your own input and output streams to other 'devices'. Redirecting these streams is achieved with the 'I' and 'O' commands. OZMON already incorporates routines to handle two more different streams, Random access files and Disc Sectors. The 'I' and 'O' commands can also redirect all IO stream calls to a user supplied routine. The most obviously useful stream is the FILES stream. It is possible to OPEN files for reading and/or writing to, and thus perform all editing, memory dumps, disassemblies, etc, direct to and from disc or Network without having to load the program into RAM. This is especially useful when dealing with large programs or when you already have other data in RAM. The 'I' can switch between four different streams as follows: I0 Read from processor RAM (default). I1 Read from I/O processor RAM. I2/"---" Open file "---" for reading (OPENIN). I3/uuu Redirect input stream calls to user routine at 'uuu'. I4/bb/t/d Initialise sector reads on drive 'd', track 't'. The 'O' command is identical except that O2/"---" will OPENUP a file if it already exists or OPENOUT if it doesn't. The input stream can be set independently of the output stream allowing, for example, transfer of portions of disc sectors into memory or back again, etc. Working from the Second processor When a Second processor has been fitted and switched on OZMON has to execute in 2nd processor RAM. When OZMON is operating like this the I0 and O0 streams only access 2nd processor memory. For this reason the I1 and O1 streams are provided to peek and poke I/O processor RAM. One consequence of this is that transparent acces of Sideways ROM's is not possible. Since the I and O streams are separate it is easy to transfer memory across the TUBE linking the two processors. I1 and O1 use OSWORD calls 5 and 6. 15 Using the FILE stream The I2/"--" and O2/"--" commands will only open files on the current filing system. It is essential that the filing system supports Random Access files, so using cassettes is impractical. This is because all OZMON commands expect the filing system to treat the 'address' of the byte being PEEKed (BGETed) or POKEd (BPUTted) as the pointer to the bytes position in the file (and this 'address' can change quite a bit). A short program will serve to illustrate: )I2/"dummy" )H ?90:H ?2905 )I2/"" This is equivalent to X%=OPENIN"dummy" PTR#X%=90:PRINT ~(BGET#X%) PTR#X%=2905:PRINT ~(BGET#X%) CLOSE#X% If this was done on a cassette system the two 'H' commands would have read the first two bytes of the file, ignoring the addresses supplied. An obvious use of the FILE accessing facility is to transfer portions of files in and out of memory. For example: )O0:I2/"FILE" )M 20/&3000/30 )I2/"" This would OPENIN the file "FILE" and take 30 bytes from position 20 in the file onwards and put them into memory from &3000 onwards. If "FILE" was ,say , only 39 bytes long then we are obviously asking for more bytes than are there so the error "File Read Only" will be signalled after 19 bytes have been moved into memory. The reverse process would be as follows: )I0:O2/"FILE" )M &3000/20/30 )O2/"" This would OPENOUT the file "FILE" (or OPENUP if it already existed) and transfer 30 bytes from &3000 onto the file starting at position 20. If the file is shorter than 50 bytes long then it will be extended every time we poke a value at a position outside its current size. When you are finished with a file you must close it with I2/"" or O2/"" , whichever is appropriate. This is to tell OZMON you are finished and to allow the filing system to update the media. The following commands will cause the error "I/O file already open" because OZMON was not properly informed to close them: )O2/"oldfile" )O0 )O2/"newfile" or )I2/"oldfile" )I0 )I2/"newfile" If you use I2/"---" and "---" does not exist then the error "File could not be opened" will be signalled. 16 So far we have assumed that peeks and pokes are only going to occur to different files. For direct file editing it is essential that the file be opened for reading AND writing (I2 is only read and O2 is only write). This is achieved by the command: IO2/"----" (Not OI2/"----" !) This command will not create a file, if it does not already exist it will signal an error like I2 does. What it does is to OPENUP the file and signal OZMON that all peeks and pokes are to work on the same file. When this command has been invoked it is possible to use the 'E'dit command to alter the file directly. Files opened for peek and poke are closed with I2/"" or O2/"". There is one problem unique to IO2 files that must be mentioned. Any attempt to read a byte from outside the file would not normally result in an error message. The file would be extended, by the FS, up to the address requested (the new space being filled with 0) before the value &FE is returned. While doing memory dumps of an IO2 file it is virtually guaranteed that you will accidently try to peek outside the files current size. To avoid corrupting the length of sensitive files in this way OZMON checks all addresses sent to IO2 files and if they are outside the file it will return &FE, preventing the new address from reaching the filing systems BGET routine. This range checking also occurs with I2 file to avoid annoying "file read only" errors from stopping a printout. ERRORS: Input file already open. Output file already open. Bad I/O filename. File cannot be opened. 17 Installing your own I/O devices In addition to FILE and DISC Sector editing you may, at some stage, wish to access some other form of data storage media. With the I3 and O3 commands it is possible to write your own driver software and link it into OZMON's commands. Possible uses could be remote editing of machines across a network, or editing of non-standard discs, etc. Your routines must conform to the following format: I3/iii On entry at 'iii' A is undefined. X will point to two zero page locations which hold the address of the byte to be read. On exit A holds the byte read, X and Y must be preserved. O3/ooo On entry at 'ooo' A contains the byte being poked, X again points to two zero page locations containing the bytes destination address. On exit A, X, and Y must be preserved. There is no time limit on how long your routine takes although very slow I/O drivers make for tedious ASCII dumps. Memory locations &20 to &2D are available for use by your routines as scratchpads. Note that these locations will definately be corrupted when other I/O streams are in use (FILE or DISC, etc). To give you some idea of what is going on try redirecting all pokes to the VDU stream with O3/&FFEE and then do some poke operations. The results would look something like this: )O3/&FFEE )?0/65 A)?&2000/&42 B)F 0/0/"Hello" Hello)F &C000/5/"7" 77777) )O0 Since &FFEE is the 'print character in A' routine every byte that OZMON thought it was poking was in fact being printed. A similar demonstration can be achieved with peeks by entering I3/&FFE0 and then trying an ASCII dump. This will cause OZMON to 'peek' from the keyboard buffer instead of memory. Notice that in both of these trivial examples the address supplied is ignored, it is assumed that your routines make appropriate use of the address data. 18 Disc Sector Editing OZMON provides the DFS user with access to discs at the sector level with the I4 and O4 commands. The idea is that the normal editor commands can edit disc sectors by treating them like any other memory location. OZMON needs to be given some buffer space when editing sectors. I4 and O4 each require a 256 byte buffer which may be in any page from &400 onwards. Since &600 and &700 are used by OZMON it would be convenient to use &400 for the I4 buffer and &500 for the O4 buffer. OZMON only stores the high byte of their location so buffers must start on page boundaries. The I4/O4 commands have the following format: I4/buffer/track/drive O4/buffer/track/drive 'track' must be from 0 to 79 (this is the base track), and 'drive' is 0,1,2,or 3 to specify which drive the disc is in. If you try to put the O4 buffer on top of the I4 buffer or vice-versa then an error will be signalled. Since OZMON uses 16 bit addresses it cannot address the whole disc in one go; rather, the disc is accessed in 64K blocks. The 'address' of the data you want is converted to a track and sector number and added to the base track specified in the I4 or O4 commands. Using the I4 command is very simple and it cannot corrupt the disc. Once you have 'opened' a disc for reading it does not need to be 'closed' later, merely typing I0 will suffice. When the disc is opened the first sector of the base track is loaded into the I4 buffer regardless of what was there before. When OZMON wants data from another sector it first checks to see if this new sector is currently in the O4 buffer. If it is then the O4 buffer is merely transferred into the I4 buffer, otherwise the new sector is loaded into the I4 buffer from disc. This ensures that PEEKs reflect any POKEs to the O4 buffer that have not yet been put on the disc. Using the O4 command is totally different. You must keep close track of what you are doing when a disc has been 'opened' for output because mistakes can easily crash a disc. When the disc is initially opened OZMON reads the first sector of the base track into the buffer, ready to be altered. When data is poked onto the sector it is the buffer that is modified each time and not the disc. This makes poking faster and minimises drive wear. The output buffer is only updated to disc when a byte is poked to another sector or the disc is 'closed'.If the O4/bb/tt/dd command is re-executed before the disc has been 'closed' then the old contents of the O4 buffer are updated to disc before the new sector is loaded in. For example, suppose you have poked a few bytes into sector 0 and then poke a byte into sector 1. )O4/&500/0/0 )?7/65 ?8/66 )?&100/90 (Because each sector is 256 bytes long address &100 is regarded as being the first byte of sector 1). 19 What will happen is this: OZMON updates its buffer copy of sector 0 in RAM. When the poke is then made to sector 1 sector 0 is updated on disc, sector 1 is read into the buffer and the buffer is modified as required.(If the I4 and O4 buffers are pointing to the same track and sector then pokes to the O4 buffer are also copied into the I4 buffer so that PEEKs and POKEs correspond). Notice that sector 1 has not yet been updated on disc. This may be achieved by a superfluous poke to sector 0 again or by 'closing' the disc. This is achieved by entering: )O4 The O4 must be entered by itself with no parameters. Standard BBC discs have 10 sectors per track (&A00 bytes per track). Thus to read byte 0 of sector 0, track 1 you could use this: )I4/&400/0/0 )N?&A00 or this: )I4/&400/1/0 )N?0 OZMON can also handle discs with 18 sectors per track ( at 256 bytes per sector still ) rather than the standard 10. This situation is likely to occur with some of the new double density systems. They usually provide 8271 emulator software in their ROMs so that OSWORD &7F ( sector READ/WRITE ) works properly. When reading BBC format discs there is no problem. However when reading the double density format discs the emulator software pretends the disc is still in 8271 format, except it doesn't tell you that there are 8 extra sectors on each track. On the basis of 10 sectors per track OZMONs sector editing stream would ignore the last 44% of each track. This extra facility overcomes the problem. Status byte 4 controls this function: Bit 0: READ stream (I4) 0=10 sectors/track 1=18 sectors/track Bit 1: WRITE stream (O4) 0=10 sectors/track 1=18 sectors/track The following formula shows how the computer uses the 'address' given to determine the appropriate track and sector: track=((addr DIV 256)DIV S)+basetrack sector=(addr DIV 256)MOD S pos.in sector=(addr MOD 256) where S=10 or 18 depending on the setting of P4. ERRORS: Illegal buffer space. Bad track. Bad drive. That's the O/P buffer. That's the I/P buffer. Sector not on disc. 20 Chapter 4 OZMON memory map and Internal routine entry points In OZMON entry points are provided for 6 of OZMON's internal routines. These entry points are provided to allow user utility programs access to the numeric conversion routines,assembler, etc. When using these routines you must be sure that the OZMON ROM is the 'currently selected ROM' ( see the 'R' command ) if your routine is to be accessed by the 'G' command. If your routine is called by the Command extension vector, however, then OZMON is always selected. ADDR &9FE0 OZPEEK &9FE3 OZPOKE &9FE6 OZPARAM &9FE9 OZHPRINT &9FEC OZDPRINT &9FEF OZASSEM OZPEEK: See the chapter on the I3 command. This routine reads the input stream and returns the byte read in A. The X register points to two zero page locations where you have stored the address of the byte to be peeked. OZPOKE: See the chapter on the O3 command. This is the output stream entry point. The byte in A is poked at the address pointed to by X, as before. OZPARAM: This is the general purpose parameter evaluator. OZPARAM expects locations &B,C, and D to point to the next parameter to be evaluated. &C,D point to the start of the line and &B is the index pointer to where in the line the parameter starts. On exit the parameter buffer is set up as described in the memory map section. Location &B will be updated to point to the next non-space character or just after a marker ( "/" ) or the ( CHR$13 ) at the end of the line. Carry is cleared if there are no more parameters otherwise it is set. The accumulator holds the parameter 'type' on exit. OZHPRINT: Prints the single byte value in A as a two byte hex number. X and Y are preserved. OZDPRINT: Takes the two byte number in X and Y ( low byte/high byte ) and prints it in decimal. If A is non-zero on entry then leading zeroes are suppressed. OZASSEM: The assembler takes all the data pointed to by &B,C,and D, up to the next ":" or CHR$13, and tries to assemble it. &7,8 hold the address to be assembled to ( P% in BASIC ) and &9,A point to where the assembled code must be stored ( O% in BASIC II ). If OZASSEM finds a lable "@n" ( not ".@n" ) it will assign the value in &7,8 to that lable. On entry bit0 of A is 1 for offset assembling or 0 to store data at &7,8. Bit1 of A should be set if the mnemonic is to be assembled but NOT stored, bit2 of A is set if you want to ignore 'Branch out of range' conditions. On exit carry is clear if an error condition exists, A holds the error codes: A=1 'Bad mnemonic' A=2 'Branch out of range' A=3 'Bad addressing mode' No error messages are given, this is left up to the calling routine. Before error 1 is issued the MACROEXTension vector is tried (&786,787) and if this works then the error 1 is suppressed. OZASSEM returns with &7,8,9,A and &B correctly updated. 21 Memory Map: ZERO Page: &0 -> &3 Parameter buffer for OZPARAM &0 Parameter type. Type 0:Numeric parameter &1,2:Holds the actual number &3:0 if 1 byte given, 1 of 2 bytes given Type 1:String in inverted commas &1,2:Address of string &3:String length Type 255:String at a known address &1,2:Address of string &3:Terminating byte ( usually CHR$13 ) &4 Socket number of 'currently selected ROM' for READs &5 -> &A Parameter buffers reserved for use by OZMON command routines. &B Index to next character to be interpreted on the command line. &C,D Address of the start of the command line. &E,F Secondary pointer. &12 -> &15 Reserved for single step mode command &16 -> &19 General scratch pads, liable to be changed by any subroutine. &1A -> &1F Reserved for command routines scratchpads. &20 -> &2D Reserved for the I/O drivers &2E,2F Holds 'Machine high order address' (OSBYTE &82). Language workspace: &600 -> &630 General string buffer and OZASSEM workspace. &631 -> &638 The status bytes set by 'P' &640 -> &6CB Storage for the two byte lables @0 to @69 &6CF Socket number of ROM selected for WRITEs &6D0 -> &6DF OZASSEM workspace &6E0 Input stream. 1:I0 2:I1 3:I2 4:I4 0:I3 &6E1 Output stream. 1:O0 2:O1 3:O2 4:O4 0:O3 &6E2,6E3 Base Track and Current Sector for Disc PEEKs &6E4,6E5 Base Track and Current Sector for Disc POKEs &6E6 Drive number for Disc PEEKs &6E7 Drive number for Disc POKEs &6E8 Track of sector currently in I4 buffer &6E9 Track of sector currently in O4 buffer &6EA MSB of Input Sector buffer &6EB MSB of Output Sector buffer &6EC -> &6ED Length of current I2 or IO2 file &6EE Channel number for BGETing (I2) &6EF Channel number for BPUTing (O2) &6FA -> &6FF Scratchpad for OZPARAM arithmetic calculations &700 -> &77F Text input buffer &780,781 OZPOKE vector &782,783 OZPEEK vector &784,785 Command extension vector. If OZMON encounters an unrecognised command letter it will jump through this vector. By setting this vector to a user routine extra commands may be easily added. &B points to the offending character. On return ( with RTS ) the user routine must SET the carry flag if it has accepted the command otherwise the error 'Mistake' will be issued. &786,787 MACROEXTension vector for OZASSEM. The first three characters of the unrecognised mnemonic are at &6D0 with &B pointing to the next character on the input line. &18 holds the OZASSEM control byte. Carry must be set on exit, and address pointers updated, if user routine has accepted the mnemonic. &788 -> &7FF Paged-ROM accessing routines, do not corrupt or OZMON will crash. 22 OZMON Error messages Bad parameter : Unrecognised parameter encountered Bad Binary : The characters after the '%' was not a valid binary string Bad Hex : The '&' has not been followed by a valid hex character Bad I/O file name : The I2/"---" filename is not a valid string Bad track : The track number in the I4 or O4 command is greater than 79 Bad drive : The drive number in the I4 or O4 command is greater than 3 Escape : An 'Escape' condition has occurred either from the escape key being pressed or some other means ( RS432,etc ) Finished : A correct return to command level from Single Step mode has been made File cannot be opened : The current filing system has returned a channel number of 0, usually because the file doesn't exist Illegal Op-code : Single Step mode has encountered an undefined command ( disassembled as "???" ) Invalid lable : The '@' has been followed by a number greater than 69 Input file already open : I2/"---" has been executed twice without closing the file in between times Illegal buffer space : Memory below &400 may not be assigned as I4 or O4 buffers I/O streams not the same : The 'E' command has been attempted with different I and O streams Not enough parameters : The minimum number of parameters has not been provided No valid ROM present : The 'R' command has selected an empty socket Output file already open : O2/"---" has been executed twice without closing the file in between times Parameter mismatch : String given when numeric was expected Stack error : More bytes have been pulled off the stack during Single Step mode than were on it in the beginning--OR-- a return from Single Step mode was attempted with the stack pointer incorrectly placed. Sector not on disc : A peek or poke has been attempted to a track > 79 ( See I4/O4 for method of calculating track from addresses ) Too many parameters : String buffer has more than 48 characters in it. Used by 'F','S',and'EQU' assembler directive That's the O/P buffer : The page you selected for the I4 buffer is already in use as the O4 buffer That's the I/P buffer : The page you selected for the O4 buffer is already in use as the I4 buffer If an error message is generated by another ROM (e.g. FS error, ROM routines called with the 'G' command, etc) then OZMON also prints " in ROM:nn" after the error message.