
DISX4 - Full-Screeen Interactive Disassembler
by Bruce Tomlin - bruce@xi6.com


DISX4 is a multi-CPU disassembler for various vintage CPU architectures, mostly 8-bit. It will keep track of live changes to label references.


What disx4 is intended for:
- making a decent disassembly that can be saved as a .asm file that you can tweak later
- not for making the prefect disassembly that needs no further touching

Cool things that it doesn't do:
- track RAM references
- deal with split references (high half in one instruction, low half in another)
- combine separate binary files (if your code comes from multiple ROMs, you will need to create a combined binary first)
- handle multiple code segments with different address ranges


=== BULDING ===

This uses a standard makefile, so use the "make" command to build it. It should work in a standard Linux or MacOS environment with C++ developer tools installed. If this isn't sufficient information, then google for "how to use make".

On some systems, if you have not previously used the compiler, "make" might have trouble finding it. Consult the documentation of your OS distribution for more information.

If you plan on modifying the code, you might want to use "make depend" first. This generates a file named ".depend" with make dependencies for the .h files. That way, when you change a common .h file, all files that use it will be automatically rebuilt. The "make depend" command will probably complain about missing standard includes; you should ignore these warnings.

I haven't tried to build this on Windows. It might work with either Cygwin or the Linux subsystem. At least one person has tried with Cygwin, but its system headers defined "addr_t" for some reason.


=== REFERENCES ===

Each line of disassembly can have one external reference, to either code or data. Note that some CPUs have 16-bit immediate instructions which can potentially be either an address or a number. This reference address will be used for creating labels, and for code tracing. Word or longword data lines will only allow a reference from the first word on the line.

Label creation can be suppressed to certain addresses by using the Control-R command on the address.

Address 0x0000 is specifically prevented from automatically generating a reference, because it is almost never used as such.


=== TRACING ===

If the label is a code reference, the T command can disassemble into referenced code after finishing the current block of code. This can quickly disasssemble large ranges of code, but it can also be misled by "tricks" like subroutines that pop the return address, read data from that address, and then put it back before returning.  Note that the Z-80 series is particularly vulnerable to blank (0x20) characters causing bogus code references. The "rip-stop" functionality attempts to detect the most obvious situations.


=== COMMENTS ===

Comments can be attached to any code line by using the semicolon (';') command. This will bring up the current comment (if any) for editing. Press Return to save the line, press Escape to cancel changes, or delete the entire comment line and press Return to remove the comment.

Comments are saved in a ".cmt" file, which consists of lines with the address in hexadecimal ASCII, a blank, the comment text, and a newline. They are saved in sorted order, but can be loaded in a non-sorted order. If all comments have been removed, the ".cmt" file is deleted.

If a comment "falls off" because its address is now in the middle of a line, it is not immediately deleted, but can not be seen until the address starts a line again. However, when saving, such hidden labels will not be saved.

NOTE: Comments are not affected by the Undo command!


=== UNDO ===

There is minimal undo support, in the form of one saved state. It is automacially saved by the shift-C and shift-T commands, and manually by the control-U key command. To use it, use the shift-U key command. But it's really not in a useful state right now.


=== COMMAND LINE ===

Usage:
    disx4 [options] [binfile]

Options:
    -c cpu         select default CPU type
    -c ?           show list of supported CPU types
    -b xxxx        base address
    -s xxxx        size of binary data
    -o xxxx        offset to start of data in file
    -a             create binfile.asm and exit
    -l             create binfile.lst and exit
    -!             don't load binfile.ctl

The addresses for -b, -s, and -o default to hexadecimal unless the selected CPU prefers octal. A prefix letter of "H" or "O" will force hexadecimal or octal. They are also scaled for wide architectures.

If started up with no parameters, it will show an empty file, and the selected CPU type will be undefined. If "binfile.ctl" is loaded, its saved -b, -s, and -o parameters are used unless overridden.

"-c cpu" will select the default and current CPU type in a new .ctl file.

"-c ?" will show a list of supported CPU types.

"-b xxxx" will specify the load address of the first byte

"-s xxxx" will specify the maximum size of the code image to be loaded.

"-o xxxx" will specify the offset in the file to the first byte of the code image. This allows skipping a header.

"-!" will prevent automatic loading of "binfile.ctl". This will ignore any existing work in "binfile.ctl".

"-a" and "-l" will generate a .asm and/or .lst file, then return to the command line.


=== SCREEN NAVIGATION KEYS ===

Up-arrow        Move up one line
Down-arrow      Move down one line

Home            Move to first line
End             Move to last line

Page Up         Scroll down a page at a time, while staying on the same screen line
Page Down       Scroll up a page at a time, while staying on the same screen line
Space bar       Same as Page Down

Control-B       Move to top of screen, then move up a page at a time
Control-D       Move to bottom of screen, then move down a page at a time


=== SINGLE-KEY COMMANDS ===

0 - 9           Digit keys let you specify a count of 0-99 for some commands.
                The escape key will clear the count. Some commands have a maximum count.

x               (no count) Disasssemble as raw data (the default state)
a               (max count 40) Disassemble as ASCII text
b               (max count 32) Disassemble as single bytes
B               (max count 32) Disassemble as decimal bytes (unsigned)
h               (max count 32) Disassemble as hex bytes with no formatting
w               (max count 20) Disassemble as 2-byte words
shift-W         (max count 20) Disassemble as reverse 2-byte words
ctrl-W          (max count 1)  Disassemble as word address - 1 for 6502 jump tables
\               (max count 16) Disassemble as 4-byte longwords
| (shift-\)     (max count 16) Disassemble as reverse 4-byte longwords
d               (max count 20) Disassemble as decimal words (unsigned)
shift-D         (max count 16) Disassemble as decimal longwords (signed)
_ (underline)   (max count 40) Disassemble as EBCDIC text
I               (max count 16) Disassemble as binary, 0x55 = 01010101B
X               (max count 16) Disassemble as visible binary, 0x55 = _X_X_X_X
O               (max count 16) Disassemble as visible binary, 0x55 = O_O_O_O_
                See "xobits.h"/"xobits.s" for the "visible binary" equates.
*               Repeat previous data format command with same count
( and )         Expand or shrink the size of a line of data.

shift-E         Dissasemble current word as a position-independent offset in a table
                starting at the most recent label. This is commonly found on certain
                architectures such as 68k. If the target address has no label, a data
                label will be created. If the target is already disassembled as code, a
                code label will be created.

ctrl-E          The same as shift-E, but with a byte offset.

c               Disassemble current address as code. Ignored if already disassembled
                as current CPU, or if an illegal instruction.

shift-C         Disassemble as code until unconditional branch or illegal instruction.

T               Trace disassemble from current instruction, same rules as shift-C except
                that all code references are followed and disassembled as well.

shift-T         Trace disassemble until unconditional branch or illegal instruction.

ctrl-T          Disassemble as a word and trace from the referenced address. This is
                intended for jump tables. The referenced address will become a code label
                when appropriate.

l               Toggle a pre-instruction blank line before this code/data line.

shift-L         Toggle label type at this address between none, data, and code. Note that
  or            if the current line is a "EQU $-n" line, this will only remove the label.
control-L       You must use "X" to break up the previous instruction, change the label
                state, then fix it with "c" afterward.

^               Toggle label type at address referenced by the current instruction.

control-R       Toggle the no-reference attribute for selected address, to prevent labels
                from being automatically created. This is useful for certain "magic
                number" addresses like 0x1000, and almost anything at address 0000-00FF.

control-U       Save current state for the next undo.
shift-U         Undo to last saved state. State is automatically saved before shift-C and
                shift-T commands.

@               Go to the address referenced by the current instruction.
< and >         Go backward and forward along "@" or ":xxxx" usages.
[ and ]         Go backward and forward to the next non-EQU label.

!               Search the entire code for any reference to the label at the current line,
                and delete the label if not found. The address of the first reference is
                reported.

~ (tilde)       Re-center the selected line towards the middle of the screen. This is
                useful when at the very top or bottom of the screen and you need to see a
                few more lines.

"               Change the hint flags for the current address. There are two bits of
                hint flags that rotate through all four combinations.

$               Change the default hint flags for newly disassembled instructions.


=== TEXT COMMANDS ===

: command       Enter a text command
/ text          Search forward - Searches are case insensitive and collapse all spaces
                together. Searches also ignore the hex address and data fields. With
                no text, the previously searched text is reused.
? text          Search backward
; comment       Edits a comment at the current address. (code/data lines only)


While typing in the command line:

Backspace or DEL  Delete character before cursor, or exit input mode if line is empty.
Carriage return   Finish line and start executing it.
Escape            Abort current line and exit input mode.
Left/Right Arrow  Move the cursor left or right.
Ctrl-U / Ctrl-X   Erase from the cursor position to the beginning of the line.
Ctrl-A or HOME    Move cursor to start of line.
Ctrl-E or END     Move cursor to end of line.


Command list:

quit / q        Exit the program. If the disassembly status has been changed, you must
                use ":q!" to override the changes, or save first with ":w".

cpu <cputype>   Sets the current CPU type for disassembly. If defcpu has not yet been set,
                it will also be set to this CPU type.

defcpu <cputype> Sets the default CPU type that will be used for such things as number
                 syntax (0FFH vs $FF) and default endian order for pseudo-ops like DW.

list            Create the file "binfile.lst" as a listing-style file of the whole image.

asm             Create the file "binfile.asm" as a source-style file of the whole image.

save / w        Save the current disassembly state into "binfile.ctl".

load <file> [!] [Bxxxx] [Sxxxx] [Oxxxx]
                Load the binary file.
                - If "file.ctl" exists, it will be used.
                - If the file name is a single "-" character, the current file
                  will be reloaded.
                - If ! is used, the disassembly state in an existing "file.ctl" is
                  completely ignored.
                - The B/S/O parameters will override what is stored in the .ctl
                  file, but will not be saved into the .ctl file until an actual
                  save/w command is done. There must not be a blank before the
                  xxxx address. Changing Oxxxx will almost certainly cause all
                  saved disassembly information to be incorrect.
                  Warning: if the parameters result in a smaller data area,
                  some disassembly state could be lost!
                  Warning: this does not check if the current file has changes!

label / l [name] If name is specified, a custom label is added for the current
                code address. If no name is specified, any custom label for the
                current address is removed.

tabs [!] [n] [n] [n] [n] [n]
                Without any parameters, shows the current column widths.
                With parameters, sets column widths.
                "!" causes listing files to generate hard (0x09) tabs. When
                this is used, all column widths must be multiples of 8.
                The five columns are listing address, hex object code, label,
                opcode, and operands. The default values are: ! 8 16 8 8 16

xxxx            A hexadecimal number goes to that address in the image. ":0"
                should always move to the start of the image, just like the
                Home key. The current address is added to the < / > stack
                before going to the new address.

<label>         If the label exists, move to its address.

$               Moves to the end of the image, just like the End key.

rst [########]  Sets extra instruction bytes used by the 8080/Z80 RST instruction.
                An 8 digit number sets all the values at once. A value of 1 causes RST
                instructions to disassemble as two bytes, and a value of 9 causes RST
                instructions do disassemble as ten bytes. Default is 00000000.
                If no parameter is provided, it shows the current state.
                Note that changing this will not automatically re-scan the code. You
                must go to each RST instruction and re-disassemble it with the 'c' key.

hex             Change the code display between hexadecimal and octal.
octal           This is only a temporary override and is not saved on exit.


=== RIP-STOP ===

An auto-tracing disassembler can be very powerful, and with great power comes great responsibility! Each instruction set has its own quirks when it reaches data that isn't code. The problem is that many bogus labels can get created, which are a pain to clean up, and it could run wild over even more data. Each CPU disassembler can report that a given instruction is suspicious, and to stop tracing. The shift-C command stops immediately, and the shift-T command stops the current branch. To manually disassemble an offending instruction, use the lowercase "c" command.

So far this is mostly in the Z-80 and 6502 disassemblers. Here are some of the various trigger conditions:

Z-80:
- three NOP instructions in a row (repeated 0x00)
- two RST 38H instructions in a row (repeated 0xFF)
- LD r,r where r is the same register
- repated LD r1,r2 with the same pair of registers
- branches with an offset of 0x00 or 0xFF
- DJNZ with a forward offset (this is common on 8051, but rarely used on Z-80)

6502:
- two BRK instructions in a row (repeated 0x00)
- branches with an offset of 0xFF
- the rip-stop code also tries to detect "always branch" conditions such as BEQ+BNE

68HC11:
- two NOP or SWI instructions in a row (repeated 0x01 or 0x3F)
- STX $FFFF (repeated 0xFF)
- branches with an offset 0f 0xFF

8008:
- repeated MOV r,r with the same pair of registers
- two NOP instructions in a row
- two HLT instructions in a row (repeated 0xFF)


=== HINT FLAGS ===

Some diassemblers can use a few extra hints on what to do. There are two flag bits for each address, which can be one of four combinations. The meaning of these is different for each disassembler.

All: DW, DRW, DL, DRL references are disabled with a hint of 1 or 3. A hint of 1 or 3 will display decimal DB, DW, DL values as signed decimal.

Motorola CPUs: A hint flag of 1 or 3 will change a BCC or BCS opcode to BHS or BLO; FCC strings are now toggled with a hint of 1 or 3.

Z80: 16-bit references are disabled with a hint of 1 or 3, immediate bytes can be displayed as ASCII or decimal, IX/IY offsets can be displayed as decimal, branches to self can be displayed as "$".

6809: Immediate bytes display in ASCII or decimal, and references are enabled/disabled for immediate words.

68HC11: Immediate word values are disabled/enabled with a hint flag of 1 or 3; D register values are non-references by default.

68HC16: Immediate byte values are displayed in ASCII or decimal, immediate word values have references enabled/disabled

68K: A hint flag of 1 or 3 will disable references in some Effective Addresses.

6502/65816: Immediate bytes can be formatted as characters or decimal numbers, and zero page references can be disabled. Absolute references and branches can have their references disabled. Branches to self can be displayed as "*".

65816: Some instructions change length depending on the run-time value of two processor status flags. These have been assigned to set the "LONGA" (immediate loads for the accumulator are 16 bits) and "LONGI" (immediate loads for the index registers are 16 bits) flags.

0 = none, 1 = LONGI, 2 = LONGA, 3 = LONGI + LONGA

8086: Immediate bytes display in ASCII or decimal, and references are enabled for immediate words and index offsets.

8008: Loads of register pairs are by default detected and combined into LXI instructions. In some cases (such as a branch into the second instruction) you will want to override this.

0,2 = combine LXI, 1,3 = don't combine LXI

8048: The bank for long jumps is by default determined by tracing back in the code for SEL MB0/MB1 instructions, but sometimes this is wrong. You can use hints to force which bank to use. On NS405 there are four banks, so the hint value is added to the bank number.

0 = automatic, 1 = current bank, 2 = SEL MB0 bank, 3 = SEL MB1 bank

Z8: Immediate bytes can be displayed as ASCII or decimal.

PIC: Immediate values for xxxLW opcodes can be displayed as ASCII or decimal.

TMS9900: Immediate values and index offsets become a reference with a hint flag of 1 or 3.

PDP-11: Register mode chooses R7 or PC, indexed offset formatted as decimal, immediate mode can be formatted as decimal or character.


=== LABELS ===

Addresses can be overriden with custom labels. This lets you name things, or use labels from existing source code, and it lets you add address references for an external ROM.

To add a label, use the ":L" or ":LABEL" command. If you specify a name, a label is added at the current address, otherwise a label is deleted at the current address. Labels are saved in a text file called "file.sym", which can be edited when not running the disassembler. Labels are converted to uppercase on entry, but the .sym file can be edited afterward for mixed-case labels.

There is also a text file called "file.equ", which is read-only to the disassembler. It contains a list of labels that can be outside the code file range. This can be used for a list of external variables or subroutines. This list is searched after the .sym labels. Each line should contain a hexadecimal number followed by a blank and a string. Any text after the string will be ignored and can be used for documentation. Any line that does not start with a hexadecimal digit will also be ignored.

NOTE: THIS FEATURE IS CURRENTLY EXPERIMENTAL AND UNDER DEVELOPMENT
(but it works rather well for just a few hours of effort!)

- to add labels outside the code range, use a .equ file
- when using the :ASM or :LIST commands, labels outside the binary file do not get EQU lines generated
- there is no check for duplicate labels
- labels are only generated in contexts where code addresses are used
- zero-page addressing only uses labels on some CPUs
- labels can not be attached to "EQU $-1" lines
- symbols are not loaded if a .ctl file was not loaded


== WIDE ARCHITECTURES ==

Most modern architectures are based on the concept of an 8-bit byte as the smallest addressable unit. The only signifcant exception is older PIC processors. This causes a problem when trying to support as many architectures as possible in a single code base. Some sort of compromises need to be made. But there are quite a few legacy architectures where the instruction word is 10-16 bits long.

Wide architecture support is going to require something or another to be weird, so choices have been made to do things in the most "sensible" way. You can to do screwy things to break it. Don't do screwy things.

* each word is internally represented as multiple bytes
This means that scaling must be done between 8-bit addresses in the raw binary, and 16-bit word addresses in the target architecture. The user should see 16-bit addresses whenever possible.

* labels should be displayed in the target word size
When PIC was the only such architcture, labels were based on the byte addresses of the data. This wasn't much of a problem because PIC had separate code and data spaces, so labels were only referenced by jumps and branches.
The way chosen to handle byte vs word addresses in labels is to look at the default CPU, and generate labels using its instruction width. They can also be displayed in the preferred radix (hex vs octal) of the default CPU.

* code address shows a word address
This is for the same reasons as above. Word-based disasssemblers can now force a word display of binary object code. In particular, displaying things as bytes shows the same code address multiple times. "EQU *-1" lines will also lose the low bit of the byte address. When displaying raw bytes, the same address will be shown for both the even and odd byte.

* command line options (and the ":load" command) use the radix and scale of the default CPU
You may need to use the :defcpu command before using :load if the width is different.

* binary file endian
This is mostly an issue of how the code is stored in a byte-addressed file, but 16-bit binary code can be stored in either endian order. PDP-11 is little-endian, but it's also a byte architecture, so it is not relevant here. However, existing .hex files for PIC that I have found were all in little-endian format. For now, the default assumption is that wide binaries except for PIC will be big-endian.

* .sym files
Addresses in .sym files use the raw byte address.

* .equ files
Addresses in .equ files use the scaled word address, because they are user-visible.


=== MISCELLANEOUS STUFF ===

* If the .bin file has been moved to a different directory, the path saved in the .ctl file will not match. There will still be an attempt to load the .ctl file from the same directory as the .bin file.

* The 8048 disassembler has to guess the SEL MB0/MB1 flag for the JMP and CALL instruction bank address. This is done by searching backwards as long as there's contiguous 8048 code. If none is found, it defaults to the bank at the current address. It is possible for a called subroutine to change the bank, and further calls/jumps after the call will have to be manually overridden with hints.

* Not all of the disassembler cores have been thoroughly tested. Some (ARM and PIC) were never quite finished.

* The PIC disassembler requires the binary be in little-endian format (low instruction byte first).

* The 78K0 disassembler is mostly working, but the code that I had hoped used it was actually for a different CPU, so it hasn't really been tested.

* Because Thumb often uses the low bit of an address to indicate Thumb code, longword references to Thumb code will be displayed as the even address "+1". You can not use the "^" command to put a label at the even address, but will have to manually add a label at the even address.


=== DISASSEMBLER STATUS ===

This is a rough estimation of the quality of each disassembler:

1 = early attempt, not even sure if all opcodes are correct
2 = actual code has been disassembled and makes some sense, but no way to re-assemble
3 = it generates code that has been re-assembled, but not a lot of it
4 = disassembled code has been regularly re-assembled and compared
5 = it has been used a lot, but some sub-types might be less than perfect

5  disz80.cpp    - heavy usage and re-assemblies
5  dis6502.cpp   - 6502 tested with many re-assemblies, 65816 requires manual hinting
5  dis6809.cpp   - heavy usage and re-assmblies, no 6309 support
5  dis68HC11.cpp - tested with many re-assemblies, but few 6303 examples
2  dis68HC12.cpp - tested on an example and an "all opcodes" binary
3  dis68HC05.cpp - few examples to test it on
5  dis68k.cpp    - heavy usage and re-assemblies for 68000; 68020 works on a few samples
4  dis8051.cpp   - tested with many re-assemblies
3  dis8048.cpp   - tested with re-assemblies, but suffers from guessing bank selects
3  dis8008.cpp   - tested on a few re-assemblies
2  dis4004.cpp   - tested on the Busicom calculator ROM
3  disz8.cpp     - tested on a few re-assemblies
2  dis1802.cpp   - sort of works, but few samples and it suffers from split references
2  disf8.cpp     - sort of works, but not enough examples
2  dispic.cpp    - sort of works, but better testing needed
1  disarm.cpp    - still needs a lot of work, can suffer from split references
3  disthumb.cpp  - needs work, and trouble dealing with odd code addresses (Thumb flag)
2  dis9900.cpp   - seems to agree with existing disassemblies
2  disnova.cpp   - seems to work okay on a few samples
2  dis1610.cpp   - seems to work okay on a few samples
2  dis7810.cpp   - only tested on one code example
1  dis78K0.cpp   - the code that I thought was 78K0 turned out to be 78K3, so no examples
2  dis78K3.cpp   - only tested on one code example
2  dis8086.cpp   - very minimal, only useful for Small model code without segments
2  dispdp11.cpp  - sort of works, but not enough examples
2  dis2650.cpp   - seems to work okay on a few samples
2  disimp16.cpp  - seems to work okay on a few samples
3  disscmp.cpp   - seems to work okay
3  dis68hc16.cpp - re-assembled some Motorola example code

=== Q AND A ===

Q: Why is it version "4"?
A: Because I've had disassemblers for a very long time. Version "2" was when I added tracing and a configuration file. It was very detailed, and it could do a good job, but it was a real pain to use. Version 3 was rewriting everything to use C++ inheritance. But it was still such a pain to use that for many years I had been wanting to do an interactive disassembler "someday". Once I finally started writing the code, it only took about two months for V4 to become functional. The V3 disassembler cores were then ported to V4.

Q: Why use ncurses and not a real windowing system?
A: Because it is more portable between Unix-like operating systems, and text UIs are underrated. I kept all the use of ncurses to a single .cpp file so that there should only be one layer to replace later. The key bindings were mostly inspired by vi and bash.

Q: Why only one level of undo?
A: Because it's better than zero levels, and doing more would be a lot of work. Actually, I haven't really used it yet, so it's mostly there as a placeholder.

Q: It crashed and now I can't see what I'm typing!
A: When an app using ncurses crashes, it can leave the terminal in an inconvienent state. The command "stty sane" should return things to normal. If it locks up, pressing control-C twice should force exit to the command line with ncurses properly cleaned up.

REMEMBER, IF IT CRASHES YOU MAY NEED TO 'stty sane' TO GET THE TERMINAL BACK

Q: It crashed with an "assert"!
A: Try to reproduce the problem. Go back and do stuff up to right before the problem, then save. Try a step at a time until it crashes. What is needed to debug this is the binary file, the .ctl file from just before the crash, and what keys to press to cause the crash.


=== HINTS AND TIPS ===

* Sometimes you have a binary of an unknown CPU type. It is very helpful to identify hex opcodes before disassembling so that you know which CPU type to select, and also to know where the hardware-defined entry points are. Sometimes even determining the base address of code can be difficult.

* Common endians, opcodes, and vectors for various CPUs:

LE 8080 - CD xx xx / C3 xx xx / C9 / F5 E5 D5 ... D1 E1 F1 / 11 xx xx / 21 xx xx
        - reset at 0000, vector entry points at 0008 0010 0018 0020 0028 0030 0038 0066
LE 6502 - A9 xx / 4C xx xx / 20 xx xx / 60
        - vector address words at FFFx
BE Z8   - D6 xx xx / 8D xx xx / AF
        - reset at 000C, vector address words at 0000-000B
LE 8048 - 02 xx xx / 12 xx xx / 83
        - reset at 0000, interrupt entry points at 0003 0007
BE 8051 - 02 xx xx / 12 xx xx / 20
        - reset at 0000, interrupt entry points at 0003 000B 0013 001B 0023
BE 6800 - BD xx xx / 7E xx xx / 39
        - vector address words at FFFx
BE 6809 - BD xx xx / 
        - vector address words at FFFx
BE 1802 - Dx / Cx xx xx / 70 / 3x xx / F8 xx By F8 xx Ay
BE 68000 - 4E56 0000 / 4E5E 4E75
         - vector address longwords at 0000-00FF
LE 8086 - return instructions C2 C3 CA CB / branch instructions 7xrr with rr F0-10

* CPUs without 16-bit load instructions are harder to work with because there are no register loads of full addresses. You can still put a label at the address, but the references will have to be manually replaced in the resulting .asm file. It is a good idea to put the reference in a comment.

* When you have subroutine calls followed by inline ASCII text or other non-code data that can't disassemble properly, one workaround is:

- use the search function to find one of the bytes of the call instruction ("/ db xxH")
- use "c" (lowercase) to convert the subroutine call to code
- repeat for all such calls
- code tracing will now automatically stop at the already disassembled subroutine call when tracing
- this is of course not as simple as it sounds


=== CHANGELOG ===

4.0.0 - 2022-05-27

Original version

4.1.0 - 2022-06-23

New features:
- Added support for user comments.
- 8051, 8048: added rip-stop for repeated 00H and FFH
- Command line input can now use left and right arrow keys.
- Tab stops are now saved to the .ctl file.

Bugs fixed:
- Fixed a possible crash when started when started with no filename.
- A7H in ASCII mode no longer produces " '''+80H "
- ORG line no longer shows a label
- 68HC11: fixed opcodes that were missed in a table update (18A6 etc.)
- The ')' command now clears the pre-LF attribute of added bytes.
- Fixed an infinite loop when search started from "END" line.
- Width of address/hex fields for search is now taken from tabs[] array.
- It is now possible to change tab stops.
- [ and ] commands will now skip past a pre-LF line.

4.2.0 - 2023-10-31

New features:
- added 68HC05 disassembler
- added ctrl-T command to trace at refaddr of current line
- added a minimal 8086 disassembler
- added a minimal PDP-11 disassembler
- added 8008 disassembler
- added Intel mnemonics for 8080 and 8085 disassembly
- added custom labels

Bugs fixed:
- 68HC11: fixed AIM/OIM/EIM/TIM instructions for 6303
- 6502: fixed some branch-always combinations
- F8: updated instruction definitions
- fixed a caching bug when deleting a label or comment

4.3.0 - 2024-07-18

New features:
- added 6301 to 68HC11 disassembler
- added ARM Thumb diassembler
- added 4004 disassembler
- added equates file support

Bugs fixed:
- ORG was only being generated with a 16-bit address
- 68HC11: ASLD was incorrectly being recognized for 6800/6802/6808
- 68HC11: ABY instruction was not recognized
- 8048: hints now affect bank choice for long JMP/CALL

4.4.0 - 2025-12-03

New features:
- add support for NS405 CPU (8048 variant)
- add Signetics 2650 disassembler
- add Motorola 68HC12 disassembler
- add octal object code output to make PDP-11 look right
- add TI 9900 disassembler
- zero-page labels support for 68HC11, 6809, 6502, 68HC05, 2650
- added hint to disable references for DW, DRW, DL, DRL
- support for wide-word architectures
- added Data General Nova disassembler
- added CP1610 disassembler
- added IMP-16 disassembler
- added SC/MP disassembler
- added 68HC16 disassembler
- 68K: added initial 68020 support
- added new 'E' command for byte offset tables, renamed 'o' command to 'e'

Bugs fixed:
- reset hint flags when changing instr type
- Z80: fix Intel 8080 opcode table
- fixed pointer use-after-free bug in comments/labels code
- PIC 14-bit was completely wrong
- tracing code already marked as data did not clear the continuation flag
- 8086: fixed a lot of problems

================
