; program: ccp/m-86 v2.0 olympia "PEOPLE" function keys ; author: douglas w. goodall, oem systems, digital research ; dated: 7/7/83 ; the function of this program is to open a file supplied in the command ; tail and use the text data within to program the function keys on a ; specific console under concurrent cp/m-86 v2.0 on the olympia "PEOPLE" ; machine. P_TERMCPM EQU 0 ; (0) TERMINATE PROGRAM TO CPM C_WRITE EQU 2 ; (2) CONOUT C_WRITESTR EQU 09H ; (9) WRITE STRING F_OPEN EQU 0FH ; (15) FILE OPEN F_READ EQU 014H ; (20) READ SEQUENTIAL F_DMASET EQU 01AH ; (26) SET DMA OFFSET F_ERRMODE EQU 02DH ; (45) SET BDOS ERROR MODE RETURN_ERROR_MODE EQU 0FFH ; (255) RETURN ERROR CODE ONLY BDOS EQU 0E0H SS_PTR EQU 3AH ; scr_struc_addrs offset cons_own_off equ 3ch ; console owner offset FUN_TAB_PTR EQU 14H C_READSTR EQU 10 PFK_ENTRY_LENGTH EQU 20 MAX_FUNCTION_KEYS EQU 17 eject cseg entry: call do_header MOV AL,FCB_F1 ; USE 1ST FILENAME BYTE TO DECIDE CMP AL,' ' JNE FILE_VER JMP INTERACTIVE FILE_VER: call set_errmode call set_ro call open_it CALL READ_IT mov ax,offset init_state ! mov state,ax process: mov si,state jmp si ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; init_state: mov cl,C_WRITE ! mov dl,1bh ! int bdos ; in this state we are waiting for a colon call getbyte ! cmp al,01ah ! je INIT_STATE_DONE ; <== cmp al,':' ! jne err_not_colon mov cl,C_WRITE ! mov dl,al ! int bdos mov ax,offset get_keyid ! mov state,ax ! jmp process INIT_STATE_DONE: CALL EXIT ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; get_keyid: ; in this state we are waiting for a keyid call getbyte ; <== ! cmp al,0ffh ! je err_eof_keyid ; <== cmp al,'A' ! jb err_get_keyid_bad ; <== cmp al,'Q'+1 ! jnb err_get_keyid_bad mov cl,C_WRITE ! mov dl,al ! int bdos mov ax,offset normal_char ! mov state,ax ! jmp process ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; normal_char: ; in this state we are waiting for a normal char to send ; to the function string call getbyte ; <== ! cmp al,0ffh ! je err_eof_normal cmp al,'\' ! jne not_hex mov ax,offset get_hex1 ! mov state,ax ! jmp process not_hex: mov cl,C_WRITE ! mov dl,al ! int bdos ! jmp process ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; get_hex1: ; in this state we are waiting for the 1st hex nybble ; to arrive call getbyte ; <== ! cmp al,0ffh ! je err_eof_1st call hex2bin ! add al,al ! add al,al ! add al,al ! add al,al mov hex1,al mov ax,offset get_hex2 ! mov state,ax ! jmp process ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; get_hex2: ; in this state we are waiting for the 2nd hex nybble ; to arrive call getbyte ; <== ! cmp al,0ffh ! je err_eof_2nd call hex2bin ! add al,hex1 push ax mov cl,C_WRITE ! mov dl,al ! int bdos pop ax cmp al,0 ! jne get2_not_zero ; if here we have just sent the zero byte mov ax,offset init_state ! mov state,ax ! jmp process get2_not_zero: mov ax,offset normal_char ! mov state,ax ! jmp process ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; hex2bin:cmp al,'0' ! jne not_0 ! mov al,0 ! ret not_0: cmp al,'1' ! jne not_1 ! mov al,1 ! ret not_1: cmp al,'2' ! jne not_2 ! mov al,2 ! ret not_2: cmp al,'3' ! jne not_3 ! mov al,3 ! ret not_3: cmp al,'4' ! jne not_4 ! mov al,4 ! ret not_4: cmp al,'5' ! jne not_5 ! mov al,5 ! ret not_5: cmp al,'6' ! jne not_6 ! mov al,6 ! ret not_6: cmp al,'7' ! jne not_7 ! mov al,7 ! ret not_7: cmp al,'8' ! jne not_8 ! mov al,8 ! ret not_8: cmp al,'9' ! jne not_9 ! mov al,9 ! ret not_9: cmp al,'A' ! jne not_a ! mov al,10 ! ret not_a: cmp al,'B' ! jne not_b ! mov al,11 ! ret not_b: cmp al,'C' ! jne not_c ! mov al,12 ! ret not_c: cmp al,'D' ! jne not_d ! mov al,13 ! ret not_d: cmp al,'E' ! jne not_e ! mov al,14 ! ret not_e: cmp al,'F' ! jne not_f ! mov al,15 ! ret ; if we are here, we failed to properly decode the ; hex nybble, this must be an error not_f: mov dx,offset hexmsg ! jmp error ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; do_header: mov cl,C_WRITESTR ! mov dx,offset header ! int bdos ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; set_errmode: ; set bdos error mode to return errors instead of bombing out ; see programmer's reference guide page 151 mov cl,F_ERRMODE mov dl,RETURN_ERROR_MODE int bdos ret set_ro: ; set the read only mode on the filename in the default fcb ; see programmer's reference guide page 160 mov al,fcb_f6 or al,80h mov fcb_f6,al ret exit: mov cl,P_TERMCPM ! int bdos EJECT ; GET BYTE FROM INOUT STREAM GETBYTE: CMP GETPTR,128 JNE GETBYTE_OK CALL READ_IT JMP GETBYTE GETBYTE_OK: MOV SI,OFFSET DEFAULT_BUF ADD SI,GETPTR MOV AL,BYTE PTR[SI] PUSH AX MOV AX,GETPTR ! INC AX ! MOV GETPTR,AX POP AX cmp al,0dh ! je getbyte cmp al,0ah ! je getbyte ret eject read_it: ; set dma offset to use the default buffer ; see programmer's reference guide page 150 mov cl, F_DMASET ! mov dx,offset default_buf ! int bdos ; read next sequential record using system call ; see programmer's reference guide page 168 mov cl,F_READ ! mov dx,offset default_fcb ! int bdos cmp al,0 ! jne read_error mov getptr,0 ret read_error: ; see programmer's reference guide page 168 cmp al,01h ! jne read_not_1 ! ret ; 01 means end of file read_not_1: cmp al,08h ! jne read_not_8 ! mov dx,offset read_8_msg ! jmp error read_not_8: cmp al,09h ! jne read_not_9 ! mov dx,offset read_9_msg ! jmp error read_not_9: cmp al,0ah ! jne read_not_a ! mov dx,offset read_a_msg ! jmp error read_not_a: cmp al,0bh ! jne read_not_b ! mov dx,offset read_b_msg ! jmp error read_not_b: cmp al,0ffh ! je read_ff ! mov dx,offset read_unk_msg ! jmp error read_ff: cmp ah,01h ! jne read_ff_not_01 ! mov dx,offset read_dio_msg jmp error read_ff_not_01: cmp ah,04h ! jne read_ff_not_04 ! mov dx,offset read_invdrv_msg jmp error read_ff_not_04: ; see programmer's reference guide page 169 ; hum, not a 01h and not 04h, must be unknown mov dx,offset read_unk_msg ! jmp error ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; eject open_it: ; try to open the default file from the command tail ; see programmer's reference guide page 160 mov cl,F_OPEN ! mov dx,offset default_fcb ! int bdos cmp al,0ffh ! je open_error ret open_error: cmp ah,00h ! jne not_00h ! mov dx,offset msg_open_00h ! jmp error not_00h: cmp ah,01h ! jne not_01h ! mov dx,offset msg_open_01h ! jmp error not_01h: cmp ah,04h ! jne not_04h ! mov dx,offset msg_open_04h ! jmp error not_04h: cmp ah,05h ! jne not_05h ! mov dx,offset msg_open_05h ! jmp error not_05h: cmp ah,07h ! jne not_07h ! mov dx,offset msg_open_07h ! jmp error not_07h: cmp ah,09h ! jne not_09h ! mov dx,offset msg_open_09h ! jmp error not_09h: cmp ah,0ah ! jne not_0ah ! mov dx,offset msg_open_0ah ! jmp error not_0ah: cmp ah,0bh ! jne not_0bh ! mov dx,offset msg_open_0bh ! jmp error not_0bh: mov dx,offset msg_open_unk ! jmp error EJECT error: mov cl,C_WRITESTR ! int bdos mov cl,C_WRITESTR ! mov dx,offset term_msg ! int bdos mov cl,P_TERMCPM ! int bdos EJECT ; THE FOLLOWING CODE IS THE NNTERACTIVE SECTION ;---------------------------------- ; MAIN PROGRAM ;---------------------------------- INTERACTIVE: CALL GET_FUNTAB_AS_ESBX MOV FUNCTION_TABLE_BASE,BX MOV SYSDAT_SEG,ES LOOP: CALL NEW_SCREEN CALL FOR_ALL_KEYS CALL POS_4_INPUT CALL GET_NEW_STUFF JMP LOOP ;---------------------------------- POS_4_INPUT: MOV CL,C_WRITE ! MOV DL,1BH ! INT BDOS ; ESC MOV CL,C_WRITE ! MOV DL,'Y' ! INT BDOS ; Y MOV CL,C_WRITE ! MOV DL,22+20H ! INT BDOS ; l MOV CL,C_WRITE ! MOV DL,15+20H ! INT BDOS ; c RET ;----------------------------------- GET_NEW_STUFF: ; CALL SYSTEM AND ASK FOR BUFFERED INPUT LINE MOV CL,C_READSTR ! MOV DX,OFFSET INPUT_BUFFER ! INT BDOS ; SET $ AT END OF INPUT LINE SO AS TO TERMINATE THE ; OUTPUT OF THIS STRING USING C_WRITESTR ; SET SI ==> 1ST STRING BYTE MOV SI,OFFSET INPUT_BUFFER ! ADD SI,2 ; DEVELOP 16 BIT LENGTH IN AX XOR AH,AH MOV AL,INPUT_BUFFER+1 ; CALCULATE OFFSET OF BYTE JUST PAST END OF INPUT ADD SI,AX ; ACTUALLY PLACE THE "$" WHERE IT WILL DO THE MOST GOOD MOV BYTE PTR [SI],0 ! INC SI ! MOV BYTE PTR [SI],'$' ; EMIT THE ESC MOV CL,C_WRITE ! MOV DL,1BH ! INT BDOS ; SEND THE PROGRAMMING STRING MOV DX,OFFSET INPUT_BUFFER+2 ! CALL SPECIAL_C_WRITESTR ; RETURN TO THE CALLER, WORK HAS BEEN DONE, REBUILD THE DISPLAY RET ;----------------------------------- FOR_ALL_KEYS: MOV AX,0 ALL_KEYS_LOOP: MOV COUNT,AX ; IN THE FOLLOWING CODE THE CONSTANT 20 IS USED TO POSITION THE LEFT MARGIN ; OF THE FUNCTION KEY DATA. IF BY SOME CHANCE ONE WERE TO PROGRAM THE ; ENTIRE FUNCTION STRING WITH NON-PRINTING HEX CONSTANTS, WHEN THE ; PROGRAM WENT TO DISPLAY THE STRING, ALL BYTES WOULD APPEAR IN HEX ; AND 20 CHARACTERS EXPRESSED AS \XX IS 60 BYTES, THEREFORE THE 20 ; THIS DOES PLACE AN UNFORTUNATE LIMIT ON THE FUNCTION KEY NAMES ; POSITION THE CURSOR FOR THE PROPER STARTING BYTE OF THE FUNCTION STRING MOV CL,C_WRITE ! MOV DL,1BH ! INT BDOS MOV CL,C_WRITE ! MOV DL,'Y' ! INT BDOS MOV AX,COUNT ! MOV DL,3 ! ADD DL,AL ! ADD DL,20H MOV CL,C_WRITE ! INT BDOS MOV CL,C_WRITE ! MOV DL,15 ! ADD DL,20H ! INT BDOS ; DISPLAY THE FUNCTION KEY DATA MOV AX,COUNT MOV CX,PFK_ENTRY_LENGTH + 3 MUL CX ADD AX,FUNCTION_TABLE_BASE MOV BX,AX PUSH ES MOV AX,SYSDAT_SEG ! MOV ES,AX CALL DISPLAY_FUNCTION POP ES MOV AX,COUNT INC AX CMP AX,MAX_FUNCTION_KEYS JNE ALL_KEYS_LOOP RET ;----------------------------------------------------------- USE_OLYMPIA: MOV CL,C_WRITE ! MOV DL,1BH ! INT BDOS MOV CL,C_WRITE ! MOV DL,'O' ! INT BDOS RET ;----------------------------------------------------------- DISPLAY_FUNCTION: PUSH ES ! PUSH BX MOV CL,C_WRITE ! MOV DL,':' ! INT BDOS ; ENTER REVERSE MOV CL,C_WRITE ! MOV DL,1BH ! INT BDOS MOV CL,C_WRITE ! MOV DL,'p' ! INT BDOS ; Z19 POP BX ! POP ES MOV DL,ES:[BX] SUB DL,0E8H ADD DL,'A' MOV CL,C_WRITE PUSH ES ! PUSH BX INT BDOS ; EXIT REVERSE MOV CL,C_WRITE ! MOV DL,1BH ! INT BDOS MOV CL,C_WRITE ! MOV DL,'q' ! INT BDOS POP BX ! POP ES ADD BX,2 ; INCREMENT TO 1ST FUNCTION BYTE DF_LOOP: MOV DL,ES:[BX] ; NOW WE WANT TO TRANSLATE FROM AN ASCII CODE TO A FUNCTION ; NUMBER PUSH BX MOV BX,OFFSET DISPLAY_FUNCTION_TABLE ! MOV AL,DL ! XLAT AL POP BX CMP AL,0 ! JE DISPLAY_FUNCTION_ZERO CMP AL,1 ! JE DISPLAY_FUNCTION_ONE CMP AL,2 ! JE DISPLAY_TERMINATE ; IF WE ARE HERE, SOMEONE MESSED AROUND WITH THE ; DISPLAY_FUNCTION_TABLE WITHOUT IMPLEMENTING THE ; APPROPRIATE "CMP AL,n ! JE DISPLAY_FUNCTION_n" ; AS ABOVE... MOV CL,P_TERMCPM ! INT BDOS DISPLAY_FUNCTION_ZERO: ; THIS PROCEDURE DISPLAYS THE CHARACTER ; IN DL ON THE CONSOLE AS A NORML PRINTABLE ; CHARACTER. PUSH ES ! PUSH BX MOV CL,C_WRITE ! INT BDOS POP BX ! POP ES JMP PROCEDURE_RETURN DISPLAY_FUNCTION_ONE: MOV AL,DL ! XOR AH,AH PUSH AX ! PUSH BX ! PUSH ES MOV CL,C_WRITE ! MOV DL,'\' ! INT BDOS POP ES ! POP BX ! POP AX CALL PRINT_BYTE JMP PROCEDURE_RETURN DISPLAY_TERMINATE: MOV CL,C_WRITESTR ! MOV DX,OFFSET ZERO_MSG ! INT BDOS RET PROCEDURE_RETURN: INC BX JMP DF_LOOP ;----------------------------------------------------------- PRINT_BYTE: PUSH AX AND AL,0F0H SAR AL,1 ! SAR AL,1 ! SAR AL,1 ! SAR AL,1 CALL PRINT_NYBBLE POP AX AND AL,0FH CALL PRINT_NYBBLE RET PRINT_NYBBLE: PUSH ES ! PUSH AX ! PUSH BX ! PUSH CX ! PUSH DX MOV BX,OFFSET HEXREF XOR AH,AH ADD BX,AX MOV DL,BYTE PTR [BX] MOV CL,C_WRITE ! INT BDOS POP DX ! POP CX ! POP BX ! POP AX ! POP ES RET ;----------------------------------------------------------- get_funtab_as_esbx: mov cl,09ah ; (154) s_sysdat int bdos xor ah,ah ; ah = 0 mov bx,0c00h mov al,es:cons_own_off[bx] ; get console number add ax,ax mov bx,es:ss_ptr[bx] add bx,ax MOV BX,ES:[BX] ; BX ==> SSn_PTR MOV BX,ES:FUN_TAB_PTR[BX] ; BX ==> FUN_TAB_PTR RET ;----------------------------------------------------------- NEW_SCREEN: MOV CL,C_WRITESTR MOV DX,OFFSET NEW_SCREEN_MSG INT BDOS RET ;----------------------------------------------------------- SPECIAL_C_WRITESTR: MOV SI,DX SP_P_LOOP: MOV DL,BYTE PTR [SI] ! INC SI ! CMP DL,'\' ! JNE SP_NORMAL_BYTE MOV AL,BYTE PTR [SI] ! CALL HEX2BIN ADD AL,AL ! ADD AL,AL ! ADD AL,AL ! ADD AL,AL ! MOV HEX1,AL INC SI ! MOV AL,BYTE PTR [SI] ! CALL HEX2BIN ! ADD AL,HEX1 MOV DL,AL ! INC SI SP_NORMAL_BYTE: PUSH DX ! MOV CL,C_WRITE ! INT BDOS ! POP DX CMP DL,0 ! JE SP_DONE JMP SP_P_LOOP SP_DONE: RET ;----------------------------------------------------------- eject dseg org 5ch default_fcb: fcb_dr rb 1 ; drive code 0=default 1=a: 2=b:... fcb_f1 rb 1 ; filename bytes fcb_f2 rb 1 ; high order bits may contain fcb_f3 rb 1 ; significance fcb_f4 rb 1 fcb_f5 rb 1 fcb_f6 rb 1 fcb_f7 rb 1 fcb_f8 rb 1 fcb_t1 rb 1 ; filetype byte fcb_t2 rb 1 ; high order bits may contain fcb_t3 rb 1 ; significance fcb_ex rb 1 ; current extent number fcb_cs rb 1 ; contains the fcb checksum value if open fcb_rs rb 1 ; reserved for internal use fcb_rc rb 1 ; record count for current extent fcb_d0_d15 rb 16 ; sys & alt_fn for rename fcb_cr rb 1 ; current record fcb_r0 rb 1 ; random record least significant byte fcb_r1 rb 1 ; random record middle byte fcb_r2 rb 1 ; random record most significant byte org 80h default_buf: rb 80h org 100h header: db 0dh,0ah db '--------------------------------------------------',0dh,0ah db 'Function Key Programmer 7/7/83 version 1.0',0dh,0ah db 'Serial No. xxx-0000-123456 All Rights Reserved',0dh,0ah db 'Copyright (C) 1983 Digital Research, Inc.',0dh,0ah db '--------------------------------------------------',0dh,0ah db '$' msg_open_00h: db '(Function.open): Function data file not found$' msg_open_01h: db '(Function.open): Disk I/O Error : permanent error$' msg_open_04h: db '(Function.open): Invalid Drive : drive select error$' msg_open_05h: db '(Function.open): File is open by another process or by the',0dh,0ah db ' current process in an incompatible mode$' msg_open_07h: db '(Function.open): Password Error$' msg_open_09h: db '(Function.open): Illegal ? in FCB$' msg_open_0ah: db '(Function.open): Open File Limit Exceeded$' msg_open_0bh: db '(Function.open): No Room in System Lock List$' msg_open_unk: db '(function.open): Unknown open error occured$' read_8_msg: db '(Function.read): Record Locked by another process$' read_9_msg: db '(Function.read): Invalid FCB$' read_a_msg: db '(Function.read): FCB Checksum error$' read_b_msg: db '(Function.read): Unlocked file verification error$' read_dio_msg: db '(Function.read): Disk I/O Error : permanent error$' read_invdrv_msg: db '(Function.read): Invalid Drive : drive select error$' read_unk_msg: db '(Function.read): Unknow error$' term_msg: db 0,0Dh,0ah,'(Function): ' db 'An error has occured which prevented the',0dh,0ah db ' function key programmer from operating$' hexmsg db 0,0DH,0AH,'(Function.hex2bin) Error parsing hex constant $' getptr rw 1 state rw 1 hex1 rb 1 ZERO_MSG DB '\00','$' CR_MSG DB '\0D','$' FUNCTION_TABLE_BASE DW 0 SYSDAT_SEG DW 0 COUNT DW 0 EJECT NEW_SCREEN_MSG: DB 1BH,'Z' ; SET Z19 MODE DB 1BH,'E' ; ERASE SCREEN DB 'Olympia "PEOPLE" FUNCTION KEY PROGRAMMER',0DH,0AH DB 'Enter control-c to exit function key programmer',0DH,0AH DB 0DH,0AH DB 'F1',0DH,0AH DB 'F2',0DH,0AH DB 'F3',0DH,0AH DB 'F4',0DH,0AH DB 'F5',0DH,0AH DB 'F6',0DH,0AH DB 'F7',0DH,0AH DB 'F8',0DH,0AH DB 'F9',0DH,0AH DB 'F10',0DH,0AH DB 'F11',0DH,0AH DB 'F12',0DH,0AH DB 'Left Arrow',0DH,0AH DB 'Right Arrow',0DH,0AH DB 'Up Left Arrow',0DH,0AH DB 'Up Arrow',0DH,0AH DB 'Down Arrow',0DH,0AH DB 0DH,0AH,0DH,0AH DB 'New definition',0DH,0AH DB '$' EJECT ; THE DISPLAY FUNCTION TABLE IS A PROCEDURE MAPPING TABLE ; POINTING TO PROCEDURES TO BE USED IN DISPLAYING A ; FUNCTION KEY CHARACTER ; 0 ==> DISPLAY AS NORMAL ASCII CHARACTER ; 1 ==> DISPLAY AS \HH DISPLAY_FUNCTION_TABLE: ; 0 1 2 3 4 5 6 7 8 9 A B C D E F DB 2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 ;0-F DB 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 ;10-1F NON-PRINTABLE DB 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 ;20-2F DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;30-3F DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;40-4F NORMAL DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;50-5F PRINTABLE DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;60-6F DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1 ;70-7F DB 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 ;80-8F DB 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 ;90-9F NON-PRINTABLE DB 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 ;A0-AF DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;B0-BF DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;C0-CF DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;D0-DF HIGH ORDER BIT DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;E0-EF PRINTABLE DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1 ;F0-FF HEXREF DB '0123456789ABCDEF' INPUT_BUFFER DB 255,0 RB 255 DB 0 END