MACHINE CODE TESTER by T.E. Watts from ZX COmputing, May 1986 If you're tired of crashing code, here's a routine that allows you to check the effects of your m/c programs before you run them. Everyone who has attempted to program in machine code will be aware of (if not very familiar with) the routine: enter code ... save code ... test ... CRASH! ... unplug ... plug in ... reload ... print addresses and trace ... amend ... save ... test ... CRASH!! ... (expletive deleted) and so on. This program saves all the frustration and a great deal of time by tracing your machine code routines step by step, showing the contents of the registers before and after each instruction and printing the contents of any address. The registers can be preset to any desired value as can the stack pointer. A separate stack from that used by the Basic system is set up which avoids problems of stack balancing and makes it very easy to check that your routine does balance the stack. The address of the instruction to be executed can, of course, be changed and a facility is included to put an address on the stack or to change the address to the last entry on the stack. The alternate register set is not printed, but is preserved and can be used. Unfortunately, owing to the screen usage of the program and (if they are used) the complexity of the ROM routines, screen printing routines will produce little or no visible results. However, the state of all registers and all stores is known at all stages so that in practice there is no real difficulty in testing such routines. The heart of the program is the machine code routine at address 6D5E (decimal 27998) which is accessed via line 710. As the alternate register pair H'L' is used by the USR routine, provision has been made to preserve and restore its contents by the routines at addresses 6D7F-6D83 and 6D90-6D97. The rest of the code is quite straightforward and should present no difficulty. The Basic program sets up initial values for the registers and stack pointer and prints these values. It also keeps track of the address of the next instruction and copies the appropriate number of bytes to addresses 6D88-6D8B. The construction of the program is outlined in Table 1, functions are listed in Table 2 and variables in Table 3. [None of these tables were printed in the magazine. JimG] Entering the program You should first enter the Basic program and after checking the listing for errors save it with the command SAVE "mctp" LINE 1. The machine code routine (Listing 2) can then be entered. Carefully check your loaded code (which shouldn't take too long since the routine is so short) and save it immediately after the Basic program when prompted. In use When saved as above, the command LOAD "mctp" will load and autostart the program. The machine code routine is loaded if necessary and the program stops with the question "Do you want instructions?". You are then asked if you wish to load a named machine code routine; this will normally be the routine you want to test and it should be saved on tape so that the command LOAD "name" CODE will load it to the correct location. The location of your code must be above 6DA4 (decimal 28068). Apart from the name of a routine to be loaded and one other option which we will come to shortly, all input to the program is either a number or a single letter, "y" or "n". All numbers may be in either decimal or hexadecimal; hex numbers must be either 2 or 4 digits long and followed by "h" (eg. 4 can be input as "4" or "04" or "04h" or "0004h"). Letters, whether as part of a hex number or a reply to a question, may be either upper or lower case. But remember that there is no syntax check on numbers and an entry such as "04D1" (i.e. "h" missing from a hex number) will produce the report "440.1 : Nonsense in Basic" or a similar error halt. If this happens then restart the program by typing "GO TO 600". The program now needs to be told the address that it starts testing from and initial values for all registers; a location in an unused part of RAM must be selected for use as the stack. The program then enters the main loop. The current location is printed in both decimal and hexadecimal and the contents of this and the next three locations are displayed in hex code. You now enter the number of bytes in the instruction or a code value to get to the required facility. The result of entering the different possible values is as follows: Number from 1 to 4: The number of bytes specified is executed and the state of the registers after execution is displayed. Zero entered: The program asks "Skip/go to?". Entering 0 to 4 causes the current address to be increased by the number. Entering a number higher than four changes the current address to the number entered and will ask if you wish to put a number on the stack (use this facility if the instruction is CALL), entering "s" changes the current address to the last entry on the stack and increments the stack pointer (use this facility if the instruction is RET). All these options are followed by the opportunity to change the contents of the registers and stack pointer. A number less than zero can be entered and this will stop the program. Number greater than 4: This is the same as entering more than four in response to the 'skip/go to' question above. The current address is changed and you can put a number on the stack. The register contents can be changed. The program stops if you try to enter any number less than zero. All the above options (except those which stop the program) are followed by the question "Print locations?". Entering "y" produces the response "Start at?" followed by "How many/End at?" and the appropriate locations are printed in decimal and hex (if the second number is greater than the first then the program assumes it to be an end location). After printing, the program returns to the question "Print locations?" and further locations can be printed. Entering anything other than "y" takes the program back to the start of the main loop. If you have stopped the program and you wish to restart at the same location and with the same data then use the command GO TO 600. RUNning the program will require you to reinitialise the registers and stack pointer; however any data above location 6D5D (27997) will be unaffected and the test in line 5 will avoid the necessity of reloading the program's machine code routine. You can, of course, RUN the program in order to load and test a different machine code routine. Testing routines which change address When testing a routine which includes instructions such as CALL, RST, JP JR, RET you should not execute the jump instruction but should change the next address to the appropriate value, and for CALL instructions put the return address (usually current address + 3) on the stack. If you have done this for a CALL then the corresponding RET is followed by executing zero bytes and entering "s" in response to the "Skip/go to" question. This action is necessary because executing an instruction which transfers control to another address will take the program counter outside the limits of the test control routine with no guarantee that control will ever be properly returned. Of course a tested routine can be called but you should be certain that it is fully tested and always returns satisfactorily.