2022-12-11
Some more work on lDebug happened recently.
Another change inspired by (FreeDOS) Debug/X, the M commands were changed so as to detect the single-expression machine-type related M commands differently. This allows to use the dollar sign prefix for the first address of a memory move M command. (This prefix forces use of a segmented address with a 86 Mode segment instead of a selector in Protected Mode. It is accepted as a no-op while in Real/Virtual 86 Mode, including by non-DPMI lDebug builds.) The change in lDebug was initially specific to the dollar sign, but has since been replaced by a different method of detecting a single expression.
This consists of parsing an address, then branching to the machine-type M command if no length or end for the range follows. As the valid numeric values for machine-type M commands with a numeric expression all fit within 16 bits, this way of dispatching works for all valid possibilities. The machine-type M commands will then parse their parameter again, insuring not all address parameters are allowed.
The benefit is that other special address parameters, like lDebug's TAKEN
and NOTTAKEN
keywords, are automatically allowed as well, without specific detection of these in the M command dispatcher.
During debugging of the dpmimini example, lDebugX would disassemble an instruction in the 32-bit code segment as mov dword […], es
and list the referenced memory as a dword as well. However, the instruction did not actually access a dword. Additionally, in the example's source the instruction had an explicit word
size keyword. So what was going on?
A little research let us conclude that a mov
with a segreg operand and a memory operand always treats the memory operand as an m16
. An osize
prefix is allowed but ignored. The assembler should not accept an explicit dword
size specifier, and the disassembler should always treat the memory operand as a word-sized operand. (That is, including for the access variables and referenced memory display.)
Something that generally is only enabled in lDebugX builds is the support for debugger exception areas, which allows to display what code caused a fault in the debugger. This was inspired by (FreeDOS) Debug/X which started displaying a linebreak before the debugger exception messages if the fault happened while accessing referenced memory in the disassembler. Exception areas are a more general implementation of the same idea.
The next thing is two fixes and one extension to the expression evaluator. One fix is that the unary ?
operator (absolute value) will always set the type to unsigned. An extension is that there is now a CLR
operator, which is a bitwise AND
with the bitwise NOT of the right hand operator. This is intended to make it easier to clear flags in debugger variables, allowing to replace R var AND= ~flag
by R var CLR= flag
.
The final fix is allowing H a ?? b :: c
commands where the b
term is an expression containing a different operator. (This fix is specific to the H command due to its twofold operation mode.) The more significant work though was on commenting ?? ::
construct support in the evaluator as well as adding a debugging output mode (as a build option). The comments are not yet finished; in particular, there is one uncommented bit that was added in a revision noted as not being understood even when it was added originally.
The disassembler support for the 40-column friendly mode was changed to use two new DAO flags instead of two DCO6 flags. Of the two flags used formerly, one was the shared global "40-column mode" flag, used by the R, D, and E commands.
The disassembler also gained several flags that enable memory access in the referenced memory display (displaying current memory contents) and for simulating repeated string compare/scan instructions (for determining how much memory is read by these instructions, to set up the access variables). There already was a flag in one of the DCO variables to disable referenced memory display, but the new flag behaves a little differently. It will still display the accessed memory address, as this can be computed without the possibility of faulting.
As another part of the HP 95LX support, the D and U commands now read their default lengths from writable debugger variables. The defaults are the same as what was hardcoded before, that being 128 bytes in DEFAULTDLEN for the D commands and 32 bytes in DEFAULTULEN for the U command.
As a part of this work, the U command also gained the variable DEFAULTULINES. If nonzero, this takes precedence as the default length and specifies how many "lines" to display. (More on that later.) The support for an explicit LINES length had been added to the U command a while ago.
Finally, the D commands were modified to also support a lines length, both explicit and through the DEFAULTDLINES variable for default length (again taking effect if nonzero).
During that modification, it was explicitly documented that the header and trailer of a D command do not count towards the count of lines specified. Moreover, the count of lines isn't truly line-based. Rather, it dumps as much data as fits in the amount of lines specified. That comes with an exception: If the symbolic build is used then the additional lines added by displaying symbols do not count towards the lines count.
Consequently it was also documented that the U command with a specified lines length doesn't count towards the lines count any additional lines for an instruction needing multiple lines. This includes if the machine code is too long to fit in one line, or the needed machine notice doesn't fit in the same line as the instruction. (Both made much more common by the 40-column friendly mode, which will shorten the machine code display to 4 bytes per line and write trailing messages so that they end in the 39th column.)
Additionally, if the symbolic build is used, lines listing symbols within the disassembly also will not count towards the lines count. This needs to be documented yet.
These limits on the lines length for the U command aren't new, despite being documented only now. They are a consequence of not actually counting lines but rather instructions (or unused prefixes). It wouldn't be desirable to truncate a multi-line instruction halfway through. That is part of the reason for this design. The other part is the simplicity.
All in all, the way the lines lengths work is that they specify the minimum amount of lines to use, not the maximum. This is unlikely to change at this point, though a different mode could be added as an option later. Because of the problem of not truncating multi-line instructions, the other mode certainly wouldn't always use the lines length as a maximum count, though.