flat assembler
Message board for the users of flat assembler.

Index > DOS > console fun

Author
Thread Post new topic Reply to topic
bitshifter



Joined: 04 Dec 2007
Posts: 764
Location: Massachusetts, USA
bitshifter
Hello, i spent the last few days writing what will eventually be the front end for my 16bit operating system, which for now is being tested in windows console.

It has some cool features like a command lookup table with function pointers which process user commands into realtime function calls, and also some string formatting tricks to change character colors or print newlines.

I thought i might share what i have learned with you because there are a lot of beginners here who probably would like to study or modify this code.

It doesnt do much, but it does what its supposed to and thats a good start.
Any comments or constructive criticism as always are greatly appreciated.
Code:
;------------------------------------------------
;
;------------------------------------------------
use16
org 0x100
jmp ProgramEntryPoint

;------------------------------------------------
; string formatting flags for PrintString function
;
; \r - set color to red
; \g - set color to green
; \b - set color to blue
; \w - set color to white
; \n - advance caret newline
;------------------------------------------------

;------------------------------------------------
;
;------------------------------------------------
buffer  rb 16
maxlen  db 15
length  db 0
prompt  db '\wInput command >> ',0
unknown db '\gUnknown command.\n',0
exiting db '\gExiting program.',0
paused  db '\wPress any key to continue...',0

color db 0x0F

commands db 'help',0,\
            'quit',0,\
            'cls',0,\
            0xFF

handlers dw on_help,\
            on_quit,\
            on_cls,\
            on_unknown

;           'x3d game engine by bitshifter'
intromsg db '\rx\g3\bd \rg\ga\bm\re \ge\bn\rg\gi\bn\re \gb\by \rb\gi\bt\rs\gh\bi\rf\gt\be\rr\n',0
helpmsg  db '\n\ghelp called\n',0
quitmsg  db '\n\gquit called\n',0

;------------------------------------------------
;
;------------------------------------------------
on_help:
   push si
   mov si,helpmsg
   call PrintString
   pop si
ret

on_quit:
   push si
   mov si,quitmsg
   call PrintString
   pop si
ret

on_cls:
   push ax
   mov al,0x00 ; number of lines to scroll (0 = clear entire window)
   call ScrollWindowUp
   pop ax

   push dx
   xor dx,dx
   call SetCaretPosition
   pop dx
ret

on_unknown:
   push si
   mov si,unknown
   call AdvanceCaretNewline
   call PrintString
   pop si
ret

;------------------------------------------------
;
;------------------------------------------------
ProcessCommand:
   push si
   push di
   push bp
   push ax
      xor bp,bp
      mov si,commands
   .for_each_command:
      mov di,buffer
      cmp byte[si],0xFF
      je .execute_command
   .for_each_character:
      mov al,byte[si]
      cmp al,byte[di]
      jne .get_next_command
      or al,al
      jz .execute_command
      inc si
      inc di
      jmp .for_each_character
   .get_next_command:
      lodsb
      or al,al
      jnz .get_next_command
      inc bp
      jmp .for_each_command
   .execute_command:
      shl bp,1
      call word[bp+handlers]
   pop ax
   pop bp
   pop di
   pop si
ret

;------------------------------------------------
;
;------------------------------------------------

SetTextColorRed:
   mov [color],0x04
ret

SetTextColorGreen:
   mov [color],0x02
ret

SetTextColorBlue:
   mov [color],0x01
ret

SetTextColorWhite:
   mov [color],0x0F
ret

;------------------------------------------------
; Params:
;   AL: number of lines to scroll (0 = clear entire window)
;------------------------------------------------
ScrollWindowUp:
   push ax
   push bx
   push cx
   push dx
      mov ah,0x06 ; function id
      mov bl,0x00 ; empty
      mov bh,0x0F ; bk+fg colors (bk = black, fg = white)
      mov cl,0x00 ; top left column
      mov ch,0x00 ; top left row
      mov dl,79   ; bottom right column
      mov dh,24   ; bottom right row
      int 0x10    ; invoke bios
      call GetCaretPosition
      mov dl,0x00
      call SetCaretPosition
   pop dx
   pop cx
   pop bx
   pop ax
ret

;------------------------------------------------
; Returns:
;   DL - caret column number
;   DH - caret row number

;
; Notes:
;   1) assumes page number 0
;------------------------------------------------
GetCaretPosition:
   push ax
   push bx
   push cx     ; silently modified
   mov al,0x00 ; empty
   mov ah,0x03 ; function id
   mov bl,0x00 ; empty
   mov bh,0x00 ; page number
   int 0x10    ; invoke bios
   pop cx
   pop bx
   pop ax
ret

;------------------------------------------------
; Params:
;   DL - caret column number
;   DH - caret row number
;
; Notes:
;   1) does not check caret bounds
;   2) assumes page number 0
;------------------------------------------------
SetCaretPosition:
   push ax
   push bx
   mov al,0x00 ; empty
   mov ah,0x02 ; function id
   mov bl,0x00 ; empty
   mov bh,0x00 ; page number
   int 0x10    ; invoke bios
   pop bx
   pop ax
ret

;------------------------------------------------
; Notes:
;   1) does not check caret bounds
;   2) assumes page number 0
;------------------------------------------------
AdvanceCaretPosition:
   push dx
   call GetCaretPosition
   inc dl
   call SetCaretPosition
   pop dx
ret

;------------------------------------------------
; Notes:
;   1) does not check caret bounds
;   2) assumes page number 0
;------------------------------------------------
RetreatCaretPosition:
   push dx
   call GetCaretPosition
   dec dl
   call SetCaretPosition
   pop dx
ret

;------------------------------------------------
; Notes:
;   1) assumes page number 0
;   2) scrolls window up one line if needed
;------------------------------------------------
AdvanceCaretNewline:
   push dx
      call GetCaretPosition
      cmp dh,24
      je .scroll_up
      mov dl,0x00 ; reset column
      inc dh      ; increase row
      call SetCaretPosition
      jmp .finished
   .scroll_up:
      push ax
      mov al,0x01 ; scroll up one line
      call ScrollWindowUp
      pop ax
   .finished:
   pop dx
ret

;------------------------------------------------
; Params:
;    AL - ascii character to print
;
; Notes:
;    1) does not advance caret
;    2) assumes page number 0
;------------------------------------------------
PrintCharacter:
   push ax
   push bx
   push cx
   mov ah,0x09    ; function id
   mov bl,[color] ; bg+fg colors
   mov bh,0x00    ; page number
   mov cx,0x01    ; repeat count
   int 0x10       ; invoke bios
   pop cx
   pop bx
   pop ax
ret

;------------------------------------------------
; Notes:
;   1) erases character at caret position
;   2) assumes page number 0
;------------------------------------------------
EraseCharacter:
   push ax
   xor ax,ax
   call SetTextColorWhite
   call PrintCharacter
   pop ax
ret

;------------------------------------------------
; Params:
;   SI: pointer to NULL terminated string
;
; Notes:
;   1) does not check caret bounds
;   2) assumes page number 0
;   3) accepts formatting flags
;------------------------------------------------
PrintString:
      push ax
      push si
      push cx
      xor cx,cx
   .load_character:
      lodsb
      or al,al
      jz .end_of_string
      cmp al,'\'
      je .activate_sequence
      cmp al,'r'
      je .set_to_red
      cmp al,'g'
      je .set_to_green
      cmp al,'b'
      je .set_to_blue
      cmp al,'w'
      je .set_to_white
      cmp al,'n'
      je .do_newline
   .print_character:
      call PrintCharacter
      call AdvanceCaretPosition
      jmp .load_character
   .activate_sequence:
      mov cx,1
      jmp .load_character
   .set_to_red:
      cmp cx,1
      jne .print_character
      mov cx,0
      call SetTextColorRed
      jmp .load_character
   .set_to_green:
      cmp cx,1
      jne .print_character
      mov cx,0
      call SetTextColorGreen
      jmp .load_character
   .set_to_blue:
      cmp cx,1
      jne .print_character
      mov cx,0
      call SetTextColorBlue
      jmp .load_character
   .set_to_white:
      cmp cx,1
      jne .print_character
      mov cx,0
      call SetTextColorWhite
      jmp .load_character
   .do_newline:
      cmp cx,1
      jne .print_character
      mov cx,0
      call AdvanceCaretNewline
      jmp .load_character
   .end_of_string:
      pop cx
      pop si
      pop ax
ret

;------------------------------------------------
;
;------------------------------------------------
ProgramEntryPoint:

      ; set video mode (first mode13 then mode3)
      ; this can be removed but to go fullscreen
      ; you will need to press the alt-enter keys
      mov al,0x13 ; graphics mode (40*25, 256 colors, 1 page)
      mov ah,0x00 ; function id
      int 0x10    ; invoke bios
      mov al,0x03 ; text mode (80*25, 16 colors, 8 pages)
      mov ah,0x00 ; function id
      int 0x10    ; invoke bios

      ; print intro
      mov si,intromsg
      call PrintString

   .reset:
      ; reset command buffer
      mov [buffer],0
      mov [length],0
      mov di,buffer

      ; print command prompt
      mov si,prompt
      call PrintString

   .input:
      ; wait for keystroke
      xor ax,ax
      int 0x16

      ; handle special keys
      cmp al,0x1B   ; VK_ESCAPE
      je .vk_escape
      cmp al,0x08   ; VK_BACK
      je .vk_back
      cmp al,0x0D   ; VK_RETURN
      je .vk_return

      ; is command buffer full?
      mov ah,[length]
      cmp ah,[maxlen]
      je .input

      ; append character to buffer
      mov byte[di],al
      inc di
      mov byte[di],0
      inc [length]

      ; print character to screen
      call SetTextColorBlue
      call PrintCharacter
      call AdvanceCaretPosition
      jmp .input

   .vk_back:
      ; backspace limiter (keeps us from erasing the prompt)
      cmp [length],0 ; is command buffer empty?
      je .input

      ; remove character from buffer
      dec di         ; decease buffer pointer
      mov byte[di],0 ; insert NULL terminator
      dec [length]   ; decrement command length

      ; update screen
      call RetreatCaretPosition
      call EraseCharacter
      jmp .input

   .vk_return:
      ; check for empty command buffer
      cmp [length],0
      je .input
      call ProcessCommand
      jmp .reset

   .vk_escape:
      ; print exiting message
      mov si,exiting
      call AdvanceCaretNewline
      call PrintString
      ; print paused message
      mov si,paused
      call AdvanceCaretNewline
      call PrintString
      ; wait for keystroke
      xor ax,ax
      int 0x16

      ; exit to operating system
      int 0x20 ; invoke bios
      ; dos version
      ;mov al,0x00 ; exit code
      ;mov ah,0x4C ; function id
      ;int 0x21    ; invoke bios
ret
    


Last edited by bitshifter on 06 May 2009, 08:03; edited 5 times in total
Post 17 Dec 2008, 08:46
View user's profile Send private message Reply with quote
baldr



Joined: 19 Mar 2008
Posts: 1651
baldr
bitshifter,
Code:
      ; save original video mode
      mov al,0x0F    ; video mode (query current)
      mov ah,0x00    ; function id
      int 0x10       ; invoke bios
      mov [orgvm],al ; save it    
will not save video mode: it will try to set video mode to 0F (EGA mono graphics). Set ah to 0F prior to invoke int 10, you will get active page also (in bh).

Words at 40:4A and 40:4C contain current video mode columns' count and video buffer size (in bytes, not character cells), respectively. They may be useful for caret positioning/scrolling.

May be you will find useful standard CR LF sequence for new line, as int 10/0E does, instead of '\n'.

Several keys return zero as ASCII code, notably F-keys, cursor movement keys. Moreover, there is Alt-NumPad method of input (Alt-27 will return 001B in ax from int 16, for example).

_________________
"Don't belong. Never join. Think for yourself. Peace." – Victor Stone.
Post 17 Dec 2008, 10:56
View user's profile Send private message Reply with quote
bitshifter



Joined: 04 Dec 2007
Posts: 764
Location: Massachusetts, USA
bitshifter
baldr:
Ok, i removed those parts of the code, thanks for the help.
If i just use mode3 it just shows the standard console window.
How do i go fullscreen and use text mode?

Also, i just figured out how to scroll the window, so i modified the code to handle automatic window scrolling if the caret hits the bottom of the screen and added a new command and handler so the user can clear the screen.
Post 17 Dec 2008, 11:51
View user's profile Send private message Reply with quote
baldr



Joined: 19 Mar 2008
Posts: 1651
baldr
bitshifter,

Set properties of .Com (Windows will create .PIF): page "Screen", "Usage: Full-screen". You may also check "Close on exit" on "Program" page.

Also at any time you can switch between windowed/full-screen modes with Alt+Enter.

By the way, you don't have to use NUL-terminated strings, counted strings are much simpler in handling and can easily be converted to NUL-terminated.
bitshifter wrote:
Ok, i removed those parts of the code, thanks for the help.
I didn't mean that you must remove them, your comment about int 10/fn 00/mode 0F was erroneous. You do have IntrList/HelpPC/TechHelp! handy, don't you?

Hard-coding screen dimensions is not a good practice, at least define them as a constants (later you won't have to hunt those 80/79/25/24 all over the source), or use BIOS data to determine them.

Lots of mov al, something/mov ah, something else

Many functions are mere wrappers for BIOS calls…

_________________
"Don't belong. Never join. Think for yourself. Peace." – Victor Stone.
Post 17 Dec 2008, 16:08
View user's profile Send private message Reply with quote
bitshifter



Joined: 04 Dec 2007
Posts: 764
Location: Massachusetts, USA
bitshifter
I did a lot of un-optimal stuff purely for clarity, this can be fixed later.
I also went ahead and sweetened up the command parsers code.
As for going fullscreen, it looks like if i go mode13 then mode03 it gives the desired result.
I use alt-enter all the time on the windows media player, but never realized it worked on the console window until i happened to try it.
Post 17 Dec 2008, 20:48
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2020, Tomasz Grysztar. Also on YouTube, Twitter.

Website powered by rwasa.