QB / QB64 Discussion Forum      Other Subforums, Links and Downloads
 Return to Index  

scan codes: cmp, adc, sbb

February 19 2011 at 12:15 AM
  (Login MCalkins)
Moderator


Response to Challenge: too many IF - THENs

The scan codes lend themselves to this, because they are in qwerty order. Check the Qbasic Help under "Keyboard Scan Codes".

This program uses int 0x16 to read the keyboard scan code. It then uses a series of cmp (compare), adc (add with carry), and sbb (subtract with borrow) instructions instead of a bunch of conditional jumps. I'm not sure if this is more efficient, but it reduces conditional jumps. The dl register is used to track the quadrant number, and the cl register is used to track whether to even display a message. (This is necessary because, for example, "{" is between "p" and "a" in the scan codes.)

In the assembly source, I included some comments in qbasic-like pseudo code to help clarify the cmp, adc, sbb sequence.

Regards,
Michael

'public domain, feb 2011, michael calkins
DEFINT A-Z
DIM t AS STRING, i AS INTEGER
DIM code AS STRING * 216
t = "E800005B83EB031E8CCA8EDA89DA81C28F00B409CD2130E4CD1680FC01746EB2"
t = t + "0330C980FC3380D1FF80FC3080D20080FC2C80D90080FC2780D10080DA0080FC"
t = t + "2280D20080FC1E80D90080DA0080FC1A80D10080DA0080FC1580DA0080FC1080"
t = t + "D90080FC0C80D10080D20080FC0780DA0084C975A18887C30080C2308897D400"
t = t + "89DA81C2BF00B409CD21E989FF1FCB205479706520616E79206B657920612D7A"
t = t + "2028412D5A29206F7220302D390D0A2045534320746F20656E640D0A0D0A244B"
t = t + "6579203F20697320696E207175616472616E74203F0D0A24"
FOR i = 0 TO 215
MID$(code, i + 1, 1) = CHR$(VAL("&h" + MID$(t, (i * 2) + 1, 2)))
NEXT i
DEF SEG = VARSEG(code)
CALL absolute(VARPTR(code))
SYSTEM

--------------------

;public domain, feb 2011, michael calkins
cpu 386
org 0x0

_routine:
call .find
.find:
pop bx
sub bx,byte 0x3
push ds
mov dx,cs
mov ds,dx

mov dx,bx
add dx,_msg0
mov ah,0x9
int 0x21

_lp:
xor ah,ah
int 0x16
cmp ah,0x1
jz _exit

mov dl,0x3 ; dl = 3
xor cl,cl ; cl = 0
cmp ah,0x33 ; if ah >= 0x33 then cl = cl - 1
adc cl,0xff
cmp ah,0x30 ; if ah < 0x30 then dl = dl + 1
adc dl,0x0
cmp ah,0x2c ; if ah < 0x2c then cl = cl - 1
sbb cl,0x0
cmp ah,0x27 ; if ah < 0x27 then cl = cl + 1: dl = dl - 1
adc cl,0x0 ;carry flag is still correct
sbb dl,0x0
cmp ah,0x22 ; if ah < 0x22 then dl = dl + 1
adc dl,0x0
cmp ah,0x1e ; if ah < 0x1e then cl = cl - 1: dl = dl - 1
sbb cl,0x0 ;carry flag is still correct
sbb dl,0x0
cmp ah,0x1a ; if ah < 0x1a then cl = cl + 1: dl = dl - 1
adc cl,0x0 ;carry flag is still correct
sbb dl,0x0
cmp ah,0x15 ; if ah < 0x15 then dl = dl - 1
sbb dl,0x0
cmp ah,0x10 ; if ah < 0x10 then cl = cl - 1
sbb cl,0x0
cmp ah,0xc ; if ah < 0xc then cl = cl + 1: dl = dl + 1
adc cl,0x0 ;carry flag is still correct
adc dl,0x0
cmp ah,0x7 ; if ah < 0x7 then dl = dl - 1
sbb dl,0x0

;0x1 --- exit
;0x2 to 0x6 --- 1
;0x7 to 0xb --- 2
;0xc to 0xf --- bad
;0x10 to 0x14 --- 1
;0x15 to 0x19 --- 2
;0x1a to 0x1d --- bad
;0x1e to 0x21 --- 4
;0x22 to 0x26 --- 3
;0x27 to 0x2b --- bad
;0x2c to 0x2f --- 4
;0x30 to 0x32 --- 3
;>= 0x33 --- bad

test cl,cl
jnz _lp
mov [bx+_asc],al
add dl,0x30
mov [bx+_q],dl
mov dx,bx
add dx,_msg1
mov ah,0x9
int 0x21
jmp _lp

_exit:
pop ds
retf

_msg0: db " Type any key a-z (A-Z) or 0-9",0xd,0xa
db " ESC to end",0xd,0xa,0xd,0xa,"$"
_msg1: db "Key "
_asc: db "? is in quadrant "
_q: db "?",0xd,0xa,"$"

--------------------
Just for info: To turn the assembly routine into a stand alone .com file:

change "org 0x0" to "org 0x100"
delete everything from "call .find" to "mov ds,dx", inclusive
change "mov dx,bx","add dx,_msg0" to "mov dx,_msg0"
change "mov [bx+_asc],al" to "mov [_asc],al"
change "mov [bx+_q],dl" to "mov [_q],dl
change "mov dx,bx","add dx,_msg1" to "mov dx,_msg1"
change "retf" to "xor ah,ah","int 0x21"


    
This message has been edited by MCalkins on Feb 19, 2011 12:29 AM
This message has been edited by MCalkins on Feb 19, 2011 12:23 AM


 
 Respond to this message