In Turbo Debugger (TD.EXE) the F8 "F8 step" will execute the loop
completely, until the cx
becomes zero (you can even create infinite loop by updating cx
back to some value, preventing it from reaching the 1 -> 0 step).
To get "single-step" out of the loop
instruction, use the F7 "F7 trace" - that will cause the cx
to go from 6 to 5, and the code pointer will follow the jump back on the start of the loop.
About some other issues of your code:
MOV SP,STRING_LENGTH
DEC SP
MOV STRING_LENGTH,SP
sp
is not general purpose register, don't use it for calculation like this. Whenever some instruction does use stack implicitly (push, pop, call, ret, ...
), the values are being written and read in memory area addressed by the ss:sp
register pair, so by manipulating the sp
value you are modifying the current "stack".
Also in 16 bit x86 real mode all the interrupts (keyboard, timer, ...), when they occur, the current state of flag register and code address is stored into stack, before giving the control to the interrupt handler code, which usually will push additional values to the stack, so whatever is in memory on addresses below current ss:sp
is not safe in 16 bit x86 real mode, and the memory content keeps "randomly" changing there by all the interrupts being executed meanwhile (the TD.EXE itself does use part of this stack memory after every single step).
For arithmetic use other registers, not sp
. Once you will know enough about "stack", you will understand what kind of sp
manipulation is common and why (like sub sp,40
at beginning of function which needs additional "local" memory space), and how to restore stack back into expected state.
One more thing about that:
MOV SP,STRING_LENGTH
DEC SP
MOV STRING_LENGTH,SP
The STRING_LENGTH
is defined by EQU
, which makes it compile time constant, and only compile time. It's not "variable" (memory allocation), contrary to the things like someLabel dw 1345
, which cause the assembler to emit two bytes with values 0100_0001B, 0000_0101B
(when read as 16 bit word in little-endian way, that's value 1345 encoded), and the first byte address has symbolic name someLabel
, which can be used in further instructions, like dec word ptr [someLabel]
to decrement that value in memory from 1345 to 1344 during runtime.
But EQU
is different, it assigns the symbol STRING_LENGTH
final value, like 14.
So your code can be read as:
mov sp,14 ; makes almost sense, (practically destroys stack setup)
dec sp ; still valid
mov 14,sp ; doesn't make any sense, constant can't be destination for MOV