Category : Assembly Language Source Code
Archive   : EMAC15ES.ZIP
Filename : IBM.ASM

 
Output of file : IBM.ASM contained in archive : EMAC15ES.ZIP
;History:382,1
;Sun May 28 00:52:17 1989 Use a different method of testing for enhanced keyboards.
;Sun May 07 00:40:17 1989 Move mouse code from pick.asm to ibm.asm
;Wed May 03 22:15:40 1989 change the arguments to ring_the_bell.
;Wed May 03 21:10:32 1989 'and' the background color with 7 to avoid blinking.
;Tue Mar 07 23:57:47 1989 add parameters to ring_the_bell
;Tue Mar 07 23:50:59 1989
;Tue Mar 07 23:46:52 1989 add Jonathan Vail's visual bell code.
;Tue Feb 21 22:20:40 1989 add keypad key support.
;Sat Feb 18 16:57:32 1989 Use hardware cursor positioning for EGA only.
;Fri Feb 17 22:35:11 1989 cleaned up snow-avoidance code a little.
;Mon Jan 30 22:58:16 1989 change the parameters for set_screen_color.
;08-25-88 23:37:09 Create two new keycodes, "C- " and "M- ".
;05-30-88 22:27:44 fix a small problem in save/restore screen
;05-29-88 22:49:48 try getting the attributes from lower left.
;05-29-88 22:42:39 get the attributes from the lower right corner rather than upper right.
;05-27-88 23:25:34 fix a problem in putch where it put garbage characters up.
;05-27-88 00:09:00 read_ibm_cga sometimes gets called with ds=bufseg, not data.
;05-27-88 00:07:02 move_line didn't respect ibm_cga flag--it was always set.
;05-17-88 20:33:20 Add support for hardware scrolls (should work for all displays) [kdb]
;05-17-88 20:02:45 Make move_line wait while reading cga screen [kdb]
;05-17-88 19:35:35 Remove all reference to scrwait function [kdb]
;05-17-88 19:03:22 Macroize scrwait for single char [kdb]
;05-15-88 19:16:51 add scrwait in scrolls [kdb]
;05-15-88 18:58:45 Make move_line wait for each character [kdb]
;05-07-88 22:07:59 implement a swap_screen_flag.
;05-03-88 23:54:55 add more extended keys.
;04-17-88 19:22:28 add some extended keycodes.
;04-16-88 13:13:01 add extended keyboard support.
;04-14-88 22:51:58 If ibm_cga, don't store_debug.
;04-01-88 23:08:28 respond to mouse keys with M-, S-, and C-
;03-31-88 22:02:25 use C-break for the break character (duh)
;03-28-88 19:19:14 just clear the screen on a MDA.
;03-28-88 19:09:19 don't save and restore video memory on an MDA.
;03-28-88 18:28:50 remove block_cursor and under_cursor
;03-26-88 21:59:07 change back to bios calls to read the keyboard.
;03-24-88 00:02:13 add fore_original and back_original.
;02-21-88 12:24:50 make control be bright, meta inverse video.
;02-13-88 18:22:56 use the 18.2 ms timer tick to time the beep.
;02-13-88 16:43:45 don't map Timeout using M-, C-, or S-
;12-07-87 20:07:29 add store_debug
;12-05-87 11:23:35 make the color default to the current color.
;12-05-87 11:20:13 clear the screen on init_entry.
;12-05-87 11:16:53 save dos's screen and restore it when finished.
;07-05-87 22:14:22 caps lock shouldn't apply to M- and C- keys.
page ,132

comment /

Porting EMACS and Percival to MS-DOS computers other than the Z-100:

This entire file (Z-100.ASM) needs to be re-written, since it contains
all the Z-100 dependencies. The following conventions must be maintained:
1) Never leave this module with DF=1.
2) Never destroy ES.
3) Never MOV AX,DATA, always use the copy in the appropriate segment register.
4) Return NC if a routine succeeds, or fulfills its goals.

/
.xlist
include memory.def


data segment byte public

public max_screen_line
max_screen_line db 22 ;number of last text row on screen.

public num_screen_cols
num_screen_cols db ?
db 0 ;in case they access it as a word.

public fore_original, back_original
fore_original db ?
back_original db ?


public scan_lines_per_char
scan_lines_per_char db 8

public computer_name, computer_name_len
computer_name db 'IBM-PC'
computer_name_len equ $-computer_name

public swap_screen_flag
swap_screen_flag dw 1 ;=1 if we should swap screens.

old_cursor dw ? ;old cursor position from the swapped
; screen.

mouse_flag db ?
mouse_buttons db ?


key_names label byte
db ',','Comma',0
db '(','LPar',0
db ')','RPar',0
db 7fh,'Delete',0

db -1,'Timeout',0
db -2,'Left Down',0 ;mouse button key names.
db -3,'Right Down',0
db -4,'Left Up',0
db -5,'Right Up',0
db -6,'Middle Down',0
db -7,'Middle Up',0
db 0


key_others label byte
db 14,'Back Space',0
db 15,'Tab',0
db 28,'Return',0
db 1,'Escape',0

db 71,'KP7',0 ;Home
db 72,'KP8',0 ;UpArrow
db 73,'KP9',0 ;PgUp
db 74,'KP-',0 ;MMinus
db 75,'KP4',0 ;LeftArrow
db 76,'KP5',0 ;Five
db 77,'KP6',0 ;RightArrow
db 78,'KP+',0 ;MPlus
db 79,'KP1',0 ;End
db 80,'KP2',0 ;DownArrow
db 81,'KP3',0 ;PgDn
db 82,'KP0',0 ;Ins
db 83,'KP.',0 ;Del

db 0


key_special label byte
db 127,'C-Back Space',0
db 10,'C-Return',0
db 0

key_table label byte
db 1,'M-Esc',0 ;extended
db 3,'C-@',0
db 14,'M-Back Space',0 ;extended
db 15,'S-Tab',0
db 16,'M-q',0
db 17,'M-w',0
db 18,'M-e',0
db 19,'M-r',0
db 20,'M-t',0
db 21,'M-y',0
db 22,'M-u',0
db 23,'M-i',0
db 24,'M-o',0
db 25,'M-p',0
db 26,'M-{',0 ;extended
db 27,'M-}',0 ;extended
db 28,'M-Return',0 ;extended
db 30,'M-a',0
db 31,'M-s',0
db 32,'M-d',0
db 33,'M-f',0
db 34,'M-g',0
db 35,'M-h',0
db 36,'M-j',0
db 37,'M-k',0
db 38,'M-l',0
db 39,'M-;',0 ;extended
db 40,"M-'",0 ;extended
db 41,'M-`',0 ;extended
db 43,'M-\',0 ;extended
db 44,'M-z',0
db 45,'M-x',0
db 46,'M-c',0
db 47,'M-v',0
db 48,'M-b',0
db 49,'M-n',0
db 50,'M-m',0
db 51,'M-Comma',0 ;extended
db 52,'M-.',0 ;extended
db 53,'M-/',0 ;extended
db 55,'M-Asterisk',0
db 59,'F1',0
db 60,'F2',0
db 61,'F3',0
db 62,'F4',0
db 63,'F5',0
db 64,'F6',0
db 65,'F7',0
db 66,'F8',0
db 67,'F9',0
db 68,'F10',0
db 71,'Home',0
db 72,'Up Arrow',0
db 73,'Pg Up',0
db 74,'M-Minus',0
db 75,'Left Arrow',0
db 76,'Five',0
db 77,'Right Arrow',0
db 78,'M-Plus',0
db 79,'End',0
db 80,'Down Arrow',0
db 81,'Pg Dn',0
db 82,'Ins',0
db 83,'Del',0
db 84,'S-F1',0
db 85,'S-F2',0
db 86,'S-F3',0
db 87,'S-F4',0
db 88,'S-F5',0
db 89,'S-F6',0
db 90,'S-F7',0
db 91,'S-F8',0
db 92,'S-F9',0
db 93,'S-F10',0
db 94,'C-F1',0
db 95,'C-F2',0
db 96,'C-F3',0
db 97,'C-F4',0
db 98,'C-F5',0
db 99,'C-F6',0
db 100,'C-F7',0
db 101,'C-F8',0
db 102,'C-F9',0
db 103,'C-F10',0
db 104,'M-F1',0
db 105,'M-F2',0
db 106,'M-F3',0
db 107,'M-F4',0
db 108,'M-F5',0
db 109,'M-F6',0
db 110,'M-F7',0
db 111,'M-F8',0
db 112,'M-F9',0
db 113,'M-F10',0
db 114,'C-PrtSc',0
db 115,'C-Left Arrow',0
db 116,'C-Right Arrow',0
db 117,'C-End',0
db 118,'C-Pg Dn',0
db 119,'C-Home',0
db 120,'M-1',0
db 121,'M-2',0
db 122,'M-3',0
db 123,'M-4',0
db 124,'M-5',0
db 125,'M-6',0
db 126,'M-7',0
db 127,'M-8',0
db 128,'M-9',0
db 129,'M-0',0
db 130,'M--',0
db 131,'M-=',0
db 132,'C-Pg Up',0
;all of the following are extended.
db 133,'F11',0
db 134,'F12',0
db 135,'S-F11',0
db 136,'S-F12',0
db 137,'C-F11',0
db 138,'C-F12',0
db 139,'M-F11',0
db 140,'M-F12',0
db 141,'C-Up Arrow',0
db 142,'C-Minus',0
db 143,'C-Five',0
db 144,'C-Plus',0
db 145,'C-Down Arrow',0
db 146,'C-Ins',0
db 147,'C-Del',0
db 148,'C-Tab',0
db 149,'C-Slash',0
db 150,'C-Asterisk',0
db 151,'M-Home',0
db 152,'M-Up Arrow',0
db 153,'M-Pg Up',0
db 155,'M-Left Arrow',0
db 157,'M-Right Arrow',0
db 159,'M-End',0
db 160,'M-Down Arrow',0
db 161,'M-Pg Dn',0
db 162,'M-Ins',0
db 163,'M-Del',0
db 164,'M-Slash',0
db 165,'M-Tab',0
db 166,'M-Return',0
db 167,'C- ',0
db 168,'M- ',0

; db 224,'Slash',0
; db 224,'Return',0

db 0,'Unknown',0


one_key_string db ?,0
ctrl_key_string db 'C-'
ctrl_key_char db ?,0

left_flag equ 1
right_flag equ 2
ctrl_flag equ 4
alt_flag equ 8
all_flags equ left_flag + right_flag + ctrl_flag + alt_flag
shift_flags db ?

bios_seg segment at 40h
org 17h
bios_shifts db ?
bios_seg ends


key_buffer label byte ;this is where we put the ASCII
db 26 dup(?) ; representation of the key.


extrn inversing: word ;if we're inverse videoing.

public color
color db 0fh ;xbbbifff bbb=background, ifff=fore.
control_color db 1fh ;attributes for control characters.
whitespc_color db 0fh ;attributes for whitespace characters.

font_8_table label byte
db 007h ;visi space
db 004h ;visi tab
db ? ;del
db ? ;eof
db ? ;visi newline
db 01ah ;right arrow
db ? ;random char.
db 01fh ;visible newline.

ibm_cga db 0 ;=0 if we can write to screen anytime,
;=1 if we should wait for retrace.
have_ega db 0 ;=0 if we don't have an EGA.

int_16_input db 0 ;function code for keyboard input
int_16_status db 1 ;function code for keyboard status

data ends


code segment byte public
assume cs:code, ds:data, es:nothing
;all of the code in this segment is called with the above assumes.

break_flag db ?

their_1b dd ?
our_1b:
mov cs:break_flag,1
iret


public init_entry
init_entry:
push es ;get their C-break.
mov ax,351bh
int 21h
mov word ptr their_1b+0,bx
mov word ptr their_1b+2,es
pop es

push ds ;set our C-break.
mov ax,cs
mov ds,ax
mov dx,offset our_1b
mov ax,251bh
int 21h
pop ds

;
;Determine whether or not the BIOS supports extended keyboard functions.
;
if 0
mov ah,5 ;write FFFFh to keyboard buffer
mov cx,0FFFFh
int 16h
mov ah,10h ;then read it back
int 16h
cmp ax,0FFFFh ;is AX set correctly?
jne init_entry_0 ;no - they don't have an extended kbd.
else
push ds
mov ax,40h
mov ds,ax
mov al,ds:[96h] ;keyboard support byte.
pop ds
test al,10h
je init_entry_0 ;no - they don't have an extended kbd.
endif
mov int_16_input,10h ;yes - use extended keyboard function codes.
mov int_16_status,11h
init_entry_0:

;
;Now set the video mode to one that we can use.
;
mov ah,15
int 10h ;get video state of the PC
mov num_screen_cols,40
cmp al,1 ;40 column text mode?
jbe init_entry_1 ;Yes, ok.
mov num_screen_cols,80
cmp al,3 ;Is screen CGA Text?
jbe init_entry_1 ;Yes, ok.
cmp al,7 ;Is screen MDA?
je init_entry_5 ;Yes, ok - but we can't have an EGA.
;;; This is wrong! We can have an EGA driving a monochrome monitor. Fix it.

mov ax,0*256 + 3 ;use 25x80 color if some strange mode.
int 10h

init_entry_1:
mov ax,1200h ;test for an EGA
mov bx,10h
mov cx,-1
int 10h
cmp cx,-1
je init_entry_2 ;no EGA.

mov have_ega,1 ;remember that we have an EGA.

push ds ;get the max scanlines.
xor ax,ax
mov ds,ax
mov al,ds:[484h]
mov ah,ds:[485h]
mov cl,ds:[44ah]
pop ds

mov num_screen_cols,cl ;remember how wide it is.
sub al,2 ;leave room for a status and minibuffer line.
mov max_screen_line,al

init_entry_2:
cmp swap_screen_flag,0 ;should we swap the screen?
je init_entry_4 ;no.

mov bh,0
mov ah,3 ;get cursor position
int 10h
mov old_cursor,dx

mov dl,max_screen_line ;copy the page zero to page one.
add dl,2
mov al,dl
inc al
add al,dl
init_entry_3:
call move_line ;enter with dl=source, al=destination.
dec al
dec dl
jns init_entry_3

init_entry_5:
push es
mov dh,0
mov dl,max_screen_line
add dl,2
call get_video_ptr
mov ax,es:[di] ;get the attributes from the lower left.
pop es
mov fore_original,ah
and fore_original,0fh
mov cl,4 ;rotate the background to where we
shr ah,cl ; want it.
and ah,7
mov back_original,ah

clear_screen:
mov dh,0 ;clear the screen.
mov dl,max_screen_line
add dl,2
clear_screen_1:
call clear_to_eol ;enter with dl=row, dh=column.
dec dl
jns clear_screen_1
init_entry_4:
ret


public uninit_exit
uninit_exit:
;called when exiting. May destroy any but seg-regs.

push ds ;restore C-break.
lds dx,their_1b
mov ax,251bh
int 21h
pop ds

cmp swap_screen_flag,0 ;should we swap the screen?
jne uninit_exit_4 ;yes.
ret ;no.
uninit_exit_4:

mov ah,15
int 10h ;get video state of the PC
cmp al,7 ;don't restore the memory on an MDA
je uninit_exit_1 ; 'cuz it ain't there.

mov dx,old_cursor
mov bh,0
mov ah,2 ;set cursor position
int 10h

mov al,max_screen_line ;copy the page one to page zero.
add al,2
mov dl,al
add dl,dl
uninit_exit_3:
call move_line ;enter with dl=source, al=destination.
dec dl
dec al
jns uninit_exit_3
ret

uninit_exit_1:
mov dl,0
mov dh,max_screen_line
add dh,2
mov bh,0
mov ah,2 ;set cursor position
int 10h

call clear_screen

ret


outreg macro port,value
mov al,port
out dx,al
inc dx
mov al,value
out dx,al
dec dx
endm


if 0
set_start_addr:
;given screen_start (the first text line on the screen), scan_row (the first
; scan row we're displaying), and bot_window, set the appropriate registers.

mov dx,03dah ;wait for vertical retrace.
cli ;no interrupts.
set_start_addr_h:
in al,dx ;Wait for horizontal retrace
test al,8 ; so will catch vertical
jz set_start_addr_h ; retrace at start.
set_start_addr_v:
in al,dx ;Wait for vertical retrace.
rcr al,1
jc set_start_addr_v

mov dx,03d4h

mov bx,screen_start ;screen_start is given in terms of
shr bx,1 ; bytes, but we need words.
outreg 0ch,bh ;the high byte of the starting address.
outreg 0dh,bl ;the low byte of the starting address.

outreg 08h,scan_row ;Preset row scan.

mov bx,bot_window
shl bh,1 ;put the bit in the right place.
shl bh,1
shl bh,1
shl bh,1
or bh,0fh ;assume that the rest are ones.

outreg 18h,bl ;set the low byte of line compare.
outreg 07h,bh ;set the overflow bits.

sti

ret
endif


public store_ibm_cga
store_ibm_cga:
cmp have_ega,0 ;do we have an EGA?
jne store_ibm_cga_1 ;yes - we know better than they do,
mov ibm_cga,al ; so ignore them.
store_ibm_cga_1:
ret


public store_debug
store_debug:
if 0
cmp ibm_cga,0 ;don't do this on an IBM CGA.
jne store_debug_1
push ds
push es
push ax
mov ax,data
mov ds,ax
mov es,ax
mov dh,num_screen_cols
sub dh,2
mov dl,max_screen_line
inc dl
call get_video_ptr ;enter with dl=current row, dh=current column.
;return with es:di->character position.
pop ax

mov es:[di],al
mov es:[di+2],ah
pop es
pop ds
store_debug_1:
endif
ret


;this routine should check for a break character. Return cy if none,
; nc if we should break.
public check_breakchar
check_breakchar:
cmp cs:break_flag,0 ;test the break flag.
mov cs:break_flag,0 ;clear the break flag.
stc
je check_breakchar_1
clc
check_breakchar_1:
ret


public check_for_key
check_for_key:
;return zr,ax=0 if no key is waiting.
;return nz,ax=key if a key is waiting, but don't input the key yet.
mov ah,int_16_status ;check for a key.
int 16h
jne check_for_key_1 ;go if we got a key.
mov ax,0 ;return ax=0 if we didn't.
check_for_key_1:
ret


public get_key_value
get_key_value:
;exit with ax=keycode.
mov ah,int_16_input
int 16h
ret


public decode_key
decode_key:
;enter with ax=key value.
;exit with si,cx -> the key's name in ASCII.
mov di,offset key_buffer

cmp ax,0f9h ;one of the mouse buttons?
jb decode_key_7
cmp ax,0feh
ja decode_key_7

push ax
push ds
mov ax,bios_seg
mov ds,ax
assume ds:bios_seg

mov ah,bios_shifts
and ah,all_flags ;isolate the flags we're interested in.
pop ds
assume ds:data
mov shift_flags,ah
call decode_meta
call decode_ctrl
call decode_shift
pop ax

decode_key_7:

or al,al ;extended function key?
je decode_key_5
cmp al,0e0h
je decode_key_5

push ax ;now we look for ASCII keys that
mov si,offset key_others ; have dedicated keys.
call decode_search ;search for the scan code names.
pop ax
jne decode_key_2 ;go if we found it.

mov ah,al
mov si,offset key_names ;now search for the ASCII keys that
; we don't (or can't) represent.
call decode_search ;search for the literal names.
jne decode_key_1 ;copy it in.
mov al,ah

cmp al,' ' ;control char?
jae decode_key_6 ;no
add al,'`' ;yes - convert into letter.
mov ctrl_key_char,al
mov si,offset ctrl_key_string
cmp al,'z' ;control character > 'C-z'?
jbe decode_key_1 ;no.
sub ctrl_key_char,'`'-'@' ;yes - make it C-[, not C-{
jmp short decode_key_1
decode_key_2:
push si
mov si,offset key_special
mov ah,al ;now see if it's one of the ones we
call decode_search ; know are special.
pop ax
jne decode_key_1 ;yes - it is.
mov si,ax
jmp short decode_key_1
decode_key_6:
mov one_key_string,al
mov si,offset one_key_string
jmp short decode_key_1

decode_key_5:
mov si,offset key_table ;search for the extended functions.
call decode_search
decode_key_1:
lodsb ;copy to the next null.
stosb
or al,al
jne decode_key_1
dec di ;don't include the null.
mov si,offset key_buffer
mov cx,di
sub cx,si
ret


decode_ctrl:
test shift_flags,ctrl_flag
je decode_ctrl_1
mov ax,'C' + '-'*256
stosw
decode_ctrl_1:
ret


decode_shift:
test shift_flags,left_flag + right_flag
je decode_shift_1
mov ax,'S' + '-'*256
stosw
decode_shift_1:
ret

decode_meta:
test shift_flags,alt_flag
je decode_meta_1
mov ax,'M' + '-'*256
stosw
decode_meta_1:
ret


decode_search:
;enter with ah=key to search for, si->table.
;exit with al=key, nz if found, al=0, zr if not found.
lodsb
or al,al ;end of table?
je decode_search_2 ;yes - try shifted values.
cmp al,ah ;is this the key?
je decode_search_2 ;yes.
decode_search_1:
lodsb ;skip to the next null.
or al,al
jne decode_search_1
jmp decode_search
decode_search_2:
or al,al
ret


public ring_the_bell
ring_the_bell:
;enter with bx = first argument, cx = second argument.
or cx,cx
jne ring_the_bell_1
mov cx,1 ;defaults to duration of one.
ring_the_bell_1:
or bx,bx ;negative frequency?
jl vbell ;yes - they must want a visual bell.


;Beep procedure count values
;---------------------------
;To generate a given freqency note out of the speaker with the Beep procedure
;on the PC using Channel 2 of the 8253 timer, the channel 2 count register
;must be loaded with a value such that the 8253 input clock frequency
;(1.19318 MHz) divided by the count figure equals the audio frequency.
;enter with bx=count figure for frequency to be generated.
beep:
push cx
mov cx,1
call sleep
pop cx
mov al,0b6h ; Channel 2, LSB then MSB, Square Wave, Binary
out 43h,al ; Program 8253 command register
mov ax,bx ; Get the frequency to be generated
out 42h,al ; Load Channel 2 count register LSB
mov al,ah
out 42h,al ; Load Channel 2 count register MSB
in al,61h ; Read settings from 8255 PPI I/O Port "PB"
mov ah,al ; Save original settings in AH
or al,3 ; Enable Timer Channel 2 & Speaker data
out 61h,al ; program the 8255 with new setting-speaker on
call sleep ; Wait for a while.
mov al,ah ; Get original 8255 Port "PB" settings
out 61h,al ; Reset port to original values-speaker off
ret


vbell:
push cx
mov cx,1 ;get syncronized with the timer
call sleep

call reverse

pop cx ;now wait that many seconds.
or cx,cx ;if zero duration, just wait one tick.
jne vbell_1
mov cx,1
vbell_1:
call sleep

reverse:
push di ; Save es,di
push es
call get_video_seg

mov ah,num_screen_cols ; Calc number of chars
mov al,max_screen_line
add al,2 ; the entire screen
mul ah
mov cx,ax
mov di,1 ; Offset to start at
rev1:
mov al,es:[di] ; Reverse the foreground/background
rol al,1
rol al,1
rol al,1
rol al,1
and al,77h
and byte ptr es:[di],not 77h
or es:[di],al
add di,2
loop rev1

pop es
pop di

ret


sleep:
;pause for cx 18ths.
push bx
push ds ; make ds = bios.
mov ax,40h
mov ds,ax
wait2:
mov bx,ds:[6ch] ; Get the current timer value.
wait1:
cmp bx,ds:[6ch] ; Did the timer value "tick"?
je wait1 ; No - keep waiting for a tick.
loop wait2 ; LOOP is first executed
pop ds
pop bx
ret


code ends

code segment byte public
assume cs:code, ds:nothing, es:data, ss:data
;all of the code in this segment is called with the above assumes.


public read_ibm_cga
read_ibm_cga:
mov al,ibm_cga
ret


public position_cursor
position_cursor:
;enter with dh=col (0...80), dl=row (0..max_screen_line)
;exit with cursor set to that position.
push bx
push dx
push si
push di
push bp

xchg dh,dl
mov bh,0
mov ah,2 ;set cursor position
int 10h

pop bp
pop di
pop si
pop dx
pop bx
ret


crt_status equ 3dah ; crt status port

;requires dx = crt_status. Destroys ax.
retrace_wait macro
local loop1,loop2
loop1:
in al,dx
shr al,1 ; display enabled?
jc loop1 ; yes, keep waiting
loop2:
in al,dx
shr al,1 ; now wait for it to go off
jnc loop2 ; so can have whole cycle
endm


public move_line
move_line:
;enter with dl=source row, al=destination row.
push ax
push bx
push cx
push dx
push si
push di
push bp
push ds
push es

push ax ;compute the source byte.
mov al,num_screen_cols
mul dl
shl ax,1
mov si,ax
pop ax

mov ah,num_screen_cols ;compute the destination byte.
mul ah
shl ax,1
mov di,ax

mov cx,word ptr num_screen_cols ;move the line.
call get_video_seg ;get the video card plane.
mov ds,ax
assume ds:nothing, es:nothing

cmp ibm_cga,0
je move_line_2

mov dx,crt_status ;load it only once.
move_line_1:
retrace_wait
lodsw ;get our char into bx.
mov bx,ax
retrace_wait
mov ax,bx
stosw
loop move_line_1
jmp short move_line_3

move_line_2:
rep movsw

move_line_3:

pop es
pop ds
assume ds:nothing, es:data
pop bp
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret


public clear_to_eol
clear_to_eol:
;enter with dl=current row, dh=current column.
push bx
mov bl,num_screen_cols
call clear_count
pop bx
ret


public clear_count
clear_count:
;enter with dl=current row, dh=current column, bl=column to clear to.
push ax
push bx
push cx
push si
push di
push bp
push es
clear_count_0:
cmp dh,bl ;already past it?
jae clear_count_3 ;yes.

mov ah,color
mov al,' ' ;clear to the background color.
push ax
call get_video_ptr
assume ds:nothing, es:nothing

mov cl,bl ;compute the number of chars to clear.
sub cl,dh
mov ch,0

pop ax

cmp ibm_cga,0 ;slow refresh?
je clear_count_2

mov bx,ax ;retrace_wait destroys ax.
mov dx,crt_status ;load it only once.
clear_count_1:
retrace_wait
mov ax,bx
stosw
loop clear_count_1
jmp short clear_count_3

clear_count_2:
rep stosw

clear_count_3:
pop es
assume ds:nothing, es:data
pop bp
pop di
pop si
pop cx
pop bx
pop ax
ret


get_video_ptr:
;enter with dl=current row, dh=current column.
;doesn't destroy bx.
;return with es:di->character position.
mov al,num_screen_cols ;compute the offset of the char.
mul dl
add al,dh
adc ah,0
shl ax,1
mov di,ax
get_video_seg:
;return with es,ax=video segment.
xor ax,ax
mov es,ax
mov ax,0b000h
cmp byte ptr es:[449h],7 ;MDA?
je get_video_seg_1 ;yes - we have the segment already.
mov ax,0b800h ;no - segment at b800h.
get_video_seg_1:
mov es,ax
ret


public xychrout
xychrout:
;enter with dh=col, dl=row, al=character to print, ah=font to print it in.
push ax ;save everything that we might need.
push bx
push cx
push dx
push di
push si
push es
push ds
mov bx,es
mov ds,bx
cmp dh,num_screen_cols ;past the right margin?
jae xychrout_3 ;yes - don't print.
cmp ah,0 ;font zero?
jne xychrout_5 ;no - print specially.
mov ah,color ;assume no inverse video
cmp al,20h ;print control chars specially.
jb xychrout_control
cmp al,0ffh ;print 255 specially
jne xychrout_1 ;everything else gets printed normally.
xychrout_del:
mov al,7fh-'@' ;show bold del.
xychrout_control:
mov ah,control_color
add al,'@'
jmp short xychrout_1
xychrout_5:
mov ah,whitespc_color
mov bx,offset font_8_table
sub al,4dh ;first character in font 8.
xlat
xychrout_1:
mov bx,inversing ;set the inverse video flag.
and bl,77h ;strip out just the color.
xor ah,bl ;now flip the colors (if desired).
mov bx,ax ;save the char in bx.
call get_video_ptr
assume ds:nothing, es:nothing
cmp ibm_cga,0 ;if we have an IBM CGA, we have to wait
je xychrout_4 ; for retrace, otherwise not.
mov dx,crt_status
retrace_wait
xychrout_4:
mov ax,bx
stosw
xychrout_3:
pop ds
pop es
assume ds:nothing, es:data
pop si
pop di
pop dx
pop cx
pop bx
pop ax
ret


public hardware_roll_down
hardware_roll_down:
;exit: if this machine is capable of hardware roll, do it and exit with cy=0,
; otherwise, exit with cy=1. The hardware roll must leave the last line
; on the screen as the last line.
;preserve bx.
cmp ibm_cga,0
je no_roll_down

push bx
push cx
push dx
mov ch,ah
mov cl,0
mov dh,al
mov dl,num_screen_cols
dec dl
mov bh,color
mov ax,701h
int 10h
pop dx
pop cx
pop bx
clc
ret
no_roll_down:
stc
ret


public hardware_roll_up
hardware_roll_up:
;exit: if this machine is capable of hardware roll, do it and exit with cy=0,
; otherwise, exit with cy=1. The hardware roll must leave the last line
; on the screen as the last line.
;preserve bx.
cmp ibm_cga,0
je no_roll_up

push bx
push cx
push dx
mov ch,ah
mov cl,0
mov dh,al
mov dl,num_screen_cols
dec dl
mov bh,color
mov ax,601h
int 10h
pop dx
pop cx
pop bx
clc
ret
no_roll_up:
stc
ret


public set_screen_color
set_screen_color:
;enter with si -> list of colors (fore, back, control, whitespc)
mov cl,4
mov ah,[si+1] ;background doesn't change.
shl ah,cl
and ah,70h ;don't let them set blinking colors.
mov al,[si] ;compute the normal attributes.
or al,ah
mov color,al
mov al,[si+2] ;now the control attributes.
or al,ah
mov control_color,al
mov al,[si+3] ;now the whitespace attributes.
or al,ah
mov whitespc_color,al
ret


public pick_init, pick_on, pick_off, check_pick, get_pick_values
pick_init:
call mouse_exists
mov ax,0
int 33h
mov mouse_flag,al ;remember if the mouse exists.
mov mouse_buttons,bl ;remember the number of buttons.
mov ax,4 ;move the mouse to the upper right hand.
mov cx,635
mov dx,0
int 33h
mov ax,10 ;set text cursor (ignored on Z-100).
mov bx,0 ;software text cursor.
mov cx,77ffh ;screen mask
mov dx,7700h ;cursor mask
int 33h

mov al,max_screen_line ;compute the "number of scan lines"
add al,2
mul scan_lines_per_char
dec dx
mov dx,ax ;set the "number of scan lines"
mov cx,0
mov ax,8
int 33h

mov al,8 ;we're assuming nine bits per char.
mul num_screen_cols
dec ax
mov dx,ax ;set the "number of bit columns"
mov cx,0
mov ax,7
int 33h

call check_pick ;ensure that there are no up or down
call check_pick ; events left.
call check_pick
call check_pick
call check_pick
call check_pick
ret


pick_on:
call mouse_exists
mov ax,1
int 33h
ret


pick_off:
call mouse_exists
mov ax,1 ;ensure that we work with MOUSEKEY.
int 33h
mov ax,2
int 33h
ret


check_pick:
;return nz and al=pick character. return zr if no pick.
call mouse_exists
push bx
push cx
push dx
cmp mouse_flag,0 ;inhibit mouse presses if it isn't there.
je check_pick_1
mov ax,5
mov bx,0 ;left button press
int 33h
mov ax,0feh
or bx,bx
jne check_pick_1
mov ax,5 ;right button press
mov bx,1
int 33h
mov ax,0fdh
or bx,bx
jne check_pick_1
mov ax,6 ;left button release
mov bx,0
int 33h
mov ax,0fch
or bx,bx
jne check_pick_1
mov ax,6 ;right button release
mov bx,1
int 33h
mov ax,0fbh
or bx,bx
jne check_pick_1
cmp mouse_buttons,2 ;do we have only two buttons?
je check_pick_1 ;yes - no pick.
mov ax,6 ;middle button release
mov bx,2
int 33h
mov ax,0f9h
or bx,bx
jne check_pick_1
mov ax,5 ;middle button press
mov bx,2
int 33h
mov ax,0fah
or bx,bx
jne check_pick_1
check_pick_1:
pop dx
pop cx
pop bx
ret

get_pick_values:
mov cx,0
mov dx,0
call mouse_exists
mov ax,3
int 33h

push cx ;save the x value.

mov ax,dx
div scan_lines_per_char
mov ah,0
push ax
call read_linesbefore
push ax
call read_newrow
pop bx
sub bx,ax ;bx=linesbefore - newrow.
pop dx
add dx,bx ;add y-value.
inc dx ;ax= y-value - newrow + linesbefore + 1.
pop ax ;compute the x-value.

push dx

mov cl,8
div cl
mov ah,0
inc ax
push ax ;add in firstcolumn.
call read_firstcolumn
pop cx
add cx,ax

pop dx

ret

extrn read_firstcolumn: near
extrn read_linesbefore: near
extrn read_newrow: near


;this routine returns from the routine that called it if the mouse is not
; installed.
mouse_exists:
push ds
xor ax,ax
mov ds,ax
mov ax,word ptr ds:[33h*4+2]
pop ds
cmp ax,0 ;any mouse interrupt at all?
je mouse_exists_2 ;no - no mouse.
cmp ax,40h ;is the mouse interrupt in the bios?
jne mouse_exists_1 ;no - must be a real mouse.
mouse_exists_2:
add sp,2
xor ax,ax
ret
mouse_exists_1:
ret

code ends

end


  3 Responses to “Category : Assembly Language Source Code
Archive   : EMAC15ES.ZIP
Filename : IBM.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. 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/