汇编 8086 TASM - 0Ah 21h 记住最后一个条目
Assembly 8086 TASM - 0Ah 21h remembers last entry
所以我正在编写一个 uni 作业 - 一个减去两个输入的小数(最多 10 个字符 ea)的程序。第一次迭代按预期工作。但是,当我重新启动程序时,由于某种原因,第二个操作数被记住了。
输入它的提示确实出现了,但随后被跳过,就好像我已经输入了一些东西——事实上,我在第一次迭代中输入了同样的东西。
问题是:为什么会发生,我该如何解决?第一个提示正确工作。
提示在INPUT_2下:
.model small
.386
stack 100h
dataseg
inputMsg1 db 0Ah, 0Dh, 'Enter first operand', 0Ah, 0Dh, '$'
inputMsg2 db 0Ah, 0Dh, 'Enter second operand', 0Ah, 0Dh, '$'
inputMax1 db 11
inputLen1 db ?
input1 db 12 dup(?)
input1Packd db 5 dup(0)
inputMax2 db 11
inputLen2 db ?
input2 db 12 dup(?)
input2Packd db 5 dup(0)
packMode db 0 ;Режим упаковки: 1 - первая цифра, 2 - вторая
resMsg db 0Ah, 0Dh, 'Result: $'
res db 9 dup(' '),'$'
retryMsg db 0Ah, 0Dh
db 'Press Any Key to continue, ESC to quit'
db '$'
errorMsg db 0Ah, 0Dh, 'Something went wrong. Try again$'
codeseg
START:
startupcode
jmp INPUT_1
INPUT_1_ERROR:
lea DX, errorMsg
mov AH, 09h
int 21h
INPUT_1:
lea DX, inputMsg1
mov AH, 09h
int 21h
lea DX, inputMax1
mov AH, 0Ah
int 21h
cmp inputLen1, 0
jz INPUT_1_ERROR
INPUT_1_PROCESS:
lea BX, input1
lea DX, input1Packd
xor CX, CX
mov CL, inputLen1
mov SI, CX
dec SI
mov DI, 4
INPUT_1_LOOP:
mov AL, [BX][SI]
cmp AL, '0'
jb INPUT_1_ERROR
cmp AL, '9'
ja INPUT_1_ERROR
and AL, 0Fh
mov AH, packMode
cmp AH, 0
jnz INPUT_1_PACK_SECOND
INPUT_1_PACK_FIRST:
inc AH
push BX
mov BX, DX
mov [BX][DI], AL
pop BX
jmp INPUT_1_PACK_FINISHED
INPUT_1_PACK_SECOND:
dec AH
shl AL, 4
push BX
mov BX, DX
or [BX][DI], AL
pop BX
dec DI
INPUT_1_PACK_FINISHED:
mov packMode, AH
dec SI
loop INPUT_1_LOOP
mov packMode, 0
jmp INPUT_2
INPUT_2_ERROR:
lea DX, errorMsg
mov AH, 09h
int 21h
INPUT_2:
lea DX, inputMsg2
mov AH, 09h
int 21h
lea DX, inputMax2
mov AH, 0Ah
int 21h
cmp inputLen2, 0
jz INPUT_2_ERROR
INPUT_2_PROCESS:
lea BX, input2
lea DX, input2Packd
xor CX, CX
mov CL, inputLen2
mov SI, CX
dec SI
mov DI, 4
INPUT_2_LOOP:
mov AL, [BX][SI]
cmp AL, '0'
jb INPUT_2_ERROR
cmp AL, '9'
ja INPUT_2_ERROR
and AL, 0Fh
mov AH, packMode
cmp AH, 0
jnz INPUT_2_PACK_SECOND
INPUT_2_PACK_FIRST:
inc AH
push BX
mov BX, DX
mov [BX][DI], AL
pop BX
jmp INPUT_2_PACK_FINISHED
INPUT_2_PACK_SECOND:
dec AH
shl AL, 4
push BX
mov BX, DX
or [BX][DI], AL
pop BX
dec DI
INPUT_2_PACK_FINISHED:
mov packMode, AH
dec SI
loop INPUT_2_LOOP
MATH_SETUP:
mov SI, 4
mov CX, 4
mov DI, 7
MATH:
lea BX, input1Packd
mov AL, [BX][SI]
lea BX, input2Packd
mov AH, [BX][SI]
sbb AL, AH
pushf
das
dec SI
mov AH, AL
lea BX, res
and AL, 0Fh
or AL, 30h
mov [BX][DI], AL
dec DI
shr AH, 4
or AH, 30h
mov [BX][DI], AH
dec DI
popf
loop MATH
lea BX, res
mov CX, 7
mov SI, 0
SHORTEN:
mov AL, [BX][SI]
cmp AL, '0'
jnz WRAPUP
inc SI
loop SHORTEN
WRAPUP:
push CX
lea DX, resMsg
mov AH, 09h
int 21h
lea DX, res
pop CX
cmp CX, 0
jz SKIP_SHORTEN
PRINT_SHORTEN:
add DX, 7
sub DX, CX
jmp FINISH_SHORTEN
SKIP_SHORTEN:
add DX, 6
FINISH_SHORTEN:
mov AH, 09h
int 21h
lea DX, retryMsg
mov AH, 09h
int 21h
mov AH, 01h
int 21h
cmp AL, 1Bh
jz QUIT
lea BX, input1Packd
mov DX, 1
BCD_CLEANUP:
mov DI, 0
mov CX, 5
BCD_CLEANUP_LOOP:
mov [BX][DI], 0
inc DI
loop BCD_CLEANUP_LOOP
lea BX, input2Packd
cmp DX, 1
mov DX, 0
jz BCD_CLEANUP
jmp START
QUIT:
exitcode 0
end START
也欢迎任何更好的代码建议,但如果您没有问题的答案则不需要。
DOS 缓冲输入功能 0Ah 允许您在您提供的输入缓冲区的存储器 space 中拥有预设文本。有关此 DOS 功能的完整说明,请参阅 .
第一次您的程序 运行 的 inputLen1 和 inputLen2 字段由于您定义它们的方式而为空在源代码中使用 db ?
转换为零。
但是当你重新运行代码时就不再是这样了!长度仍然显示您在之前 运行 中得到的内容。在相同的输入缓冲区上再次调用函数 0Ah 之前,您需要将这两个字段清零。
mov DX, 0
jz BCD_CLEANUP
mov inputLen1, DL ;DL=0
mov inputLen2, DL ;DL=0
jmp START
MATH 循环有几个关于 CF
.
的问题
sbb al, ah
指令取决于进位标志中的值,但您忽略了确保它在此循环的第一次迭代中关闭。只需添加 clc
:
clc
MATH:
lea BX, input1Packd
mov AL, [BX][SI]
lea BX, input2Packd
mov AH, [BX][SI]
sbb AL, AH
das
指令消耗了从 sbb
指令获得的进位标志,但它是从 das
指令获得的进位标志您需要 preserve/restore 让它通过循环传播。
sbb AL, AH
das
pushf
...a program that subtracts two entered decimals (max 10 characters ea)...
如果您输入 9 或 10 个字符,则不会考虑那些最重要的数字,因为 MATH_SETUP 实际上将您限制为 8 个字符(这反过来这是一件好事,因为 res 缓冲区只有显示 8 个字符的空间)!
MATH_SETUP:
mov SI, 4 <-- Could permit 10 packed BCD digits
mov CX, 4 <-- Max 8 characters
mov DI, 7 <-- Max 8 characters
所以我正在编写一个 uni 作业 - 一个减去两个输入的小数(最多 10 个字符 ea)的程序。第一次迭代按预期工作。但是,当我重新启动程序时,由于某种原因,第二个操作数被记住了。 输入它的提示确实出现了,但随后被跳过,就好像我已经输入了一些东西——事实上,我在第一次迭代中输入了同样的东西。 问题是:为什么会发生,我该如何解决?第一个提示正确工作。
提示在INPUT_2下:
.model small
.386
stack 100h
dataseg
inputMsg1 db 0Ah, 0Dh, 'Enter first operand', 0Ah, 0Dh, '$'
inputMsg2 db 0Ah, 0Dh, 'Enter second operand', 0Ah, 0Dh, '$'
inputMax1 db 11
inputLen1 db ?
input1 db 12 dup(?)
input1Packd db 5 dup(0)
inputMax2 db 11
inputLen2 db ?
input2 db 12 dup(?)
input2Packd db 5 dup(0)
packMode db 0 ;Режим упаковки: 1 - первая цифра, 2 - вторая
resMsg db 0Ah, 0Dh, 'Result: $'
res db 9 dup(' '),'$'
retryMsg db 0Ah, 0Dh
db 'Press Any Key to continue, ESC to quit'
db '$'
errorMsg db 0Ah, 0Dh, 'Something went wrong. Try again$'
codeseg
START:
startupcode
jmp INPUT_1
INPUT_1_ERROR:
lea DX, errorMsg
mov AH, 09h
int 21h
INPUT_1:
lea DX, inputMsg1
mov AH, 09h
int 21h
lea DX, inputMax1
mov AH, 0Ah
int 21h
cmp inputLen1, 0
jz INPUT_1_ERROR
INPUT_1_PROCESS:
lea BX, input1
lea DX, input1Packd
xor CX, CX
mov CL, inputLen1
mov SI, CX
dec SI
mov DI, 4
INPUT_1_LOOP:
mov AL, [BX][SI]
cmp AL, '0'
jb INPUT_1_ERROR
cmp AL, '9'
ja INPUT_1_ERROR
and AL, 0Fh
mov AH, packMode
cmp AH, 0
jnz INPUT_1_PACK_SECOND
INPUT_1_PACK_FIRST:
inc AH
push BX
mov BX, DX
mov [BX][DI], AL
pop BX
jmp INPUT_1_PACK_FINISHED
INPUT_1_PACK_SECOND:
dec AH
shl AL, 4
push BX
mov BX, DX
or [BX][DI], AL
pop BX
dec DI
INPUT_1_PACK_FINISHED:
mov packMode, AH
dec SI
loop INPUT_1_LOOP
mov packMode, 0
jmp INPUT_2
INPUT_2_ERROR:
lea DX, errorMsg
mov AH, 09h
int 21h
INPUT_2:
lea DX, inputMsg2
mov AH, 09h
int 21h
lea DX, inputMax2
mov AH, 0Ah
int 21h
cmp inputLen2, 0
jz INPUT_2_ERROR
INPUT_2_PROCESS:
lea BX, input2
lea DX, input2Packd
xor CX, CX
mov CL, inputLen2
mov SI, CX
dec SI
mov DI, 4
INPUT_2_LOOP:
mov AL, [BX][SI]
cmp AL, '0'
jb INPUT_2_ERROR
cmp AL, '9'
ja INPUT_2_ERROR
and AL, 0Fh
mov AH, packMode
cmp AH, 0
jnz INPUT_2_PACK_SECOND
INPUT_2_PACK_FIRST:
inc AH
push BX
mov BX, DX
mov [BX][DI], AL
pop BX
jmp INPUT_2_PACK_FINISHED
INPUT_2_PACK_SECOND:
dec AH
shl AL, 4
push BX
mov BX, DX
or [BX][DI], AL
pop BX
dec DI
INPUT_2_PACK_FINISHED:
mov packMode, AH
dec SI
loop INPUT_2_LOOP
MATH_SETUP:
mov SI, 4
mov CX, 4
mov DI, 7
MATH:
lea BX, input1Packd
mov AL, [BX][SI]
lea BX, input2Packd
mov AH, [BX][SI]
sbb AL, AH
pushf
das
dec SI
mov AH, AL
lea BX, res
and AL, 0Fh
or AL, 30h
mov [BX][DI], AL
dec DI
shr AH, 4
or AH, 30h
mov [BX][DI], AH
dec DI
popf
loop MATH
lea BX, res
mov CX, 7
mov SI, 0
SHORTEN:
mov AL, [BX][SI]
cmp AL, '0'
jnz WRAPUP
inc SI
loop SHORTEN
WRAPUP:
push CX
lea DX, resMsg
mov AH, 09h
int 21h
lea DX, res
pop CX
cmp CX, 0
jz SKIP_SHORTEN
PRINT_SHORTEN:
add DX, 7
sub DX, CX
jmp FINISH_SHORTEN
SKIP_SHORTEN:
add DX, 6
FINISH_SHORTEN:
mov AH, 09h
int 21h
lea DX, retryMsg
mov AH, 09h
int 21h
mov AH, 01h
int 21h
cmp AL, 1Bh
jz QUIT
lea BX, input1Packd
mov DX, 1
BCD_CLEANUP:
mov DI, 0
mov CX, 5
BCD_CLEANUP_LOOP:
mov [BX][DI], 0
inc DI
loop BCD_CLEANUP_LOOP
lea BX, input2Packd
cmp DX, 1
mov DX, 0
jz BCD_CLEANUP
jmp START
QUIT:
exitcode 0
end START
也欢迎任何更好的代码建议,但如果您没有问题的答案则不需要。
DOS 缓冲输入功能 0Ah 允许您在您提供的输入缓冲区的存储器 space 中拥有预设文本。有关此 DOS 功能的完整说明,请参阅
第一次您的程序 运行 的 inputLen1 和 inputLen2 字段由于您定义它们的方式而为空在源代码中使用 db ?
转换为零。
但是当你重新运行代码时就不再是这样了!长度仍然显示您在之前 运行 中得到的内容。在相同的输入缓冲区上再次调用函数 0Ah 之前,您需要将这两个字段清零。
mov DX, 0
jz BCD_CLEANUP
mov inputLen1, DL ;DL=0
mov inputLen2, DL ;DL=0
jmp START
MATH 循环有几个关于 CF
.
sbb al, ah
指令取决于进位标志中的值,但您忽略了确保它在此循环的第一次迭代中关闭。只需添加clc
:clc MATH: lea BX, input1Packd mov AL, [BX][SI] lea BX, input2Packd mov AH, [BX][SI] sbb AL, AH
das
指令消耗了从sbb
指令获得的进位标志,但它是从das
指令获得的进位标志您需要 preserve/restore 让它通过循环传播。sbb AL, AH das pushf
...a program that subtracts two entered decimals (max 10 characters ea)...
如果您输入 9 或 10 个字符,则不会考虑那些最重要的数字,因为 MATH_SETUP 实际上将您限制为 8 个字符(这反过来这是一件好事,因为 res 缓冲区只有显示 8 个字符的空间)!
MATH_SETUP:
mov SI, 4 <-- Could permit 10 packed BCD digits
mov CX, 4 <-- Max 8 characters
mov DI, 7 <-- Max 8 characters