Assembly · In the CV
Table Builder and Sorter in 8086 Assembly
Wrote a program that builds a data table from user input and sorts it by any column.
- 8086 Assembly
- DOS interrupts (INT 21h)
About
Assembly code for the 8086 emulator that builds a table of 1 to 10 columns and 1 to 50 rows, which can be sorted right after it is created. Numeric data is sorted in descending order and text data in ascending order.
Source code
tablesort.asm
.MODEL SMALL
.STACK 100H
.DATA
MAX_ROWS EQU 50
MAX_COLS EQU 10
CELL_SIZE EQU 9 ; 8 bytes + 1 for '$' terminator
MSG_WELCOME DB 13,10,'=== TABLE MANAGEMENT SYSTEM ===',13,10,'$'
MSG_COL_COUNT DB 13,10,'Enter number of columns (1-10): $'
MSG_ROW_COUNT DB 13,10,'Enter number of rows (1-50): $'
MSG_COL_NAME DB 13,10,'Enter name for column $'
MSG_COL_TYPE DB '=> Type (S)tring or (N)umeric? $'
MSG_ROW_DATA DB 13,10,'=== Enter Row Data ===',13,10,'$'
MSG_CELL_PROMPT DB 13,10,'Enter value for cell $'
ERR_INVALID_TYPE DB 13,10,'ERROR: Invalid type! Use S or N',13,10,'$'
ERR_EMPTY_CELL DB 13,10,'ERROR: Cell cannot be empty!',13,10,'$'
MSG_DISPLAY DB 13,10,'=== CURRENT TABLE ===',13,10,'$'
ERR_INVALID_NUM DB 13,10,'ERROR: Invalid number! Please try again.',13,10,'$'
MSG_SORT_PROMPT DB 13,10,'Enter column number to sort (1-$'
MSG_SORTED DB 13,10,'=== SORTED TABLE ===',13,10,'$'
SPACER DB ' | $'
NEWLINE DB 13,10,'$'
DASH_LINE DB '-------------------------------------------------',13,10,'$'
COLON_SPACE DB ': $'
CLOSE_PAREN DB '): $'
DOT DB '.$'
COL_TYPES DB MAX_COLS DUP(0) ; 0 = numeric, 1 = string
COL_NAMES DB MAX_COLS * CELL_SIZE DUP('$') ; Column names storage
TABLE_DATA DB MAX_ROWS * MAX_COLS * CELL_SIZE DUP('$') ; Table data storage
TEMP_BUFFER DB CELL_SIZE DUP(0) ; Temporary buffer
INPUT_BUFFER DB 10 DUP(0) ; Input buffer for numbers
ROW_SIZE DW 0 ; Size of each row in bytes
NUM_COLS DB 0 ; Number of columns
NUM_ROWS DB 0 ; Number of rows
CURRENT_COL DB 0 ; Current column index
CURRENT_ROW DB 0 ; Current row index
SORT_COL DB 0 ; Column to sort by
.CODE
MAIN PROC
MOV AX, @DATA
MOV DS, AX
MOV ES, AX
LEA DX, MSG_WELCOME ; Display welcome message
MOV AH, 09H
INT 21H
; Get user input and process data
CALL GET_COLUMN_COUNT
CALL GET_COLUMN_METADATA
CALL GET_ROW_COUNT
CALL INPUT_TABLE_DATA
; Display initial table
LEA DX, MSG_DISPLAY
MOV AH, 09H
INT 21H
CALL DISPLAY_TABLE
CALL SORT_TABLE_HANDLER ; Handle sorting and display sorted table
; Exit program
MOV AH, 4CH
INT 21H
MAIN ENDP
GET_COLUMN_COUNT PROC
GET_COL_RETRY:
; Prompt for column count
LEA DX, MSG_COL_COUNT
MOV AH, 09H
INT 21H
; Get number input
CALL GET_NUMBER_INPUT
CMP AX, 1
JB GET_COL_INVALID
CMP AX, MAX_COLS
JA GET_COL_INVALID
; Store valid column count
MOV NUM_COLS, AL
LEA DX, NEWLINE
MOV AH, 09H
INT 21H
RET
GET_COL_INVALID:
; Handle invalid input
LEA DX, ERR_INVALID_NUM
MOV AH, 09H
INT 21H
JMP GET_COL_RETRY
GET_COLUMN_COUNT ENDP
GET_COLUMN_METADATA PROC
MOV CURRENT_COL, 0
COL_META_LOOP:
; Loop through columns
MOV AL, CURRENT_COL
CMP AL, NUM_COLS
JAE COL_META_DONE
; Display column number prompt
LEA DX, MSG_COL_NAME
MOV AH, 09H
INT 21H
; Display current column number
MOV AL, CURRENT_COL
ADD AL, '1'
MOV DL, AL
MOV AH, 02H
INT 21H
LEA DX, COLON_SPACE
MOV AH, 09H
INT 21H
; Get column name
CALL CALCULATE_COL_NAME_ADDR
MOV DI, BX
CALL GET_STRING_INPUT
TYPE_RETRY:
; Get column type
LEA DX, MSG_COL_TYPE
MOV AH, 09H
INT 21H
; Read character and convert to uppercase
MOV AH, 01H
INT 21H
CMP AL, 'a'
JB CHECK_TYPE
CMP AL, 'z'
JA CHECK_TYPE
SUB AL, 32
CHECK_TYPE:
; Validate type input
CMP AL, 'S'
JE SET_STRING_TYPE
CMP AL, 'N'
JE SET_NUMERIC_TYPE
; Invalid type handling
LEA DX, ERR_INVALID_TYPE
MOV AH, 09H
INT 21H
JMP TYPE_RETRY
SET_STRING_TYPE:
; Set column as string type
MOV AL, CURRENT_COL
XOR AH, AH
MOV BX, OFFSET COL_TYPES
ADD BX, AX
MOV BYTE PTR [BX], 1
LEA DX, NEWLINE
MOV AH, 09H
INT 21H
JMP NEXT_COL_META
SET_NUMERIC_TYPE:
; Set column as numeric type
MOV AL, CURRENT_COL
XOR AH, AH
MOV BX, OFFSET COL_TYPES
ADD BX, AX
MOV BYTE PTR [BX], 0
LEA DX, NEWLINE
MOV AH, 09H
INT 21H
NEXT_COL_META:
; Move to next column
INC CURRENT_COL
JMP COL_META_LOOP
COL_META_DONE:
RET
GET_COLUMN_METADATA ENDP
GET_ROW_COUNT PROC
GET_ROW_RETRY:
; Prompt for row count
LEA DX, MSG_ROW_COUNT
MOV AH, 09H
INT 21H
; Get number input
CALL GET_NUMBER_INPUT
CMP AX, 1
JB GET_ROW_INVALID
CMP AX, MAX_ROWS
JA GET_ROW_INVALID
; Store valid row count
MOV NUM_ROWS, AL
LEA DX, NEWLINE
MOV AH, 09H
INT 21H
RET
GET_ROW_INVALID:
; Handle invalid row count
LEA DX, ERR_INVALID_NUM
MOV AH, 09H
INT 21H
JMP GET_ROW_RETRY
GET_ROW_COUNT ENDP
INPUT_TABLE_DATA PROC
MOV CURRENT_ROW, 0
ROW_INPUT_LOOP:
; Loop through rows
MOV AL, CURRENT_ROW
CMP AL, NUM_ROWS
JAE INPUT_DATA_COMPLETE
; Display row header
LEA DX, MSG_ROW_DATA
MOV AH, 09H
INT 21H
; Display row number
LEA DX, DOT
MOV AH, 09H
INT 21H
MOV AL, CURRENT_ROW
INC AL
CALL PRINT_NUMBER
LEA DX, NEWLINE
MOV AH, 09H
INT 21H
MOV CURRENT_COL, 0
COL_INPUT_LOOP:
; Loop through columns
MOV AL, CURRENT_COL
CMP AL, NUM_COLS
JAE ROW_INPUT_COMPLETE
; Display cell prompt
LEA DX, MSG_CELL_PROMPT
MOV AH, 09H
INT 21H
; Display column letter
MOV AL, CURRENT_COL
ADD AL, 'A'
MOV DL, AL
MOV AH, 02H
INT 21H
MOV DL, ' '
MOV AH, 02H
INT 21H
; Display column name
MOV DL, '('
INT 21H
CALL CALCULATE_COL_NAME_ADDR
MOV DX, BX
MOV AH, 09H
INT 21H
MOV DL, ')'
MOV AH, 02H
INT 21H
LEA DX, COLON_SPACE
MOV AH, 09H
INT 21H
; Calculate cell address
CALL CALCULATE_CELL_ADDR
MOV DI, BX
; Check column type and get appropriate input
MOV AL, CURRENT_COL
XOR AH, AH
MOV BX, OFFSET COL_TYPES
ADD BX, AX
CMP BYTE PTR [BX], 0
JE INPUT_NUMERIC_CELL
; String input
CALL GET_STRING_INPUT
JMP NEXT_COL_INPUT
INPUT_NUMERIC_CELL:
; Numeric input
CALL GET_NUMERIC_INPUT
NEXT_COL_INPUT:
; Next column
INC CURRENT_COL
JMP COL_INPUT_LOOP
ROW_INPUT_COMPLETE:
; Next row
INC CURRENT_ROW
JMP ROW_INPUT_LOOP
INPUT_DATA_COMPLETE:
RET
INPUT_TABLE_DATA ENDP
DISPLAY_TABLE PROC
; Display table header and rows
CALL PRINT_TABLE_HEADER
CALL PRINT_TABLE_ROWS
RET
DISPLAY_TABLE ENDP
PRINT_TABLE_HEADER PROC
; Print top border
LEA DX, DASH_LINE
MOV AH, 09H
INT 21H
MOV CURRENT_COL, 0
HEADER_LOOP:
; Loop through columns to print headers
MOV AL, CURRENT_COL
CMP AL, NUM_COLS
JAE HEADER_COMPLETE
; Print spacer
LEA DX, SPACER
MOV AH, 09H
INT 21H
; Print column name
CALL CALCULATE_COL_NAME_ADDR
MOV DX, BX
MOV AH, 09H
INT 21H
; Next column
INC CURRENT_COL
JMP HEADER_LOOP
HEADER_COMPLETE:
; Complete header line
LEA DX, SPACER
MOV AH, 09H
INT 21H
LEA DX, NEWLINE
MOV AH, 09H
INT 21H
RET
PRINT_TABLE_HEADER ENDP
PRINT_TABLE_ROWS PROC
MOV CURRENT_ROW, 0
PRINT_ROW_LOOP:
; Loop through rows
MOV AL, CURRENT_ROW
CMP AL, NUM_ROWS
JAE PRINT_ROWS_COMPLETE
; Print row separator
LEA DX, DASH_LINE
MOV AH, 09H
INT 21H
MOV CURRENT_COL, 0
PRINT_COL_LOOP:
; Loop through columns
MOV AL, CURRENT_COL
CMP AL, NUM_COLS
JAE PRINT_ROW_COMPLETE
; Print spacer
LEA DX, SPACER
MOV AH, 09H
INT 21H
; Get cell address
CALL CALCULATE_CELL_ADDR
MOV DI, BX
; Check column type for display formatting
MOV AL, CURRENT_COL
XOR AH, AH
MOV BX, OFFSET COL_TYPES
ADD BX, AX
CMP BYTE PTR [BX], 0
JE PRINT_NUMERIC_CELL
; Print string cell
MOV DX, DI
MOV AH, 09H
INT 21H
JMP NEXT_PRINT_COL
PRINT_NUMERIC_CELL:
; Print numeric cell
MOV DX, DI
MOV AH, 09H
INT 21H
NEXT_PRINT_COL:
; Next column
INC CURRENT_COL
JMP PRINT_COL_LOOP
PRINT_ROW_COMPLETE:
; Complete row line
LEA DX, SPACER
MOV AH, 09H
INT 21H
LEA DX, NEWLINE
MOV AH, 09H
INT 21H
; Next row
INC CURRENT_ROW
JMP PRINT_ROW_LOOP
PRINT_ROWS_COMPLETE:
; Print bottom border
LEA DX, DASH_LINE
MOV AH, 09H
INT 21H
RET
PRINT_TABLE_ROWS ENDP
SORT_TABLE_HANDLER PROC
; Prompt for sort column
LEA DX, MSG_SORT_PROMPT
MOV AH, 09H
INT 21H
; Display valid column range
MOV AL, NUM_COLS
CALL PRINT_NUMBER
LEA DX, CLOSE_PAREN
MOV AH, 09H
INT 21H
SORT_INPUT_RETRY:
; Get sort column input
CALL GET_NUMBER_INPUT
CMP AX, 1
JB SORT_INPUT_INVALID
CMP AL, NUM_COLS
JA SORT_INPUT_INVALID
; Store sort column (0-indexed)
DEC AL
MOV SORT_COL, AL
LEA DX, NEWLINE
MOV AH, 09H
INT 21H
; Perform sorting
CALL BUBBLE_SORT
; Display sorted table
LEA DX, MSG_SORTED
MOV AH, 09H
INT 21H
CALL DISPLAY_TABLE
RET
SORT_INPUT_INVALID:
; Handle invalid sort column
LEA DX, ERR_INVALID_NUM
MOV AH, 09H
INT 21H
JMP SORT_INPUT_RETRY
SORT_TABLE_HANDLER ENDP
BUBBLE_SORT PROC
; Calculate row size (columns * cell size)
MOV AL, NUM_COLS
MOV BL, CELL_SIZE
MUL BL
MOV ROW_SIZE, AX
; Check if only one row
MOV CL, NUM_ROWS
DEC CL
JZ SORT_DONE ; Only one row - nothing to sort
SORT_OUTER:
; Initialize swap flag and inner counter
MOV DL, 0 ; Swap flag = false
MOV CH, 0 ; Inner index = 0
SORT_INNER:
; Check inner loop condition
CMP CH, CL
JAE CHECK_SWAP ; End of inner loop
; Calculate addresses for current and next row
MOV CURRENT_ROW, CH
MOV AL, SORT_COL
MOV CURRENT_COL, AL
CALL CALCULATE_CELL_ADDR
MOV SI, BX ; First cell
MOV AL, CH
INC AL
MOV CURRENT_ROW, AL
CALL CALCULATE_CELL_ADDR
MOV DI, BX ; Second cell
; Check column type for comparison
MOV AL, SORT_COL
XOR AH, AH
MOV BX, OFFSET COL_TYPES
ADD BX, AX
CMP BYTE PTR [BX], 0
JE COMPARE_NUMERIC
; String comparison (ascending order)
PUSH CX ; Save row counter
CALL COMPARE_STRINGS
POP CX ; Restore row counter
CMP AX, 0
JG DO_SWAP ; Swap if first > second (for ascending)
JMP NO_SWAP_NEEDED
COMPARE_NUMERIC:
; Convert strings to integers
PUSH SI
CALL STRING_TO_INT_SI
MOV BP, AX ; Store first value
POP SI
PUSH DI
MOV SI, DI
CALL STRING_TO_INT_SI
MOV BX, AX ; Store second value
POP DI
; For descending order: swap if first < second
CMP BP, BX
JGE NO_SWAP_NEEDED ; Jump if first >= second (no swap needed)
DO_SWAP:
PUSH CX ; Save row counter
CALL SWAP_TABLE_ROWS
POP CX ; Restore row counter
MOV DL, 1 ; Set swap flag
NO_SWAP_NEEDED:
; Next comparison
INC CH
JMP SORT_INNER
CHECK_SWAP:
; Check if any swaps occurred
CMP DL, 0
JE SORT_DONE ; Exit if no swaps
DEC CL
JNZ SORT_OUTER ; Continue while CL > 0
SORT_DONE:
RET
BUBBLE_SORT ENDP
; ========== UTILITY PROCEDURES ============
GET_NUMBER_INPUT PROC
PUSH BX
PUSH CX
PUSH DX
PUSH SI
; Set up input buffer
LEA SI, INPUT_BUFFER
MOV CX, 0 ; Character count
NUMBER_INPUT_LOOP:
; Read character
MOV AH, 01H
INT 21H
; Check for Enter key
CMP AL, 13
JE NUMBER_INPUT_DONE
; Check for Backspace
CMP AL, 8
JE NUMBER_BACKSPACE
; Validate digit
CMP AL, '0'
JB NUMBER_INPUT_LOOP
CMP AL, '9'
JA NUMBER_INPUT_LOOP
; Check buffer limit
CMP CX, 5 ; Max 5 digits
JAE NUMBER_INPUT_LOOP
; Store digit and increment counters
MOV [SI], AL
INC SI
INC CX
JMP NUMBER_INPUT_LOOP
NUMBER_BACKSPACE:
; Handle backspace
CMP CX, 0
JE NUMBER_INPUT_LOOP
DEC SI
DEC CX
; Erase character from display
MOV DL, 8
MOV AH, 02H
INT 21H
MOV DL, ' '
INT 21H
MOV DL, 8
INT 21H
JMP NUMBER_INPUT_LOOP
NUMBER_INPUT_DONE:
; Check for empty input
CMP CX, 0
JE NUMBER_INVALID
; Convert string to number
LEA SI, INPUT_BUFFER
XOR AX, AX
XOR DX, DX
CONVERT_LOOP:
; Process each digit
CMP CX, 0
JE CONVERT_DONE
MOV BL, [SI]
SUB BL, '0'
XOR BH, BH
; AX = AX * 10 + BX
MOV DX, 10
MUL DX
ADD AX, BX
; Next digit
INC SI
DEC CX
JMP CONVERT_LOOP
CONVERT_DONE:
; Restore registers and return
POP SI
POP DX
POP CX
POP BX
RET
NUMBER_INVALID:
; Return 0 for invalid input
MOV AX, 0
POP SI
POP DX
POP CX
POP BX
RET
GET_NUMBER_INPUT ENDP
CALCULATE_COL_NAME_ADDR PROC
; Calculate column name address: col_index * cell_size
MOV AL, CURRENT_COL
MOV AH, CELL_SIZE
MUL AH
MOV BX, OFFSET COL_NAMES
ADD BX, AX
RET
CALCULATE_COL_NAME_ADDR ENDP
; FIXED CELL ADDRESS CALCULATION
CALCULATE_CELL_ADDR PROC
; Calculate cell address: (row * num_cols + col) * cell_size
MOV AL, CURRENT_ROW
XOR AH, AH ; Clear AH for 16-bit multiplication
MOV DL, NUM_COLS
XOR DH, DH ; DX = NUM_COLS
MUL DX ; AX = row_index * num_cols
MOV DL, CURRENT_COL
XOR DH, DH ; DX = col_index
ADD AX, DX ; AX = row_index * num_cols + col_index
MOV DX, CELL_SIZE ; DX = 9
MUL DX ; DX:AX = AX * 9 (use full 16-bit multiplication)
MOV BX, OFFSET TABLE_DATA
ADD BX, AX ; Add offset to table base
RET
CALCULATE_CELL_ADDR ENDP
GET_STRING_INPUT PROC
PUSH DI
MOV CX, CELL_SIZE - 1 ; Max characters (8)
MOV SI, 0 ; Character counter
STRING_CHAR_LOOP:
; Read character
MOV AH, 01H
INT 21H
CMP AL, 13 ; Enter key
JE STRING_INPUT_DONE
CMP AL, 8 ; Backspace
JE STRING_BACKSPACE
; Check buffer limit
CMP SI, CX
JAE STRING_CHAR_LOOP
; Store character
STOSB
INC SI
JMP STRING_CHAR_LOOP
STRING_BACKSPACE:
; Handle backspace
CMP SI, 0
JE STRING_CHAR_LOOP
DEC DI
DEC SI
; Erase character from display
MOV DL, 8
MOV AH, 02H
INT 21H
MOV DL, ' '
INT 21H
MOV DL, 8
INT 21H
JMP STRING_CHAR_LOOP
STRING_INPUT_DONE:
; Check for empty input
CMP SI, 0
JE STRING_EMPTY
; Terminate string
MOV AL, '$'
STOSB
; New line
LEA DX, NEWLINE
MOV AH, 09H
INT 21H
POP DI
RET
STRING_EMPTY:
; Handle empty input
LEA DX, ERR_EMPTY_CELL
MOV AH, 09H
INT 21H
POP DI
JMP GET_STRING_INPUT
GET_STRING_INPUT ENDP
GET_NUMERIC_INPUT PROC
PUSH DI
MOV CX, CELL_SIZE - 1 ; Max characters (8)
MOV SI, 0 ; Character counter
NUMERIC_CHAR_LOOP:
; Read character
MOV AH, 01H
INT 21H
CMP AL, 13 ; Enter key
JE NUMERIC_INPUT_DONE
CMP AL, 8 ; Backspace
JE NUMERIC_BACKSPACE
; Validate character (digits or signs)
CMP AL, '-'
JE HANDLE_SIGN
CMP AL, '+'
JE HANDLE_SIGN
CMP AL, '0'
JB NUMERIC_CHAR_LOOP
CMP AL, '9'
JA NUMERIC_CHAR_LOOP
; Check buffer limit
CMP SI, CX
JAE NUMERIC_CHAR_LOOP
; Store character
STOSB
INC SI
JMP NUMERIC_CHAR_LOOP
HANDLE_SIGN:
; Handle sign character (only allowed at start)
CMP SI, 0
JNE NUMERIC_CHAR_LOOP
CMP SI, CX
JAE NUMERIC_CHAR_LOOP
STOSB
INC SI
JMP NUMERIC_CHAR_LOOP
NUMERIC_BACKSPACE:
; Handle backspace
CMP SI, 0
JE NUMERIC_CHAR_LOOP
DEC DI
DEC SI
; Erase character from display
MOV DL, 8
MOV AH, 02H
INT 21H
MOV DL, ' '
INT 21H
MOV DL, 8
INT 21H
JMP NUMERIC_CHAR_LOOP
NUMERIC_INPUT_DONE:
; Check for empty input
CMP SI, 0
JE NUMERIC_EMPTY
; Terminate string
MOV AL, '$'
STOSB
; New line
LEA DX, NEWLINE
MOV AH, 09H
INT 21H
POP DI
RET
NUMERIC_EMPTY:
; Handle empty input
LEA DX, ERR_EMPTY_CELL
MOV AH, 09H
INT 21H
POP DI
JMP GET_NUMERIC_INPUT
GET_NUMERIC_INPUT ENDP
STRING_TO_INT_SI PROC
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
XOR DI, DI ; Initialize result to 0
XOR BX, BX ; Sign flag (0=positive, 1=negative)
XOR CX, CX ; Temporary storage
; Check first character for sign
MOV DL, [SI]
CMP DL, '$'
JE STI_DONE ; Empty string
CMP DL, '-'
JE STI_NEGATIVE
CMP DL, '+'
JE STI_POSITIVE
JMP STI_CONVERT_LOOP
STI_NEGATIVE:
MOV BX, 1 ; Set negative flag
INC SI ; Move to next character
JMP STI_CONVERT_LOOP
STI_POSITIVE:
INC SI ; Move to next character
STI_CONVERT_LOOP:
; Get next character
MOV DL, [SI]
CMP DL, '$' ; End of string
JE STI_DONE
SUB DL, '0' ; Convert ASCII to digit
CMP DL, 0 ; Validate digit (0-9)
JB STI_DONE
CMP DL, 9
JA STI_DONE
; Efficient multiply by 10 using shifts
MOV AX, DI ; AX = current value
SHL AX, 1 ; AX = value*2
MOV CX, AX ; CX = value*2 (temporary)
MOV AX, DI
SHL AX, 3 ; AX = value*8
ADD AX, CX ; AX = value*10 (8+2)
ADD AX, DX ; Add new digit
MOV DI, AX ; Update result
; Next character
INC SI
JMP STI_CONVERT_LOOP
STI_DONE:
; Apply sign if negative
MOV AX, DI
CMP BX, 1
JNE STI_EXIT
NEG AX
STI_EXIT:
; Restore registers and return
POP DI
POP SI
POP DX
POP CX
POP BX
RET
STRING_TO_INT_SI ENDP
; FIXED STRING COMPARISON LOGIC
COMPARE_STRINGS PROC
PUSH SI
PUSH DI
CLD ; Clear direction flag (forward)
CS_LOOP:
; Compare bytes
MOV AL, [SI]
MOV BL, [DI]
CMP AL, '$'
JE CHECK_SECOND_END
CMP BL, '$'
JE FIRST_LARGER
CMP AL, BL
JB CS_LESS ; String1 < String2
JA CS_GREATER ; String1 > String2
; Characters are equal, move to next
INC SI
INC DI
JMP CS_LOOP
CHECK_SECOND_END:
CMP BL, '$'
JE CS_EQUAL
JMP CS_LESS ; String1 ended first, so it's less
FIRST_LARGER:
JMP CS_GREATER
CS_LESS:
MOV AX, -1
JMP CS_DONE
CS_EQUAL:
XOR AX, AX
JMP CS_DONE
CS_GREATER:
MOV AX, 1
CS_DONE:
; Restore registers and return
POP DI
POP SI
RET
COMPARE_STRINGS ENDP
; FIXED ROW SWAPPING WITH PROPER ADDRESS CALCULATION
SWAP_TABLE_ROWS PROC
PUSH AX
PUSH BX
PUSH CX
PUSH SI
PUSH DI
; Calculate address of first row
XOR AX, AX
MOV AL, CH ; Row index
XOR AH, AH ; AX = row index (zero extended)
MUL ROW_SIZE ; AX = row_index * ROW_SIZE
LEA SI, TABLE_DATA
ADD SI, AX
; Calculate address of second row
MOV AL, CH
INC AL ; Next row
XOR AH, AH
MUL ROW_SIZE ; AX = (row_index+1) * ROW_SIZE
LEA DI, TABLE_DATA
ADD DI, AX
; Swap entire rows
MOV CX, ROW_SIZE
SWAP_LOOP:
MOV AL, [SI]
MOV BL, [DI]
MOV [SI], BL
MOV [DI], AL
INC SI
INC DI
LOOP SWAP_LOOP
POP DI
POP SI
POP CX
POP BX
POP AX
RET
SWAP_TABLE_ROWS ENDP
PRINT_NUMBER PROC
PUSH AX
PUSH DX
; Check if single digit
CMP AL, 10
JB SINGLE_DIGIT
; Two-digit number handling
AAM ; Convert to unpacked BCD
ADD AX, 3030H ; Convert to ASCII
PUSH AX
MOV DL, AH ; Print tens digit
MOV AH, 02H
INT 21H
POP DX
MOV DL, DH ; Print units digit
INT 21H
JMP PRINT_DONE
SINGLE_DIGIT:
; Single-digit number
ADD AL, '0'
MOV DL, AL
MOV AH, 02H
INT 21H
PRINT_DONE:
POP DX
POP AX
RET
PRINT_NUMBER ENDP
END MAIN