Condition: jumps if SF = 1. SF is simply a copy of the top bit of the last result: bit 7 for a byte operation, bit 15 for a word. Read as a signed number, that means the result is negative. MOV does not set flags, so to ask about a value already in a register use TEST AX, AX or OR AX, AX first.
MOV AX, -1234TEST AX, AX ; flags from AX itself: SF = 1MOV DL, "Y" ; MOV leaves the flags aloneJS SHOW1 ; taken: DL stays "Y"MOV DL, "N"SHOW1:MOV AH, 02h ; DOS: print the character in DLINT 21h
SF is reliable as "the top bit is set", but not as "a < b" after a compare: if the subtraction overflowed, the sign is wrong. For signed comparisons use JL / JGE, which also look at OF. A handy non-arithmetic use: SHL AL, 1 moves bit 6 into the sign position, so the next JS tests that bit.
Range
On the 8086 JS exists only in the SHORT form: two bytes, opcode 78h and a signed 8-bit displacement counted from the end of the instruction. The target must lie within −128..+127 bytes of that point. To go farther, invert the test and hop over an unconditional JMP, which can reach the whole segment. MASM 6 makes this rewrite itself when it finds the target out of range (its default OPTION LJMP), so the listing may show two instructions where you wrote one.
JNS SKIP1 ; the opposite test, a short hopJMP FARAWAY ; any distance in the segmentSKIP1:
Later CPUs
The 80386 added a near form of every conditional jump, 0Fh 88h followed by a 16-bit displacement (32-bit in 32-bit code), so from the 386 on JS can reach anywhere in the segment. Code for the 8086 must stay with the short form.