MONITOR by Jon Ellis from ZX Computing November 1986 If you're writing your own machine code programs you'll need a good monitor to help debug them - so here it is. [NOTE: I made a small correction to the text in the program, replacing the] [incorrectly spelled phrase "Number base togle now" with the phrase ] ["Number base toggle is". JimG] Over the course of writing many machine code routines I realised that I had no good program for debugging them. So, If you haven't got a program - write it yourself. Here is that program, a monitor which should provide all the functions you would normally need in the course of debugging a machine code program. Numbers can be entered In either hex or decimal, regardless of the state of the number base toggle. Decimal numbers must all be five digits long, being bulked out with leading zeros if necessary. To enter a number in hex, type '&' as the first character, and then the number in four hex digits, again using leading zeros if necessary. If only one byte is required then the low byte is taken, ie. if you enter a number greater than 255 when the Monitor is expecting a number in the range 0 to 255, then your input will be taken as modulo 256. After most functions have been executed the Monitor will pause for you to examine the results of the function, if any. To terminate this pause press either 'X' or BREAK and you will then be returned to the menu. The Monitor is written so that you can treat the Spectrum as a Z80 processor only as far as possible. This means that, although the Spectrum operating system requires the IY register to have the value 23610 at all times, unless your routine is going to use the operating system, you may ignore this requirement. A similar situation occurs with the HL pair. The registers that are used when your routine is run are not those used by the Monitor or the Spectrum ROM. To abort a function you should press BREAK which will return you to the menu. Monitor Functions The monitor offers a menu of 18 functions: 1) Alter Memory. This function will prompt for a start address (see note on the input of numbers), and the program will then print the address and its contents. The Monitor will then wait for you to input the new value before moving on to the next byte. When you have filled up a screen, press 'X' for another page. At any time you may press BREAK to escape. 2) Breakpoint. This function enables you to place an instruction in the middle of the code that is being debugged, which causes execution to be stopped and control returned to the Monitor so that you can alter/inspect the registers etc. The breakpoint instruction is three bytes long, and thus two breakpoints should not be inserted less than four bytes apart otherwise a crash might occur on execution. The code that occupied the three bytes overwritten by the breakpoint instruction is stored, and will be replaced when the breakpoint is deleted. When you select this function from the menu it will prompt for the address at which the breakpoint is to be inserted. A total of nine breakpoints may be used at once. If all nine are in use then nothing will happen when the function is selected. 3) Convert Number. This function will prompt for the input of a number and then print the number in decimal, hex, and binary. 4) Delete Breakpoint. When selected, this command will display all nine of the breakpoints, and then ask for the number of the breakpoint to be deleted. (Note that you should enter the number of the breakpoint (1-9), not its address). The three bytes that were overwritten will then be replaced. 5) Examine Stack. The Monitor provides 40 bytes of stack space solely for use by the object program. On entering the Monitor or resetting the registers, the stack is reduced to one word in length, this word being a return address inside the Monitor, which should prevent a crash in the event of a RET instruction being executed at the end of the object program. On selection, this function displays all the words currently on the user stack. 6) Fill Memory Block. This command allows you to fill a block of memory with a specified value. It prompts for a start address, the length of the block to be filled, and the byte to be used. 7) Jump to Routine. The function will prompt for the address to be jumped to, and execution will continue from this address using the values of the user registers (see later). This function is to allow for the object code to be tested. Ideally a breakpoint should be used at the end of the code to return to the Monitor, in which case the report "BREAK at (address)" will be displayed. However, a RET instruction should also work providing that the routine has used the stack correctly. 8) Look at Breakpoints. This function displays the addresses of each of the nine breakpoints, an address of 0 indicating that the breakpoint is unused. 9) Move Memory Block. This command allows you to copy blocks of memory to other areas. It prompts for the start address of the block, the start of the destination area, and the length of the block to be copied. 10) Number Base Toggle. This toggle determines the base in which all numeric output from the monitor will be displayed. It toggles between hex, decimal and binary. Only some output can be displayed in binary due to the length of a binary word (16 characters), other output being displayed in hex. The toggle defaults to decimal. 11) One-Step Routine. This is probably one of the most useful functions. It enables you to step through the object code one instruction at a time, whilst keeping track of the user register values. The Monitor will prompt for a start address, and will commence stepping from that address, updating the register display after each instruction and then pausing for you to inspect the registers, To move to the next instruction, press 'X'. To escape, press BREAK. 12) Printers Toggle. When toggled to ON, this causes output from the View Memory function to be dumped to the ZX Printer. The toggle defaults to OFF. 13) Quit. Returns control to BASIC. 14) Register Display. This function displays the values of the user registers, both the normal and the alternate set. The current values of the interrupt vector register, I, and the memory refresh register R, are also displayed. The value given for the program counter, PC, refers to the last instruction executed. The value of the stack pointer, SP, that is displayed refers to the user stack. The flags register of the normal AF pair is shown expanded into bit format, with each of the six flags labelled. The value of the maskable interrupt flip-flop is also shown, the interrupts being enabled or disabled as appropriate when the user code is executed. 15) Specify Entry Values. This function allows you to change the values of the user registers, perhaps to test a subroutine whose parameters are passed to it in the registers. You can also specify the value of the zero flag and the carry flag. You should select the register to be altered by pressing the appropriate letter. To escape press BREAK. 16) Use Other Program. This function allows you to use another program and to call it from the Monitor. The function is not designed for the execution of the object program, but for the calling of some other utility such as a disassembler. When you quit the other program, control will return to the Monitor. The use of this function to call an assembler forms a very powerful development tool. 17) View Memory. This displays the contents of memory from the specified start location, dumping also to the printer if the printer toggle is on. The routine displays 110 bytes per page, 20 bytes per page if using binary. When the page is full the computer will wait for you to press 'X' before proceeding to the next page. To escape, press BREAK. 18) Zero Registers. This function restores the user registers to their original values that they held when the Monitor was first entered. In most cases this is 0, but the IY register defaults to 23610 and the HL pair defaults to 10072 as required by the Spectrum operating system. The user stack is also reset and preloaded with the return address mentioned earlier in the Examine Stack function. Instructions The Monitor is written entirely in machine code and occupies the memory from 28350 to 32767, and is thus 4418 bytes long. This means that it will fit on a 16K Spectrum, but it is unlikely that the expansion opportunities offered by the User program feature will be utilised fully. Type in listing 1 and save it - this is the hex loader. Run the program and you will be prompted for the string of hex digits and then for the check digit. Although the check digit might not look right it is actually more effective than a normal checksum, spotting the vast majority of transposition errors. When you have finished the program will save the finished code and then verify it. Reset the machine and then type CLEAR 28349: LOAD "MONITOR" CODE as a direct command. After the code has loaded you should enter the Monitor with RANDOMIZE USR 28350. A menu of the 18 functions should be displayed. You should test each of the functions carefully. If you discover any errors then listing 3 should help - it displays the code you have entered in the same format as listing 2. -- Another Fine Product transcribed by: Jim Grimwood, Weardale, England (http://www.users.globalnet.co.uk/~jimg/) --