Category : Display Utilities
Archive   : NUMLOC.ZIP
Filename : NUMLOC4.ASM
; Followed by descriptive phrases
; EQU STATEMENTS CAN GO HERE
kb_data equ 60h ; keyboard data port
kb_ctrl equ 61h ; keyboard control port.
eoi equ 20h ; EOI VALUE FOR THE 8259, programmable
; interrupt controller chip.
int_ctrl equ 20h ; port address for the 8259 PIC chip
bios_data segment at 40h ; BIOS data area
org 17h ;
kb_status db ? ; keyboard status byte
org 1ah ;
Buffer_head dw ? ; pointer to keyboard buffer head
buffer_tail DW ? ; pointer to keyboard buffer tail.
org 80H
Buffer_start dw ? ; Starting keyboard buffer address
buffer_end DW ? ; ending keyboard buffer address
bios_data ends
code segment para public 'code'
assume cs:code
org 100H
begin: jmp initialize
enable_values db 2ch,28h,2dh,29h,2ah,2eh,1eh ; Don't know what these
; enable values do.
kb_stat1 db 0 ; keeps track of the right and left shft keys
aux_shift db 0 ; auxiliary keyboard status byte. keeps trk
; of the numloc shift status.
adapter db 2 ; 0=MDA, 1= CGA, 2=EGA
video_segment dw 0b800H ; default video segment
cursor_mode dw 0607h ; default cursor shape.
addr_6845 dw ? ; port address of CRTC
ibm db 'IBM' ; EGA ASCII signature
old9h label dword
old9h_vector dw 2 dup (?) ; storage for interrupt 9 vector
; **************************************************
fill_parms dw 1,030fh,12 ; Don't know what fill parms are for.
dw 2,050fh,12
dw 2,070fh,12
dw 2,090fh,10
dw 17,0537h,4
dw 0,0737h,4
dw 0,0937h,3
def_table db 0,'1234567890-=',0
db 0,'QWERTYUIOP[]',0
DB 0,'ASDFGHJKL;',39,96
DB 0,0,'ZXCVBNM,./'
DB 17 DUP (0)
DB '789-456+123',0,0
UPPER_CASE DB 0,033,064,035,036,037,094,038,042,040,041,157,154,0
db 0,153,130,133,144,146,155,147,136,142,143,151,152,0
db 0,128,145,132,148,131,149,137,138,139,159,158,0
db 0,0,135,156,150,134,129,141,140,060,062,063 ; upper case
db 0,0,0,32,0, 059,60,061,062,063, 064,065,066,067,0, 0,0
db 0,0,0,0,0,0,0,0,0,0,0,0,0
; 01,002,003,004,005,006,007,008,009,00A,00B,00C,00D
; 0F,010,011,012,013,014,015,016,017,018,019,01A,01B,01C
; 00,01E,01F,020,021,022,023,024,025,026,027,028,029, ; scan
;2A,2B,02C,02D,02E,02F,030,031,032,033,034,035 ; codes
;36,37,38,39,3A, 3B,3C,3D,3E,3F, 40,41,42,43,44, 45,46 ; for a
; 047,048,049,04A,04B,04C,04D,04E,04F,050,051,'052,053' ; tandy
lower_case db 0,049,050,051,052,053,054,055,056,057,048,189,186,0
db 0,185,162,165,176,178,187,179,168,174,175,183,184,0
db 0,160,177,164,180,163,181,169,170,171,191,190,0
db 0,0,167,188,182,166,161,173,172,044,046,047 ; lower case
db 0,0,0,32,0, 0,0,0,0,0, 0,0,0,0,0, 0,0
db 0,0,0,0,0,0,0,0,0,0,0,0,0
; ***********************************************************************
; interupt 9 handler. Execution comes here when a key is pressed or released.
;************************************************************************
new9h proc near
sti
push ax
in al,kb_data ; gets scan code from keyboard
cmp al,42 ; left shift pressed
je exit ;
cmp al,42+128 ; left shift key released
je exit ;
cmp al,54 ; right shift pressed
je exit ;
cmp al,54+128 ; right shift released.
je exit
cmp al,58 ; caps locs set
je exit ;
cmp al,58+128 ; caps lock released
je exit ;
cmp al,28 ; Enter key down
je exit ; Apparently, I don't need to do anything when
; the enter key is released. The program works
; without a "cmp al,28+128, je exit" coding.
; Same for esc, bkspace, etc.
cmp al,59 ; Space key
je exit
cmp al,60
je exit
cmp al,61
je exit
cmp al,62
je exit
cmp al,63
je exit
cmp al,14 ; backspace
je exit
cmp al,15 ; tab
je exit
cmp al,43 ; left arrow on the tandy 1000
je exit ; keypad. The scan code for the right
; arrow is 78.
cmp al,41 ; up arrow on the tandy 1000 keypad.
je exit ; scan code for the down arrow is
; 74. We don't need to include down arrow
; here because there is a test al,64
; later on, which exits for any scan
; code 64 and above.
cmp al,1 ; Escape key.
je exit
cmp al,69 ; If the numlock key, scan code 69, is
; pressed, execution jumps to the numlock
je numlock ; procedure and toggles aux_shift. This
cmp al,69+128 ; tracks the status of the numlock key.
je numlock
cmp aux_shift,0 ; aux_shift keeps track of the numlock key
je exit ; if it is down, then aux_shift is one and
; we can jump to new key to translate
; the chr. If numlock is up, then it is a 0
; and execution returns to normal int 9
; vector.
test al,64 ; exit if scan code larger than 64. This is
jnz exit ; really if scan code is between 64 & 127,
; but since there are no scan codes higher,
; this works just find.
jmp newkey ; Aux_shift must be one and the key pressed
; must be a character key for execution to
; get to this point.
exit: pop ax
jmp old9h
;**********************************************************************
; numloc key pressed, so this routine is to toggle the aux_shift byte
; *******************************************************************
numlock: push ax
call reset_kb ; reset the keyboard. I handle the
; numlock key here, so I must clear
; the keyboard.
pop ax
xor aux_shift,1 ; toggle scroll lock key
end_int: mov al,eoi ; issue EOI to 8259 controller
out int_ctrl,al
pop ax ; clean up the stack. AX is pushed at
; beginning of the new9h proc. This pops
; that push.
iret
;************************************************************************
; The numloc key is down, aux_shift is 1, so when key is pressed,
; execution comes here to substitute one of the upper 128 characters
; for the character pressed. An extended ASCII code is selected from the
; tables depending on which scan code is intercepted. Then the ASCII
; code is stuffed into the keyboard buffer. The scan code is discarded.
;*************************************************************************
newkey: push ax
call get_status ; get status of the rt & lft shft keys.
; This determines whether the ASCII code
; is selected from the upper case letters
; or the lower case letters.
call reset_kb ; reset keyboard.
pop ax
test al,80h ; is the high bit set
jnz newkey3 ; yes, then don't process it.
push bx ; no, save bx.
mov bx,offset lower_case ; start with lower case and if
and kb_stat1,67 ; the shft keys are not pressed,
jz newkey1 ; then stick with lower case, else
mov bx,offset upper_case ; change to upper case.
newkey1: mov ah,al ; transfer scan code to AH
dec al ; set al relative to zero base
xlat lower_case ; Get ASCII code from table
or al,al ; is it 0
je newkey2 ; yet, then don't process this key.
; I don't think I need to check if it
; is zero. I think I took care of
; all the keys with zero ASCII values
; at the beginning of this program.
; for ex: cmp al,1 ; esc key
; je exit
call insert_char ; insert key into keyboard buffer
newkey2: pop bx ; restore bx register value
newkey3: mov al,eoi ; issue end of interrupt signal
out int_ctrl,al
pop ax ; restore ax and clean up the stack
iret
new9h endp
;--------------------------------------------------------------------
; Resets the keyboard
;--------------------------------------------------------------------
reset_kb proc near
in al,kb_ctrl ; get control port value
mov ah,al ; Save it in ah.
or al,80h ; Sets the high bit of
; the value, which means
; the key was released.
out kb_ctrl,al ; Sends this value, out the cntrl
; port, which resets the keyboard.
mov al,ah ; get the original cntrl
; value
out kb_ctrl,al ; Send it out the ctrl
; port, which enables the
; keyboard
ret
reset_kb endp
; -----------------------------------------------------------------------
; Get_Status returns the main keyboard shift status byte in al
; then save the status of the left and right shift keys in kb_stat1
; -----------------------------------------------------------------------
get_status proc near
push ds ; save ds
mov ax,bios_data
mov ds,ax ; point ds to bios data area
assume ds:bios_data
mov al,kb_status ; get status byte in al.
pop ds ; restore ds
assume ds:nothing
mov kb_stat1,al ; we need Get_status, because
; kb_stat1 holds the shift key
; and tells us whether we need to
; use lower_case or upper_case to
; translate the character.
ret
get_status endp
;
; -------------------------------------------------------------------
; Inserts the character code in AX into the keyboard buffer.
; Entry AH,AL - scan code, ascii code.
; --------------------------------------------------------------------
insert_char proc near
push dx
push ds
mov bx,bios_data
mov ds,bx
assume ds:bios_data
mov bx,buffer_tail ; get current buffer tail address
mov dx,bx ; transfer it to dx
add dx,2 ; calculate next buffer position
cmp dx,buffer_end ; Did we over shoot the end.
jne insert1 ; No, then continue
mov dx,buffer_start ; Yes, then wrap around
insert1: cmp dx,buffer_head ; is the buffer full
je insert2 ; Yes, then branch
mov [bx],ax ; deposit character into buffer
mov bx,dx ; advance buffer tail
mov buffer_tail,bx ; record its new value
insert2: pop ds
assume ds:nothing
pop dx ; restore dx
ret ; exit
insert_char endp
ret
initialize proc near
mov ax,0c000h ; set es to ega bios segment
mov es,ax
mov di,1eh ; point di to signature location
lea si,ibm ; point si to 'ibm' text
mov cx,3 ; three bytes to compare
cld ; clear df
repe cmpsb ; check three bytes
je init1 ; branch if signature found
; determine whether adapter is a cga or an mda
dec adapter ; decrement assumed value
mov ah,15 ; get current video mode
int 10h
cmp al,7 ; is it mode 7?
jne init1 ; No, then it's a CGA
; The display adapter is an mda. Modify video attributes
dec adapter ; reset adapter value to mda
sub video_segment,800h ; modify video segment value
init1: mov cx,cursor_mode ; set scan lines in cx
mov ah,1 ; video function, set cursor
int 10h ; reset cursor
; get and save the address of the CRT Controller
mov ax,40h ; point EX to BIOS data area
mov es,ax
mov di,63h ; point DI to address word
mov dx,es:[di] ; get CRTC address
mov addr_6845,dx ; Save it
; Save the old interrupt 9 vector and replace it with a new one
mov ax,3509h ; get current interrupt 9 vector
int 21h
mov old9h_vector,bx ; save it
mov old9h_vector[2],es
mov ah,25h ; then point it to NEW9H
lea dx,new9h
int 21h
; Terminate, leaving additional room for screen buffering. Whoops, I don't
; think I need screen buffering. That was necessary for KBX.COM, not for me.
mov dx,offset initialize+1 ; +1 instead of + 1276, since
; I don't need screen buffer
; offset of last byte plus 1 (relative to PSP) of
; the program to remain resident.
int 27h ; terminate, but stay resident.
initialize endp
;---------------------------------------------------
code ends ; end of code segment
; **************************************************
end begin ;end assembly
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/