'DisAssem' ROM ============== This ROM provides routines for disassembling machine code of various processors. The routines are accessed via an OSWORD call which is implemented by the ROM. OSWORD 190 - Disassembly routine -------------------------------- To call the disassembly routine, use the following OSWORD call: On entry: A=190, XY point to control block: Call address: &FFF1 Control block: XY+0 &10 - Length of entry control block XY+1 &20 - Length of exit control block XY+2 Processor number XY+3 Flag (default zero) XY+4 \ XY+5 \ Address of instruction XY+6 / XY+7 / XY+8... Bytes of instruction to be disassembled On exit: A,X,Y may be corrupted. Control block: XY+0 XY+1 XY+2 Disassembly status flag XY+3 Number of bytes disassembled XY+4 Text string of disassembled instruction, : terminated by a CR (value 13). : XY+31 Maximum length of string 28 characters. You send the routine the address of the disassembly, and also the bytes that are at that address for it to disassemble. Most CPUs have instructions with a maximum length of four bytes, but some have longer instructions, eg the 80x86 has a couple of instructions 6 bytes long. So, it is recommended that you provide eight bytes (two words) to disassemble. This simplifies the routine so that it does not have to attempt to read the bytes directly from memory itself. In the returned control block, XY+3 contains the actual number of bytes disassembled, and so is the value by which to increase the address pointer to disassemble the next instruction. The status byte at XY+2 holds flags about the disassembly, the top bit always being used to indicate if the instructions could be disassembled or not. If b7=0, it was a valid instruction. If b7=1, it could not be disassembled, and the returned text string is "EQUB &xx" or "DEFB &xx" depending on the processor. If b6=1, then the disassembled instruction terminates a piece of code, such as an unconditional return or jump. The disassembler program can use this bit to print a blank line to clarify listings. The bottom six bits are used by different disassembly routines for different purposes. In the entry control block, XY+2 holds the processor control number. Numbers allocated so far are: 0 reserved 44 ARM 2 6502 65 6502/65C02/6512 8 8008 68 68x00 series 9 6809 80 Z80, Zilog mnemonics 11 pdp11 85 8080/8085, Zilog mnemonics 12 6512 86 80x86 series 18 80186 89 INS8900 28 80286 94 9440 series 30 oggin 99 9900 32 32016 65186 38 80386 48 80486 58 80586 A call with XY+0 set to 8 will return a string at XY+4 holding the name of the processor the routine disassembles. This call can be used to check if a specific disassembly routine is available. Calling with XY+0 set to 8 also returns a flag in XY+3 with the following information: b0-b1: CPU address width, 0=16, 1=24, 2=32 b2-b3: CPU data width, 0=bytes, 1=16-bit words, 2=32-bit words b4: Disassembly base, 0=hex, 1=octal A simple disassembly program would be the following: 10 REM Disassembly test program 1 20 REM By J.G.Harston 30 DIM ctrl% 31:X%=ctrl%:Y%=X% DIV 256 40 INPUT "Address: &"A$:ADDR%=EVAL("&"+A$) 50 A%=190:REPEAT 60 !X%=&2010:X?2=80 :REM Z80 70 X%!4=ADDR% :REM Address 80 X%!8=!ADDR% :REM Data at the address 90 CALL &FFF1 100 PRINT;~ADDR%;" "; 110 FOR Z%=ADDR% TO ADDR%+X%?3-1 120 PRINT;~?Z%;" ";:NEXT 130 PRINTTAB(20);$(X%+4):IF(X%?2AND64):PRINT 140 ADDR%=ADDR%+X%?3 150 UNTIL0 The 6502 disassembly routine (type number 2) returns the following information in the status byte: b7: could not be disassembled b6: instruction is RTS, RTI or JMP b5-0: unused, zero The 65C12 disassembly routine (type number 12) returns the following information in the status byte: b7: could not be disassembled b6: instruction is RTS, RTI, JMP or BRA b5-1: unused, zero b0: Instruction specific to 65C12 The 65C12 disassembly routine recognises the extra instructions on the 65C12. The generic 6502 series disassembly routine (type number 65) returns the following information in the status byte: b7: could not be disassembled b6: instruction is RTS, RTI, JMP or BRA b5-2: unused, zero b1: instruction specific to Rockwell R65C02 b0: instruction specific to 65C12 The generic 6502 series disassembly routine recognises the extra instructions on the 65C12 and the extra instructions on the Rockwell R65C02. The oggin disassembly routine (type number 30) returns the following information in the status byte: b7: could not be disassembled b6: instruction is RET or JMP b5-1: unused, zero b0: extended oggin instruction set For further information, see "An Introduction to the oggin machine", David Budgen, University of Stirling Computing Science Department. The Z80 disassembly routine (type number 80) returns the following information in the status byte: b7: could not be disassembled b6: instruction is unconditional RET, JP or JR b5-b2: unused, zero b1: Instruction not on the 8080/8085 b0: Undocumented instruction The Z80 disassembly routine recognises the undocumented instructions using the index registers as 8-bit register pairs, labelling them IXL, IXH, IYL and IYH, and the Shift Left and Set instructions CB30 to CB38. The 8080/8085 disassembly routine (type number 85) returns the following information in the status byte: b7: could not be disassembled b6: instruction is unconditional RET or JP b5-b0: unused, zero OSBYTE 90 - General ------------------- All the ROMs that I write conform to my ROM selection standard that allows interrogation of the ROMs in a uniform manner. This is the OSBYTE 90 call, used to enable and disable the ROM, and to ask for status information about it. The arrangement of the OSBYTE 90 call is: On entry: A=90 X=ID number, or zero Y=call number On exit: A=90 X=b7-b6 ROM status, b5-b0 other specific info. Y=other info. All ROMs respond to X=0, Y=0 on entry (*FX90,0 or just *FX90) by displaying their ID number and their name, eg: >*FX90 6: Harston ADFS 9: Z80 BASIC With X set to non-zero, it is a specific call to a particular ROM, with Y containing the call number. All ROMs respond to calls with Y=0 to enable to ROM, Y=1 to disable to ROM and Y=255 to request the ROM's status, eg: >*FX90,9,1 will disable the ROM with program ID 9, ie Z80 BASIC. On return from calls 0, 1 and 255, the top two bits of X hold information about whether the ROM is present, and whether it is enabled or not. Bit 7 holds if the ROM is enabled or disabled, and bit 6 holds if the ROM is actually present of not. This is summarised as: X=11xxxxxx ROM not present X=10xxxxxx ROM present, but disabled X=0yxxxxxx ROM present and enabled If the ROM is enabled (ie bit 7 is zero), then it must also be present, so bit 6 is an implied zero. This allows bit 6 to be used to return information on other things. The other six bits of X can be used to return specific information about the ROM. The top two bits of X hold the status of the ROM before the call, so if the ROM is disabled, and you enable it with Y=0, then X will return %10xxxxxx. When calling from a second processor using the Osbyte call, the Y register is ignored and zero is used instead for calls below Osbyte &80. This means that if you use a call with Y=255 to read the status, and it returns saying that the ROM was disabled, the ROM will actually have been enabled, because Y=0 has been used instead. To get round this, use something like: A%=90:X%=number:Y%=255:S%=(USR&FFF4 AND&FF00)DIV256 IF (S% AND &C0)=&80 THEN OSCLI "FX90,"+STR$(number)+",1" This will re-disable a ROM found to be actually disabled. Some of the program IDs that I have used so far are: 1: CharRom - character set ROM 2: NewMOS 3: 4: 5: Games Auto Boot ROM 6: HADFS - Harston Advanced Disk Filing System 7: Z80 Emulator - Emulates a Z80 CPU 8: 9: Z80 BASIC - Z80BBCBASIC with BBC file i/o 10: 11: Dissem ROM - Various disassembly routines If anyone else wants to adhere to this method for a ROM that they are writing, write to me, and I will assign you a number and give you the routine I use for service call 7 to provide the OSBYTE 90 call. OSBYTE 90 - in DisAssem ROM --------------------------- The DisAssem ROM has program ID 11, and by default, the ROM is enabled. To disable it, you can use *FX90,11,1. The ROM will re-enable itself on a power-on reset or a memory-clear reset. The bottom six bits of X do not hold anything valid.