HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Moving a cursor with the keyboard in assembly

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
thewithassemblymovingkeyboardcursor

Problem

I am a beginner in assembly. But that didn't stop me from making a simple operating system completely made in assembly. It's very simple and doesn't do much. It's just a proof of concept. I would like to know what I can improve. Any feedback would be great.

bits 16
mov dl, 0 ; Cursor position column
mov dh, 0 ; Cursor position row

; Draw a really simple UI
; Draws a blue background
mov ah, 09h 
mov al, 32
mov bl, 10h
mov cx, 1000h
int 10h 

; Draws a gray bar
mov ah, 09h
mov al, 32
mov bl, 70h
mov cx, 160d
int 10h

main:
    ; Waits for a key press
    mov ah, 00h
    int 16h

    ; Compare the al register to see what key the user pressed

    ; If the user pressed the 's' key move the cursor down
    cmp al, 115
    je Down

    ; If the user pressed the 'w' key move the cursor up
    cmp al, 119
    je Up

    ; If the user pressed the 'a' key move the cursor left
    cmp al, 97
    je Left

    ; If the user pressed the 'd' key move the cursor right
    cmp al, 100
    je Right

    ; If the user pressed the Space Bar make the background of the   cursor magenta
    cmp al, 32
    je SpaceBar

    ; Jump back to main
    jmp main

    ; Our functions
    SpaceBar:
          mov ah, 09h
          mov bl, 50h
          mov cx, 1d
          int 10h
          jmp main  

    Right:
        add dl, 1
        call SetCursor
        jmp main
        ret

    Left:
      sub dl, 1
      call SetCursor
      jmp main
      ret

   Up:
     sub dh, 1
     call SetCursor
     jmp main
     ret

   Down:
      add dh, 1
      call SetCursor
      jmp main
      ret

   SetCursor:
       mov ah, 02h
       mov bh, 00
       int 10h
       ret

 times 510-($-$) db 0
 dw 0xAA55

Solution

Eventually you're going to want to handle other key-presses, correct? You might also want to handle other encoding styles, like EBCDIC, correct?

So, I've never done Assembly before, but these are pretty simple things to design for, and I hope the implementation is correct. First, we want to build a (very large) jump table for ASCII. Essentially, a jump table eliminates all of your comparisons down to exactly one comparison. It's pretty easy to set up:

goto ascii(al) ; Jump to the line of the character code
ascii:  goto nulInput  ; This would be `0` code input
        goto sohInput  ; This would be `1` code input / Start of Heading
        goto stxInput  ; This would be `2` code input / Start of Text
        ; Add End of Text (3), End of Transmission (4), Enquiry (5)
        ; Acknowledgement (6), Bell (7)
        goto bsInput   ; This would be `8` code input / Backspace
        goto htInput   ; This would be `9` code input / Horizontal Tab
        goto lfInput   ; This would be `A` code input / Line Feed
        ; Add Vertical Tab (B), Form Feed (C)
        goto crInput   ; This would be `D` code input / Carriage return
        ; Shift Out (E), Shift In (F), Data Link Escape (10)
        ; Device Control 1 / XON (11), Device Control 2 (12)
        ; Device Control 3 / XOFF (13), Device Control 4 (14)
        ; Negative Acknowledgement (15), Synchronous Idle (16)
        ; End of Transmission Block (17), Cancel (18), End of Medium (19)
        ; Substitute (1A)
        goto escInput   ; This would be `1B` code input / Escape
        ; File Separator (1C), Group Separator (1D), Record Separator (1E)
        ; Unit Separator (1F)
        goto spacInput  ; This would be `20` code input / Space
        goto exclInput  ; This would be `21` code input / Exclamation Point
        ; In Order:
        ; " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ;  ?
        ; @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _
        ; ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~
        goto delInput   ; This would be `7F` code input / Delete


So you should get the point, go through the ASCII spec line-by-line and put a line for each record in the spec, then a label for each of those lines. For the ones you don't wish to implement yet, simply have a restart label or badCode label that ignores the input.

Once that's done we now know how to implement EBCDIC, just build an EBCDIC jump table.

What you might not realize is that having 128 (because eventually you want to support all codes/keys, right?) cmp statements will cause negative performance because al is compared up to 128 times for each key press, that's a lot. So we build a jump table that might be more work to implement initially, but in the end we'll end up with a much easier to maintain setup, and performance will not degrade. When we call jmp ascii(al), it jumps to the ascii label, then to the line identified by al. Easy stuff.

Regarding your indentation and such, from what I've seen usually assembly is spaced fairly far from the left (8-12 spaces) then all labels go at position 0. This helps keep them in plain sight, since assembly doesn't have 'functions' and such, and there's not a real concept of 'nesting' (you can nest labels, but any label can be accessed from any other location/scope so it doesn't always do any good).

Code Snippets

goto ascii(al) ; Jump to the line of the character code
ascii:  goto nulInput  ; This would be `0` code input
        goto sohInput  ; This would be `1` code input / Start of Heading
        goto stxInput  ; This would be `2` code input / Start of Text
        ; Add End of Text (3), End of Transmission (4), Enquiry (5)
        ; Acknowledgement (6), Bell (7)
        goto bsInput   ; This would be `8` code input / Backspace
        goto htInput   ; This would be `9` code input / Horizontal Tab
        goto lfInput   ; This would be `A` code input / Line Feed
        ; Add Vertical Tab (B), Form Feed (C)
        goto crInput   ; This would be `D` code input / Carriage return
        ; Shift Out (E), Shift In (F), Data Link Escape (10)
        ; Device Control 1 / XON (11), Device Control 2 (12)
        ; Device Control 3 / XOFF (13), Device Control 4 (14)
        ; Negative Acknowledgement (15), Synchronous Idle (16)
        ; End of Transmission Block (17), Cancel (18), End of Medium (19)
        ; Substitute (1A)
        goto escInput   ; This would be `1B` code input / Escape
        ; File Separator (1C), Group Separator (1D), Record Separator (1E)
        ; Unit Separator (1F)
        goto spacInput  ; This would be `20` code input / Space
        goto exclInput  ; This would be `21` code input / Exclamation Point
        ; In Order:
        ; " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
        ; @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _
        ; ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~
        goto delInput   ; This would be `7F` code input / Delete

Context

StackExchange Code Review Q#156257, answer score: 3

Revisions (0)

No revisions yet.