; ============================================================================= ; ; Litos8 console display driver ; ; ============================================================================= ; ----------------------------------------------------------------------------- ; Exported user functions (22): ; DispConChar - display console character ; DispConSpc - display console space character ; DispConNewLine - display console new line (CR/LF characters) ; DispConText - display console text ; DispConTextZ - display console ANSIIZ text ; DispConTextStr - display console text string ; DispCon2Dig - display console 2 digits ; DispCon2DigSpc - display console 2 digits with space ; DispConByte - display console unsigned Byte ; DispConSByte - display console signed Byte ; DispConWord - display console unsigned Word ; DispConSWord - display console signed Word ; DispConDWord - display console unsigned DWord ; DispConSDWord - display console signed DWord ; DispConHByte - display console HEX Byte ; DispConHWord - display console HEX Word ; DispConHDWord - display console HEX DWord ; DispConBByte - display console BIN Byte ; DispConBWord - display console BIN Word ; DispConBDWord - display console BIN DWord ; DispConDate - display console date ; DispConTime - display console time ; ----------------------------------------------------------------------------- CODE_SECTION ; ----------------------------------------------------------------------------- ; Display console character ; ----------------------------------------------------------------------------- ; INPUT: AL = character ; NOTES: Supported controll characters BS, TAB, LF, FF, CR. ; ----------------------------------------------------------------------------- ; ------------- push registers DispConChar: push ax ; push AX push dx ; push DX ; ------------- prepare current position -> DX mov dx,[CursorPos] ; DX <- current position ; ------------- BS, back space cmp al,BS ; back space? jne short DispConChar2 ; no back space or dl,dl ; column 0? jnz short DispConChar1 ; not column 0 or dh,dh ; already row 0? jz short DispConChar9 ; already column 0 dec dh ; DH <- one row up mov dl,[VideoCols] ; DL <- number of columns DispConChar1: dec dl ; decrease cursor column jmp short DispConChar8 ; set new cursor position ; ------------- TAB, tabulator DispConChar2: cmp al,TAB ; tabulator? jne short DispConChar3 ; no tabulator add dl,8 ; DL <- shift by tabulator and dl,~7 ; align column to tabulator position jmp short DispConChar6 ; check row overflow ; ------------- LF, line feed DispConChar3: cmp al,LF ; line feed? je short DispConChar7 ; line feed ; ------------- FF, form feed, clear screen cmp al,FF ; form feed? jne short DispConChar4 ; no form feed call DispClear ; clear display jmp short DispConChar9 ; ------------- CR, carriage return DispConChar4: cmp al,CR ; carriage return? jne short DispConChar5 ; no carrage return mov dl,0 ; DL <- 0, row begin jmp short DispConChar8 ; set cursor position ; ------------- valid character DispConChar5: mov ah,[DefColor] ; AH <- default color call DispChar ; display character inc dl ; increase column ; ------------- scroll screen on overflow DispConChar6: cmp dl,[VideoCols] ; check column overflow jb short DispConChar8 ; no overflow mov dl,0 ; new column DispConChar7: inc dh ; increase row cmp dh,[VideoRows] ; check row overflow jb short DispConChar8 ; no overflow dec dh ; decrease row call DispScroll ; scroll screen ; ------------- set new cursor position DispConChar8: call SetCursor ; set new cursor position ; ------------- pop registers DispConChar9: pop dx ; pop DX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Display console space ; ----------------------------------------------------------------------------- DispConSpc: push ax ; push AX mov al," " ; AL <- space character call DispConChar ; display character pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Display console newline (CR/LF) ; ----------------------------------------------------------------------------- DispConNewLine: push ax ; push AX mov al,CR ; AL <- CR character call DispConChar ; display character mov al,LF ; AL <- LF character call DispConChar ; display character pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Display console text ; ----------------------------------------------------------------------------- ; INPUT: SI = pointer to text ; CX = text length ; ----------------------------------------------------------------------------- ; ------------- push registers DispConText: push ax ; push AX push cx ; push CX push si ; push SI ; ------------- display text jcxz DispConText8 ; no text DispConText2: lodsb ; AL <- character call DispConChar ; display console character loop DispConText2 ; next character ; ------------- pop registers DispConText8: pop si ; pop SI pop cx ; pop CX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Display console ASCIIZ text ; ----------------------------------------------------------------------------- ; INPUT: SI = pointer to ASCIIZ text (zero terminated) ; ----------------------------------------------------------------------------- ; ------------- push registers DispConTextZ: push ax ; push AX push si ; push SI ; ------------- display text DispConTextZ2: lodsb ; AL <- character or al,al ; end of text? jz short DispConTextZ8 ; end of text call DispConChar ; display console character jmp short DispConTextZ2 ; next character ; ------------- pop registers DispConTextZ8: pop si ; pop SI pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Display console text string ; ----------------------------------------------------------------------------- ; INPUT: BX = pointer to TEXT structure ; ----------------------------------------------------------------------------- ; ------------- push registers DispConTextStr: push ax ; push AX push cx ; push CX push si ; push SI ; ------------- display text mov cx,[bx+TEXT_Length] ; CX <- text length jcxz DispConTextStr8 ; no text lea si,[bx+TEXT_Text] ; SI <- start of text DispConTextStr2:lodsb ; AL <- character call DispConChar ; display console character loop DispConTextStr2 ; next character ; ------------- pop registers DispConTextStr8:pop si ; pop SI pop cx ; pop CX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Display console 2 digits ; ----------------------------------------------------------------------------- ; INPUT: AL = data byte (0..99) ; ----------------------------------------------------------------------------- DispCon2Dig: push ax ; push AX aam ; AL <- units, AH <- tens xchg al,ah ; AL <- tens, AH <- units add ax,"00" ; AL,AH <- convert to ASCII character call DispConChar ; display character mov al,ah ; AL <- units call DispConChar ; display character pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Display console 2 digits with space ; ----------------------------------------------------------------------------- ; INPUT: AL = data byte (0..99) ; ----------------------------------------------------------------------------- DispCon2DigSpc: push ax ; push AX aam ; AL <- units, AH <- tens xchg al,ah ; AL <- tens, AH <- units add ax,"00" ; AL,AH <- convert to ASCII character cmp al,"0" ; unsignificant zero? jne short DispCon2DigSpc2 ; valir digit mov al," " ; AL <- space DispCon2DigSpc2:call DispConChar ; display character mov al,ah ; AL <- units call DispConChar ; display character pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Display console unsigned Byte ; ----------------------------------------------------------------------------- ; INPUT: AL = unsigned data byte ; ----------------------------------------------------------------------------- ; ------------- push registers DispConByte: push ax ; push AX ; ------------- hundrends cmp al,100 ; check 100 jb short DispConByte2 ; number is < 100 push cx ; push CX mov cl,100 ; CL <- divider mov ah,0 ; AX = number div cl ; AL <- hundreds, AH <- units add al,"0" ; AL <- convert to ASCII character call DispConChar ; display character mov al,ah ; AL <- units pop cx ; pop CX jmp short DispConByte3 ; ------------- tens DispConByte2: cmp al,10 ; check 10 jb short DispConByte4 ; number is < 10 DispConByte3: aam ; AL <- units, AH <- tens xchg al,ah ; AL <- tens, AH <- units add al,"0" ; AL <- convert to ASCII character call DispConChar ; display character mov al,ah ; AL <- units ; ------------- units DispConByte4: add al,"0" ; AL <- convert to ASCII character call DispConChar ; display character ; ------------- pop registers pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Display console signed Byte ; ----------------------------------------------------------------------------- ; INPUT: AL = signed data byte ; ----------------------------------------------------------------------------- DispConSByte: or al,al ; negative number? jns short DispConByte ; number is positive push ax ; push AX mov ah,al ; AH <- character to display mov al,"-" ; AL <- sign character call DispConChar ; display sign character mov al,ah ; AL <- number to display neg al ; AL <- change to positive number call DispConByte ; display number pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Display console unsigned Word ; ----------------------------------------------------------------------------- ; INPUT: AX = unsigned data word ; ----------------------------------------------------------------------------- ; ------------- small number (in byte) DispConWord: or ah,ah ; small number ? jz short DispConByte ; small number, in byte ; ------------- push registers push ax ; push AX push bx ; push BX push cx ; push CX push dx ; push DX ; ------------- decode number into stack xor cx,cx ; CX <- character counter mov bx,10 ; BX <- 10, divider DispConWord2: xor dx,dx ; DX <- 0 div bx ; divide one digit add dl,"0" ; DL <- convert to ASCII character push dx ; push digit into stack inc cx ; increase digit counter or ax,ax ; already zero ? jnz short DispConWord2 ; decode next digit ; ------------- display number DispConWord4: pop ax ; pop digit from the stack call DispConChar ; display digit loop DispConWord4 ; next digit ; ------------- pop registers pop dx ; pop DX pop cx ; pop CX pop bx ; pop BX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Display console signed Word ; ----------------------------------------------------------------------------- ; INPUT: AX = signed data word ; ----------------------------------------------------------------------------- DispConSWord: or ax,ax ; negative number? jns short DispConWord ; number is positive push ax ; push AX mov al,"-" ; AL <- sign character call DispConChar ; display sign character pop ax ; pop AX neg ax ; AX <- change to positive number call DispConWord ; display number neg ax ; AX <- original number ret ; ----------------------------------------------------------------------------- ; Display console unsigned DWord ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = unsigned data dword ; ----------------------------------------------------------------------------- ; ------------- small number (in word) DispConDWord: or dx,dx ; small number? jz short DispConWord ; small number, on word ; ------------- push registers push ax ; push AX push bx ; push BX push cx ; push CX push dx ; push DX push si ; push SI ; ------------- decode number into stack xor cx,cx ; CX <- character counter mov bx,10 ; BX <- 10, divider DispConDWord2: xchg ax,si ; SI <- number LOW xchg ax,dx ; AX <- number high xor dx,dx ; DX <- 0 div bx ; divide / 10 xchg ax,si ; SI <- new high, AX <- low div bx ; divide / 10 add dl,"0" ; DL <- convert to ASCII character push dx ; push digit into stack inc cx ; increase digit counter mov dx,si ; DX <- new high or si,ax ; check zero result jnz short DispConDWord2 ; decode next digit ; ------------- display number DispConDWord4: pop ax ; pop digit from the stack call DispConChar ; display digit loop DispConDWord4 ; next digit ; ------------- pop registers pop si ; pop SI pop dx ; pop DX pop cx ; pop CX pop bx ; pop BX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Display console signed DWord ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = signed data dword ; ----------------------------------------------------------------------------- ; ------------- check negative number DispConSDWord: or dx,dx ; negative number? jns short DispConDWord ; number is positive ; ------------- display negative sign push ax ; push AX mov al,"-" ; AL <- sign character call DispConChar ; display sign character pop ax ; pop AX ; ------------- dispay absolute value of the number push ax ; push AX push dx ; push DX neg ax ; AX <- negate number LOW adc dx,byte 0 ; DX <- carry neg dx ; DX <- negate number HIGH call DispConDWord ; display number pop dx ; pop DX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Display console HEX DWord ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = data dword ; ----------------------------------------------------------------------------- DispConHDWord: xchg ax,dx ; AX <- high word, DX <- low word call DispConHWord ; display high word xchg ax,dx ; AX <- low word, DX <- high word ; --- DispConHWord must follow! ; ----------------------------------------------------------------------------- ; Display console HEX Word ; ----------------------------------------------------------------------------- ; INPUT: AX = data word ; ----------------------------------------------------------------------------- DispConHWord: xchg al,ah ; AL <- high byte, AH <- low byte call DispConHByte ; display high byte xchg al,ah ; AL <- low byte, AH <- high byte ; --- DispConHByte must follow! ; ----------------------------------------------------------------------------- ; Display console HEX Byte ; ----------------------------------------------------------------------------- ; INPUT: AL = data byte ; ----------------------------------------------------------------------------- ; alternate method: ; add al,90h ; daa ; adc al,40h ; daa ; ------------- display high nibble DispConHByte: push ax ; push AX shr al,1 shr al,1 shr al,1 shr al,1 ; AL <- high nibble cmp al,10 ; hex character A..F ? sbb al,69h das ; AL <- hex digit call DispConChar ; display character pop ax ; pop AX ; ------------- display low nibble push ax ; push AX and al,0fh ; AL <- low nibble cmp al,10 ; hex character A..F ? sbb al,69h das ; AL <- hex digit call DispConChar ; display character pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Display console BIN DWord ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = data dword ; ----------------------------------------------------------------------------- DispConBDWord: xchg ax,dx ; AX <- high word, DX <- low word call DispConBWord ; display high word xchg ax,dx ; AX <- low word, DX <- high word ; --- DispConBWord must follow! ; ----------------------------------------------------------------------------- ; Display console BIN Word ; ----------------------------------------------------------------------------- ; INPUT: AX = data word ; ----------------------------------------------------------------------------- DispConBWord: xchg al,ah ; AL <- high byte, AH <- low byte call DispConBByte ; display high byte xchg al,ah ; AL <- low byte, AH <- high byte ; --- DispConBByte must follow! ; ----------------------------------------------------------------------------- ; Display console BIN Byte ; ----------------------------------------------------------------------------- ; INPUT: AL = data byte ; ----------------------------------------------------------------------------- ; ------------- push characters DispConBByte: push ax ; push AX push cx ; push CX ; ------------- display bits mov ah,al ; AH <- data byte mov cx,8 ; CX <- number of bits DispConBByte2: shl ah,1 ; check highest bit mov al,"0" ; AL <- bit "0" adc al,0 ; change to bit "1" call DispConChar ; display character loop DispConBByte2 ; dispaly next bit ; ------------- pop registers pop cx ; pop CX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Display console date ; ----------------------------------------------------------------------------- ; INPUT: AH = date format (DATEFORM_EURO,...) ; DL = day ; DH = month ; SI = year ; ----------------------------------------------------------------------------- ; ------------- push registers DispConDate: push ax ; push AX ; ------------- Europe format day.month.year cmp ah,DATEFORM_EURO ; Europe format? jne short DispConDate2 ; no mov al,dl ; AL <- day call DispConByte ; display day mov al,"." ; separator call DispConChar ; display separator mov al,dh ; AL <- month call DispConByte ; display month mov al,"." ; separator call DispConChar ; display separator mov ax,si ; AX <- year call DispConWord ; display year jmp short DispConDate8 ; ------------- USA format month/day/year DispConDate2: cmp ah,DATEFORM_USA ; USA format? jne short DispConDate4 ; no mov al,dh ; AL <- month call DispConByte ; display month mov al,"/" ; separator call DispConChar ; display separator mov al,dl ; AL <- day call DispConByte ; display day mov al,"/" ; separator call DispConChar ; display separator mov ax,si ; AX <- year call DispConWord ; display year jmp short DispConDate8 ; ------------- Japan format year-month-day DispConDate4: mov ax,si ; AX <- year call DispConWord ; display year mov al,"-" ; separator call DispConChar ; display separator mov al,dh ; AL <- month call DispCon2Dig ; display month mov al,"-" ; separator call DispConChar ; display separator mov al,dl ; AL <- day call DispCon2Dig ; display day ; ------------- pop registers DispConDate8: pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Display console time ; ----------------------------------------------------------------------------- ; INPUT: BH = second ; CL = minute ; CH = hour ; ----------------------------------------------------------------------------- ; ------------- push registers DispConTime: push ax ; push AX ; ------------- display hour mov al,ch ; AL <- hour call DispCon2DigSpc ; display hour mov al,":" ; separator call DispConChar ; display separator ; ------------- display minute mov al,cl ; AL <- minute call DispCon2Dig ; display minute mov al,":" ; separator call DispConChar ; display separator ; ------------- display second mov al,bh ; AL <- second call DispCon2Dig ; display second ; ------------- pop registers pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; CON device check ; ----------------------------------------------------------------------------- ; INPUT: BX = device index (0..15) ; OUTPUT: CY = invalid device ; ----------------------------------------------------------------------------- CONCheck: clc ; clear error flag ret ; ----------------------------------------------------------------------------- ; Read from CON device ; ----------------------------------------------------------------------------- ; INPUT: BX = device index (0..15) ; CX = number of bytes ; DI = destination buffer ; OUTPUT: CY = error (CX > 0) ; CX = remaining bytes (or CX = 0 if no error NC) ; ----------------------------------------------------------------------------- CONRead: push ax ; push AX jcxz CONRead4 ; no data required CONRead2: call GetCharWait ; get character cmp al,EOF ; end of file? stc ; set error flag je CONRead6 ; end of text stosb ; store character loop CONRead2 ; get next character CONRead4: clc ; clear error flag CONRead6: pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Write to CON device ; ----------------------------------------------------------------------------- ; INPUT: BX = device index (0..15) ; CX = number of bytes ; DI = source buffer ; OUTPUT: CY = error (CX > 0) ; CX = remaining bytes (or CX = 0 if no error NC) ; ----------------------------------------------------------------------------- CONWrite: push si ; push SI mov si,di ; SI <- source buffer call DispConText ; display text to console xor cx,cx ; CX <- 0, no data left pop si ; pop SI ret