TASM中16位寄存器除法兼容Emu8086的实现方案问询
Alright, let's tackle this head-on—you're running into a well-known behavior gap between Emu8086 and strict assemblers like TASM when working with 16-bit division. Let's break down why this happens, then walk through compatible fixes and even a custom procedure to match Emu8086's logic.
First, let's recap the official 8086 hardware spec for 16-bit division:
The
DIV BXinstruction expects a 32-bit dividend stored in the combined registersDX:AX(DX holds the high 16 bits, AX the low 16 bits). After division, AX gets the quotient, DX gets the remainder.
Emu8086 adds a convenience shortcut that real 8086 hardware (and strict assemblers like TASM) don't: if you only load a value into AX and skip setting DX, Emu8086 automatically zeros out DX before executing DIV. It treats your 16-bit AX value as a 32-bit value 0:AX (with DX as 0) to simplify things for beginners.
TASM, however, strictly follows the hardware spec. If DX has uninitialized garbage data (or any non-zero value) when you run DIV BX, it uses that garbage as the high 16 bits of the dividend—leading to wrong results, or even a division-by-zero error if the combined value is invalid.
1. Manual DX Zeroing (Simplest & Most Standard)
The easiest fix is to explicitly zero out DX before running DIV BX. This works in both Emu8086 and TASM, and aligns with real hardware behavior:
; Load your dividend into AX MOV AX, 0x1234 ; Load your divisor into BX MOV BX, 0x0010 ; Critical step: zero DX to match Emu8086's implicit behavior XOR DX, DX ; More efficient than MOV DX, 0 ; Now execute division: DX:AX / BX → AX=quotient, DX=remainder DIV BX
After this, AX will hold the quotient, DX the remainder—exactly what you expected.
2. Custom Procedure to Emulate Emu8086's Logic
If you want to avoid typing XOR DX, DX every time, you can write a reusable procedure that replicates Emu8086's auto-zeroing behavior. This works seamlessly in TASM:
; Custom DIV16 procedure: ; - Input: AX = 16-bit dividend, BX = 16-bit divisor ; - Output: AX = quotient, DX = remainder ; - Preserves CX (adjust if you need to save other registers) DIV16 PROC PUSH CX ; Save CX to avoid overwriting it XOR DX, DX ; Emulate Emu8086's auto-zero of DX DIV BX ; Execute standard division POP CX ; Restore saved register RET DIV16 ENDP ; Example usage: MOV AX, 0x5678 ; Dividend MOV BX, 0x0020 ; Divisor CALL DIV16 ; Now AX=0x159 (345), DX=0x0018 (24)
Just call DIV16 instead of DIV BX, and it handles the DX zeroing for you—matching Emu8086's behavior in TASM.
- Emu8086's auto-zeroing of DX is a non-standard shortcut; real 8086 hardware and strict assemblers won't do this automatically.
- Always initialize DX before 16-bit division if you're using only AX as the dividend—this is the most portable approach.
- If you need to work with 32-bit dividends (DX:AX), you don't need to zero DX; just load the high 16 bits into DX and low into AX before running
DIV.
内容的提问来源于stack exchange,提问作者Guy Sudai

