pagesize 86 v30 equ 1 ;Porting FREEMACS to CCPM computers assuming VT200 console with 8 bit controls ;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. if v30 ;macros for NEC V20/V30 or Intel 80186/286 codemacro SHRW parm:ew,count:db ;shift word right by db 0c1h ;immediate count modrm 5,parm db count endm codemacro SHLB parm:eb,count:db ;shift byte right by db 0c0h ;immediate count modrm 4,parm db count endm codemacro PUSHW parm:dw ;push immediate word db 068h dw parm endm codemacro PUSHALL ;push all register db 060h ;AX,CX,DX,BX,SP,BP,SI,DI endm codemacro POPALL ;pop all register db 061h ;DI,SI,BP,SP,BX,DX,CX,AX endm endif ; call_di equ word ptr 0[bp] ;\----------------/ call_si equ word ptr 2[bp] ; \ / call_bp equ word ptr 4[bp] ; \ / call_sp equ word ptr 6[bp] ;\\\\ saved by //// call_bx equ word ptr 8[bp] ;//// PUSHALL \\\\ call_dx equ word ptr 10[bp] ; / \ call_cx equ word ptr 12[bp] ; / \ call_ax equ word ptr 14[bp] ;/----------------\ call_es equ word ptr 16[bp] call_ds equ word ptr 18[bp] ; ; c_rawio equ 06h c_write equ 02h c_writestr equ 09h c_writeblk equ 6Fh p_delay equ 8Dh codemacro CCPM parm:db ;call CCPM db 0b1h ! db parm ;mov cl,parm db 0cdh ! db 0e0h ;int 0E0H endm data dseg word public public max_screen_line max_screen_line db 21 esc equ 1Bh dcs equ 90h csi equ 9Bh ;control string introducer chars st equ 9Ch ss2 equ 8Eh ss3 equ 8Fh soh equ 01h stx equ 02h etx equ 03h bs equ 08h cr equ 0Dh lf equ 0Ah sho equ 0Eh ;shift out character shi equ 0Fh ;shift in character init_cons db esc,'[62;0"p' ;set vt200 mode 8-bit controls db csi,'H' ;cursor to home db csi,'2J' ;erase to end of screen db csi,'0m' ;all attributes off db csi,'2l' ;unlock keyboard db csi,'1;22r' ;set scrolling region db esc,')0' ;designate Special Graphics to G1 ;____________________________________________________________________________ ;now we are (pre-)defining the user programable ;function keys to return an artificial CSI-sequence ;THIS CODE IS INSTALLATION DEPENDANT !!!!! db dcs,'0;1|' ;clear user function keys db '17/9B35377E;' ;User F6 db '18/9B35387E;' ;User F7 db '19/9B35397E;' ;User F8 db '20/9B36307E;' ;User F9 db '21/9B36317E;' ;User F10 db '23/1B;' ;User F11 = or C-[ db '24/08;' ;User F12 = or C-H db '25/0A;' ;User F13 = or C-J db '26/9B36367E;' ;User F14 db '28/9B36387E;' ;User Help db '29/9B36397E;' ;User Do db '31/9B37317E;' ;User F17 db '32/9B37327E;' ;User F18 db '33/9B37337E;' ;User F19 db '34/9B37347E',st;User F20 keypad_mode_str db esc,'=' ;Application Keypad db '$' ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ;______________________________________________________________________________ ;the following holds true only for our own standard terminal setup at ;the University of TUEBINGEN. ;THIS CODE IS INSTALLATION DEPENDANT !!!!! uninit_cons db dcs,'0;1|' ;reset user keys to BASF-PCI (SHIT MVS) db '17/1B34;' ;F6 4 = return db '18/1B32;' ;F7 2 = split db '19/1B39;' ;F8 9 = swap db '20/1B35;' ;F9 5 = rfind db '21/1B36;' ;F10 6 = rchange db '23/1B;' ;F11 = db '24/08;' ;F12 = db '25/0A;' ;F13 = db '26/01;' ;F14 = = home db '28/1B31;' ;HELP 1 = help db '29/1B33;' ;DO 3 = end db '31/1B37;' ;F17 7 = up db '32/1B38;' ;F18 8 = down db '33/1B30;' ;F19 0 = left db '34/1B2D',st ;F20 - = right db esc,'c' ;recall initial terminal parameters db '$' ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; roll_dn_string db csi,'H',csi,'1L$' roll_up_string db csi,'H',csi,'1M$' ins_line_string equ roll_dn_string+2 del_line_string equ roll_up_string+2 cur_pos_string db csi,'ror;colH$' clear_to_eol_string db csi,'K$' sv_cursor_string db esc,'7$' rs_cursor_string db esc,'8$' rvideo_string db csi,'0;1;7m$' key_buffer dw 0 ss3_scan_tab db 'ABCDMPQRSmlnpqrstuvwxy' Comma_key db 'Comma' LPar_key db 'LPar' RPar_key db 'RPar' delete_string db '*Delete' ctrl_string db '*C-' csi_name_tab db 41h,07,'Scan-up' db 42h,09,'Scan-down' db 43h,10,'Scan-right' db 44h,09,'Scan-left' db 01h,04,'Find' db 02h,11,'Insert-here' db 03h,06,'Remove' db 04h,06,'Select' db 05h,11,'Prev-Screen' db 06h,11,'Next-Screen' db 17h,02,'F6' db 18h,02,'F7' db 19h,02,'F8' db 20h,02,'F9' db 21h,03,'F10' db 23h,03,'F11' db 24h,03,'F12' db 25h,03,'F13' db 26h,03,'F14' public breakchar ; /this is normally the "Help" key, db 28h,05,'BREAK' ;< but here we'll use it as BREAK, breakchar equ 28h*256+csi ; \for HELP use user's key "UHelp" db 29h,02,'Do' ; \ THIS CODE IS INSTALLATION DEPENDANT !! db 31h,03,'F17' db 32h,03,'F18' db 33h,03,'F19' db 34h,03,'F20' ;____________________________________________________________________________ ;*** PROGRAMMED user keys *** ;THIS CODE IS INSTALLATION DEPENDANT !!!!! db 57h,03,'UF6' db 58h,03,'UF7' db 59h,03,'UF8' db 60h,03,'UF9' db 61h,04,'UF10' db 63h,04,'UF11' db 64h,04,'UF12' db 65h,04,'UF13' db 66h,04,'UF14' db 68h,04,'Help' ;<"UHelp" Reserved for Help !!! db 69h,02,'Do' ;<"UDo" = "Do" !!! db 71h,04,'UF17' db 72h,04,'UF18' db 73h,04,'UF19' db 74h,04,'UF20' ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; db 00h,07,'' ss3_name_tab db 41h,07,'Scan-up' db 42h,09,'Scan-down' db 43h,10,'Scan-right' db 44h,09,'Scan-left' db 'M',05,'Enter' db 'P',03,'PF1' db 'Q',03,'PF2' db 'R',03,'PF3' db 'S',03,'PF4' ;<< ESCAPE to terminal handler commands db 'm',08,'KP-minus' db 'l',08,'KP-comma' db 'n',08,'KP-point' db 'p',04,'KP-0' db 'q',04,'KP-1' db 'r',04,'KP-2' db 's',04,'KP-3' db 't',04,'KP-4' db 'u',04,'KP-5' db 'v',04,'KP-6' db 'w',04,'KP-7' db 'x',04,'KP-8' db 'y',04,'KP-9' db 00h,07,'' unknown_key_string db 0,7,'Unknown' font_select_string db shi,csi,'0' ;all attributes off font_attribs rb 12 curr_font db 0 special_font_string db csi,'0;1m' ;bold db sho,'$' special_chars db 66h ;00: any undefined db 60h ;01: visi space db 61h ;02: visi tab db 6Eh ;03: more character db 68h ;04: visible newline special_chars_lng equ (offset $) - (offset special_chars) ctrl_char_string db esc,'7' db csi,'0;1m' ;bold ctrl_char db '?' db esc,'8' db csi,'C$' help_buffer rb 16 temp equ help_buffer ;data ends code cseg byte public public init_entry init_entry: call prolog mov dx,offset init_cons ccpm c_writestr epilog: mov sp,bp if v30 popall else pop di ! pop si ! pop bp ! pop ax ;skip sp pop bx ! pop dx ! pop cx ! pop ax endif pop es ! pop ds ! ret prolog: pop prolog_return push ds ! push es if v30 pushall else push ax ! push cx ! push dx ! push bx push sp ! push bp ! push si ! push di endif mov bp,sp ! mov ds,own_ds jmp prolog_return prolog_return rw 1 own_ds dw seg key_buffer public uninit_exit uninit_exit: call prolog mov dx,offset uninit_cons ccpm c_writestr mov dx,10 ;wait 10 clock ticks .. ccpm p_delay ;.. for terminal recall jmps epilog 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. call prolog ! mov ax,key_buffer ;last key is in buffer ? mov call_ax,ax or ax,ax ! jnz epilog mov dl,0ffh ! ccpm c_rawio ;ask CCPM for a key present check_for_key_0: xor ah,ah ; cmp al,csi ! jne check_for_key_1 mov dl,0fdh ! ccpm c_rawio ;get first char. after CSI cmp al,'A' ! jb check_for_csi_1 ;check for cursor keys cmp al,'D' ! jbe check_for_csi_3 check_for_csi_1: cmp al,'1' ! jb check_for_key_err ;not a CSI key cmp al,'9' ! ja check_for_key_err and al,0fh ! mov temp,al mov dl,0fdh ! ccpm c_rawio ;get second char after CSI cmp al,'~' ! je check_for_csi_2 ;end of CSI key cmp al,'0' ! jb check_for_key_err cmp al,'9' ! ja check_for_key_err and ax,0fh if v30 shlb temp,4 ! add temp,al ;form decimal packed else mov cl,4 ! shl temp,cl ! add temp,al endif mov dl,0fdh ! ccpm c_rawio ;get third char. after CSI cmp al,'~' ! jne check_for_key_err ;must be '~' check_for_csi_2: mov al,temp check_for_csi_3: mov ah,csi jmps check_for_key_2 ;save CSI code check_for_key_1: ;check for SS3 key cmp al,ss3 ! jne check_for_key_2 mov dl,0fdh ! ccpm c_rawio ;get first char after SS3 push ds ! pop es mov di,offset ss3_scan_tab mov cx,length ss3_scan_tab repne scasb ;scan SS3 key table jne check_for_key_err ;key error cmp al,'S' ! je handler_seq ;special VT200 handler command sequence mov ah,ss3 ; check_for_key_2: mov key_buffer,ax ;save key mov call_ax,ax ; and return it or ax,ax ! jmp epilog check_for_key_err: call ring_the_bell xor ax,ax ! jmps check_for_key_2 handler_seq: ;test for special terminal handler command sequences by PF4 call get_ss3_seq ;get the next SS3 sequence cmp al,'p' ! jb handler_seq_PF4 ;not a decimal ASCII cmp al,'r' ! ja check_for_key_err ; ;get ASCII char in decimal representation (000-255) sub al,'p' ! mov cl,10 ! mul cl push ax ! call get_ss3_seq ! pop dx sub al,'p' ! jb check_for_key_err cmp al,9 ! ja check_for_key_err add ax,dx ! mov cl,10 ! mul cl push ax ! call get_ss3_seq ! pop dx sub al,'p' ! jb check_for_key_err cmp al,9 ! ja check_for_key_err add ax,dx ! cmp ax,255 ja check_for_key_err mov ah,'B' ! jmps check_for_key_2 ;signal bin key ; handler_seq_PF4: ;if double PF4 then return PF4 cmp al,'S' ! jne handler_seq_PF3 mov ah,ss3 ! jmp check_for_key_2 ; handler_seq_PF3: ;if "PF4 PF3" then alter the keypad mode (application <--> numeric) cmp al,'R' ! jne handler_seq_err ;*** yet !!!! --- error ---- xor keypad_mode_str+1,03h ;toggle mode mov dx,offset keypad_mode_str ccpm c_writestr xor ax,ax ! jmp check_for_key_2 ; handler_seq_err: jmp check_for_key_err get_ss3_seq: mov dl,0fdh ! ccpm c_rawio cmp al,ss3 ! jne handler_seq_err mov dl,0fdh ! ccpm c_rawio xor ah,ah ! ret public get_key_value get_key_value: ;exit with ax=key code. push ds ! mov ds,own_ds xor ax,ax ! xchg ax,key_buffer ;get key and clear buffer pop ds ! or ax,ax ! jz $+3 ! ret if v30 pushw offset get_key_value ;return from check_key_value_0 else mov ax,offset get_key_value ! push ax endif call prolog mov dl,0fdh ! ccpm c_rawio ;read char from console jmp check_for_key_0 ;check control codes public decode_key decode_key: ;enter with ax=key value. ;exit with si,cx -> the key's name in ASCII. call prolog mov di,offset help_buffer test ah,ah ! jz $+5 jmp decode_specials ;decode special keys ; cmp al,',' ! jne decode_key_LPar mov call_si,offset Comma_key mov call_cx,length Comma_key jmp epilog decode_key_LPar: cmp al,'(' ! jne decode_key_RPar mov call_si,offset LPar_key mov call_cx,length LPar_key jmp epilog decode_key_RPar: cmp al,')' ! jne decode_key_delete mov call_si,offset RPar_key mov call_cx,length RPar_key jmp epilog decode_key_delete: mov si,di ;remember beginning mov dl,al ! and dl,7fh ;form 7-bit code cmp dl,7fh ! jne decode_non_delete ;jump if no char ; push si ! mov si,offset delete_string mov cx,length delete_string test al,80h ! jnz $+4 dec cx ! inc si ;skip 8-bit-indicator push cx ! rep movsb ;move "Delete" string mov al,0 ! stosb ;append terminator pop call_cx ! pop call_si jmp epilog ; decode_non_delete: cmp dl,32 ! jb decode_ctrl_key mov call_si,si ;this is a normal displayable char mov call_cx,1 stosw ! jmp epilog ; decode_ctrl_key: push si ! mov si,offset ctrl_string mov cx,length ctrl_string test ah,80h ! jnz $+4 dec cx ! inc si ;skip 8-bit-indicator push cx ! rep movsb ;move "Ctrl"-char indicator pop cx ! mov al,dl add al,64 ! stosw ;put the control char inc cx ! mov call_cx,cx pop call_si ! jmp epilog ; decode_specials: cmp ah,csi ! jne decode_ss3 mov bx,offset csi_name_tab ;decode CSI controls jmps decode_specials_1 decode_ss3: cmp ah,ss3 ! jne decode_bin mov bx,offset ss3_name_tab decode_specials_1: cmp al,[bx] ! je decode_specials_3 cmp byte ptr [bx],0 je decode_specials_3 add bl,1[bx] ! adc bh,0 inc bx ! inc bx ! jmps decode_specials_1 decode_specials_2: mov bx,offset unknown_key_string decode_specials_3: mov cl,1[bx] ! lea si,2[bx] decode_specials_4: xor ch,ch mov call_cx,cx mov call_si,si jmp epilog decode_bin: cmp ah,'B' ! jne decode_specials_2 mov si,offset help_buffer mov [si],al ! mov cl,1 ! jmps decode_specials_4 public ring_the_bell ring_the_bell: push bx ! push cx ! push dx mov dl,7 ! ccpm c_rawio xor cx,cx ! loop $ mov dl,7 ! ccpm c_rawio pop dx ! pop cx ! pop bx ! ret public position_cursor position_cursor: ;enter with dh=col (0...131), dl=row (0..max_screen_line) ;exit with cursor set to that position. call prolog if v30 pushw offset epilog ;fall thru else mov ax,offset epilog ! push ax endif pos_cursor: std mov di,offset cur_pos_string+7 xor ax,ax ! mov ah,dh ! inc ah position_cursor_1: ;convert columne or ah,ah ! jz position_cursor_2 if v30 shrw ax,8 ! div cb10 else mov al,ah ! mov ah,0 ! div cb10 endif xchg al,ah ! or al,'0' ! stosb jmps position_cursor_1 position_cursor_2: mov al,';' ! stosb ;put parameter delimiter mov ah,dl ! inc ah position_cursor_3: ;convert line number (row) or ah,ah ! jz position_cursor_4 if v30 shrw ax,8 ! div cb10 else mov al,ah ! mov ah,0 ! div cb10 endif xchg al,ah ! or al,'0' ! stosb jmps position_cursor_3 position_cursor_4: mov byte ptr [di],csi ;insert control string introducer mov dx,di ! ccpm c_writestr ;write out cursor position command cld ! ret cb10 db 10 public clear_to_eol clear_to_eol: ;enter with dl=current row, dh=current column. call prolog call pos_cursor clear_to_eol_1: mov dx,offset clear_to_eol_string ccpm c_writestr jmp epilog public clear_count clear_count: ;enter with dl=current row, dh=current column, bl=column to clear to. call prolog call pos_cursor mov cx,call_bx ! xor ch,ch mov ax,call_dx ! xor ah,ah sub cx,ax ! jb count_clear_2 count_clear_1: push cx ! mov dl,' ' ccpm c_rawio pop cx ! loop count_clear_1 mov dx,call_dx ! call pos_cursor count_clear_2: jmp epilog public chroutput ;normal terminal output routine. ;enter with al=character to print at the current cursor position ; ah=font to print in ;exit: cursor positioned after the printed char chroutput: call prolog jmps xychrout_1 public xychrout xychrout: ;enter with dh=col, dl=row, al=character to print, ah=font to print it in. ;exit: cursor positioned after the printed char call prolog call pos_cursor xychrout_1: mov ax,call_ax ;char to print call set_font ;set font from AH --- preserves AX cmp ah,0FFh ! je xychrout_specials mov dx,ax ! and al,7fh cmp al,20h ! jb xychrout_ctrl ;display control characters ccpm c_write ! jmp epilog xychrout_ctrl: add al,40h ! test dl,80h jz xychrout_ctrl1 add al,20h ! cmp al,07fh jb xychrout_ctrl1 mov al,3ch xychrout_ctrl1: mov ctrl_char,al mov dx,offset ctrl_char_string ccpm c_writestr ! jmp epilog xychrout_specials: mov bx,offset special_chars cmp al,special_chars_lng jbe $+4 ! mov al,0 xlat special_chars mov dl,al ! ccpm c_write jmp epilog set_font: ;set character fonts cmp ah,curr_font ! jne $+3 ! ret ;font already set push ax ! mov dl,ah ;get selected font to dl cmp dl,0FFh ! je set_font_special ;set special font mov di,offset font_attribs push ds ! pop es rcr dl,1 ! jnc $+6 mov ax,'1;' ! stosw ;set bold rcr dl,1 ! jnc $+6 mov ax,'4;' ! stosw ;set underline rcr dl,1 ! jnc $+6 mov ax,'5;' ! stosw ;set blink rcr dl,1 ! jnc $+6 mov ax,'7;' ! stosw ;set reverse mov ax,'$m' ! stosw ;terminate string mov dx,offset font_select_string set_font_exit: ccpm c_writestr ;select font pop ax ! mov curr_font,ah ret set_font_special: mov dx,offset special_font_string jmps set_font_exit public hardware_announce ;Enter with dl=row, dh=col for string to announce ;ds:si=string to announce, cx=string length ;Preserves the cursor position ! hardware_announce: call prolog mov word ptr temp,si ;save string offset mov ax,call_ds mov word ptr temp+2,ax ;save string segment mov word ptr temp+4,cx ;save string length mov ah,curr_font ! push ax ;save current font mov dx,offset sv_cursor_string ccpm c_writestr ;save the cursor position mov dx,call_dx call pos_cursor ;set new cursor position cmp word ptr temp+4,0 jz hardware_announce_1 mov ah,9 ! call set_font ;set reverse video + bold mov dx,offset temp ccpm c_writeblk ;output string mov cx,80 ! sub cx,call_cx jbe hardware_announce_1 push cx ! mov dl,' ' ccpm c_write pop cx ! loop $-8 hardware_announce_1: mov dx,offset clear_to_eol_string ccpm c_writestr ;clear to end of line mov dx,offset rs_cursor_string ccpm c_writestr ;restore cursor position pop ax ! call set_font ;restore font jmp epilog 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. call prolog mov dx,offset roll_dn_string jmps hw_roll_up 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. call prolog mov dx,offset roll_up_string hw_roll_up: ccpm c_writestr clc ! jmp epilog public hardware_ins_line hardware_ins_line: ;enter with al=line number where to insert the new line call prolog if v30 pushw offset ins_line_string else mov bx,offset ins_line_string ! push bx endif jmps hw_del_ins_line public hardware_del_line hardware_del_line: ;enter with al=line number to delete call prolog if v30 pushw offset del_line_string else mov bx,offset del_line_string ! push bx endif hw_del_ins_line: xor dx,dx ! mov dl,al call pos_cursor pop dx ! ccpm c_writestr jmp epilog public block_cursor block_cursor: stc ! ret public underscore_cursor underscore_cursor: stc ! ret public set_screen_color set_screen_color: ;enter with al=VT200 graphic rendition ; bit 0 All attributes off ; 1 Display bold ; 4 Display underlined ; 5 Display blinking ; 7 Display reverse call prolog ! mov es,own_ds mov di,offset help_buffer xchg al,dl ! mov al,csi ! stosb ;build control string mov ah,';' ! mov cl,0 set_screen_color_1: rcr dl,1 ! jnc set_screen_color_2 mov al,cl ! and al,'0' ! stosw inc cl ! cmp al,8 ! jb set_screen_color_1 set_screen_color_2: mov ax,'$m' ! dec di ! stosw mov dx,offset help_buffer ;write control string ccpm c_writestr jmp epilog ;code ends end