User Tools

Site Tools


blog:pushbx:2024:0414_ldebug_work_in_mid_early_april

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

blog:pushbx:2024:0414_ldebug_work_in_mid_early_april [2024-04-14 18:21:16 +0200 Apr Sun] (current)
ecm created
Line 1: Line 1:
 +====== lDebug work in mid early April ======
 +
 +
 +**2024-04-14**
 +
 +===== Documentation or comment only changes =====
 +
 +  * isvariab.mac: [[https://hg.pushbx.org/ecm/ldebug/rev/4163f1edd258|Comment on structure and macro]]
 +  * expr.asm: [[https://hg.pushbx.org/ecm/ldebug/rev/0ed7f4ffdcd5|Note NC after addition]] didn't carry, needed to return success
 +  * expr.asm: [[https://hg.pushbx.org/ecm/ldebug/rev/b2f60d2a4d9d|Note that variable setup functions]] may CHG dx
 +  * amount.asm: Note that we use a ''mov cx, 0'' [[https://hg.pushbx.org/ecm/ldebug/rev/add0a0b6cf16|to preserve the Carry Flag]] (instead of the shorter ''xor'')
 +  * [[https://hg.pushbx.org/ecm/ldebug/rev/86c2e10a833d|Update news-r9]]: BL segment in PM fix, comma before length unit keyword
 +  * [[https://hg.pushbx.org/ecm/ldebug/rev/d03510ea167a|Add some variables to varref]] (IOK, IOI, DARESULT, XARESULT, DDTEXTAND, TRYAMISNUM, AMISNUM, TRYDEBUGNUM, DEBUGFUNC, COUNT, RHCOUNT, ELDAMOUNT, CIP, CSP)
 +  * [[https://hg.pushbx.org/ecm/ldebug/rev/275edbbf773b|Clarify that AMISNUM is stale]] if not currently in use
 +  * [[https://hg.pushbx.org/ecm/ldebug/rev/ecfe4418c5e7|Document COUNT command]] in manual
 +  * [[https://hg.pushbx.org/ecm/ldebug/rev/88a1c1ee3468|Document]] and [[https://hg.pushbx.org/ecm/ldebug/rev/5299a2bd1e11|rename to opt3_no_call_amis]] (doesn't call AMIS interface for INSTALL AREAS or to install a DPMI hook, either)
 +  * aa.asm: Replace some labels with more descriptive ones ([[https://hg.pushbx.org/ecm/ldebug/rev/58c00875d280|1]], [[https://hg.pushbx.org/ecm/ldebug/rev/7b5a902dc33f|2]], [[https://hg.pushbx.org/ecm/ldebug/rev/8ed98593190e|3]])
 +  * aa.asm: [[https://hg.pushbx.org/ecm/ldebug/rev/c40bd4d0c8e2|Comment more on ao41]]
 +  * [[https://hg.pushbx.org/ecm/ldebug/rev/bb8932363933|Update news-r9]] with DD assembly directive string overflow check, push ([[https://hg.pushbx.org/ecm/ldebug/rev/6adf0513f163|and pop]]) mem default operand size, and optimising imms8 or disp8 values that are specified as 16-bit positive values
 +
 +
 +===== Code changes =====
 +
 +  * [[https://hg.pushbx.org/ecm/ldebug/rev/73df226bbd11|Optimise register use]] in default_variable_setup, do not use si any longer and calculate element size in dx
 +  * aa.asm: [[https://hg.pushbx.org/ecm/ldebug/rev/6c2dc99168f1|in OP_SHOSIZ drop special handling of OP_IMM8]] (this was unused since v1.09)
 +  * aa.asm: [[https://hg.pushbx.org/ecm/ldebug/rev/fd56784c777b|Do not actually overflow line_out]] if DD directive is given string data that doesn't fit, detect the overflow before writing the data
 +  * aa.asm: [[https://hg.pushbx.org/ecm/ldebug/rev/28985f0d10cc|Clear two variables]] using a single ''and'' instruction with sign-extended zero
 +  * aa.asm: [[https://hg.pushbx.org/ecm/ldebug/rev/0bea73965b6c|Allow to assemble push and pop mem]] without a size
 +  * aa.asm: [[https://hg.pushbx.org/ecm/ldebug/rev/fb20703aede4|Optimise assembler skipping]] stack hinting operand types
 +  * aa.asm: Allow 16-bit positive values to be optimised to 8-bit sign-extended values if they fit, either in 16-bit ALU operations (first operand is an r/m16) ([[https://hg.pushbx.org/ecm/ldebug/rev/4482d9e1b15b|1]], [[https://hg.pushbx.org/ecm/ldebug/rev/c80cdd2a5ae8|2]]), in ''push imms8'' (16-bit CS) or ''pushw imms8'' (gets an o16 prefix in a 32-bit CS) ([[https://hg.pushbx.org/ecm/ldebug/rev/934daa14bccc|here]]), or [[https://hg.pushbx.org/ecm/ldebug/rev/def1e0cfa825|in the address displacement for an a16 address]] with one or two address registers.
 +
 +
 +===== In detail =====
 +
 +==== Push or pop memory without size ====
 +
 +I noticed that MSDebug doesn't require a specification of the operand size for a push or pop with an explicit memory operand. While it does accept the "word" or "word ptr" size specifier, it assembles the same without it. This is likely because it has no notion of 32-bit operands so the size can always be implied as word.
 +
 +I noticed that Debug/X changed its call, jmp, **and** push instructions [[https://hg.pushbx.org/ecm/fddebug/file/a1568c979ca8/LINEASM.INC#l1758|so as to do the equivalent of our OP_1632_DEFAULT]], but only in the assembler. This is done with a hack in ao13, which activates only for a (hardcoded) operand list index of 40. This is [[https://hg.pushbx.org/ecm/fddebug/file/a1568c979ca8/ASMTBL.INC#l50|the "OP_1632+OP_RM" operand list]].
 +
 +There are several problems with this approach in Debug/X:
 +
 +  * The operand list index number is hardcoded, thus fragile
 +  * The hack is only in the assembler, thus the disassembler will always display the size (I found this desirable for push in lDebug, but not for call or jmp)
 +  * The pop mem instruction uses a different operand list, hence its size must be specified
 +  * The push imm instruction can make use of lDebug's OP_1632_DEFAULT as well
 +
 +The lDebug approach to push and pop with memory operand is instead to use another new operand size type, OP_1632_DEFAULT_ASM. This allows a default size in the assembler if none is specified. However, the disassembler will always display the size. Unlike this, the disassembler will omit the default size for call and jmp (far or near) as well as push imm.
 +
 +MSDebug also omits the size for call and jmp (alike lDebug) but also for push and pop (unlike lDebug). This is because of how there is no non-default size for push and pop in MSDebug. In lDebug, disassembly of push and pop will continue to display a word size even if the disassembler could omit it. (Perhaps a new Debugger Assembler Option flag is in order?)
 +
 +
 +==== Optimising 16-bit immediates and displacements ====
 +
 +The FreeDOS Debug/X and lDebug assembler would not optimise positive 16-bit immediates to negative sign-extended 8-bit immediates when the values would allow this. The problem was that the assembler checked for sign extension to 32-bits, requiring either a negative value (-1) or a 32-bit positive value (FFFF_FFFF).
 +
 +Reported on stackexchange:
 +
 +<blockquote>I got misled by FreeDOS DEBUG, which didn’t use that encoding when
 +I wrote ''adc dx, ffff''. Now that I checked, ''adc dx, -1'' does
 +trigger it, and the former does as well in MS-DOS DEBUG.
 +<cite>[[https://retrocomputing.stackexchange.com/questions/29805/what-does-an-adc-add-with-carry-instruction-following-add-do?noredirect=1#comment105758_29805|comment by user3840170]]</cite></blockquote>
 +
 +MSDebug never had this problem because it only ever supported 16-bit immediates, so its sign extension check presumably always operates on 16 bits.
 +
 +Four different classes of this missed optimisation were identified:
 +
 +  * ''adc dx, FFFF'' ([[https://hg.pushbx.org/ecm/ldebug/rev/4482d9e1b15b|ALU operation with r/m16 and imms8]])
 +  * ''imul dx, dx, FFFF'' or ''imul dx, FFFF'' ([[https://hg.pushbx.org/ecm/ldebug/rev/c80cdd2a5ae8|3- or 2-operand imul with r16 destination and imms8]])
 +  * ''push FFFF'' (16-bit CS only) or ''pushw FFFF'' (o16 [[https://hg.pushbx.org/ecm/ldebug/rev/934daa14bccc|push imms8]])
 +  * ''mov dx, [bx + FFFF]'' ([[https://hg.pushbx.org/ecm/ldebug/rev/def1e0cfa825|a16 disp8 with one or two address registers]])
 +
 +Several changesets addressed each class in turn. This seems to handle all cases of the problematic sign extension checks.
 +
 +Some problems remain: The ALU, imul, or push cases will accept FFFF_FFFF same as if -1 was specified. The displacement correctly rejects FFFF_FFFF while allowing -1. This requires more study. (Do note that numbers can be specified using the expression evaluator by surrounding the expression with round parentheses. It may be desirable to accept ''+(-1)'' the same as ''-1''.)
 +
 +The actual implementation of each of the checks is done as follows:
 +
 +If OP_IMMS8 is not the first operand, [[https://hg.pushbx.org/ecm/ldebug/file/6adf0513f163/source/aa.asm#l2509|and the first operand is known to have a SIZ_WORD]], then [[https://hg.pushbx.org/ecm/ldebug/file/6adf0513f163/source/aa.asm#l2513|accept sign-extension if high word is zero]] (thus allowing positive 16-bit values). (This catches the ALU and imul cases.)
 +
 +[[https://hg.pushbx.org/ecm/ldebug/file/6adf0513f163/source/aa.asm#l2493|If OP_IMMS8 is the first operand]], and [[https://hg.pushbx.org/ecm/ldebug/file/6adf0513f163/source/aa.asm#l2500|there is a W suffix]] to the mnemonic (detected from OP_SHOSIZ's setting of ''byte [opsize]''), likewise accept sign-extension if high word is zero. (This catches the pushw case.)
 +
 +If OP_IMMS8 is the first operand, and there is no D suffix, [[https://hg.pushbx.org/ecm/ldebug/file/6adf0513f163/source/aa.asm#l2502|and the CS D-bit is clear (16-bit CS)]], accept sign-extension if high word is zero. (This catches the push case without a suffix in a 16-bit CS.)
 +
 +If there is [[https://hg.pushbx.org/ecm/ldebug/file/6adf0513f163/source/aa.asm#l1447|a ModR/M memory addressing mode being assembled, and there are one or two 16-bit address registers]] (no a32), then accept sign-extension if the high word of the displacement is zero.
 +
 +In all of these cases, sign-extension with the sign bit cleared automatically passes the new check as well because in that case the high word must be zero too.
 +
 +Also, the OP_IMM8 operand type (eg int, out, in, shifts and rotates) only wants to check for zero-extension. This does not need to be handled specifically because the special casing will just possibly check for a zero high word in a redundant way, which always correctly handles the zero-extension case.
 +
 +{{tag>ldebug fddebug msdebug}}
 +
 +
 +~~DISCUSSION~~
  
blog/pushbx/2024/0414_ldebug_work_in_mid_early_april.txt · Last modified: 2024-04-14 18:21:16 +0200 Apr Sun by ecm