Title Function Key Translation for the MD11 (16_Apr_84) ; ; Copyright 1984 ; Morrow Designs, Inc. ; San Leandro, Ca. ; John Zalabak ; .z80 .sall ;Suppress listings of the expanded macro definitions aseg org 0100h ; This program translates a source file residing on the disk ; into a table residing in the curently running system. The table in ; the system is used to intercept Function Keys, input from the console, ; into arbitrary length strings. These strings may contain any code ; that can be generated from the console. For example, the standard ; function key sequences (defined in the bios assmbly source code) ; include the output string HELP in response to the help key, a control_H ; iî responså tï thå control_UÐ arro÷ keù a null (nothing output) for ; á Shifted_DOWÎ arrow. page 64 ; Indeø tï Routineó (1_Mar_84) ;----------------------------- ; » Routines: ; Maiî_Linå_Keù Maiî linå oæ thå functioî keù program ; ; Save_Param Save the Input Parameters ; Opeî_á_Filå Openó thå inpuô keù file ; ; Parså_á_Linå Parseó thå nexô linå froí thå keù inpuô file ; Geô_Chaiî_Filå Chainó tï thå filå specifieä oò tï warí boot ; Code_to_Key Read & Translate Key Code; enter into Key Table ; Def_to_Temp Move a Function Key Definition into Temp Buffer ; Temp_to_Key Move the Temp Buffer definiton into Key Table ; ; Non_to_Dict_Buf Moves Non_Printing Key Name into Dict_Buffer ; Key_to_Dict_Buf Moves Function key's name into Dict_Buffer ; Lookup_Key_Name Looks for Dict_Buffer name in key dictionary ; Update_Key_Table Enter a byte into the Key Table ; ; Get_Next_Line Reads input key file until end of line/file ; Get_Non_White Reads input key file until Non Whitespace encountered ; Force_Upper_Case Force Character to Upper Case & Mask Parity ; Put_Back_Char Puts one character back into the key input file ; Get_Next_Char Gets the next character from the key input file ; ; Inject_Keys Inject Function Keys ; Get_Pointers Get Pointers into the Free Space ; Find_a_Code Find a Function Key Code ; Geô_thå_Pooì Geô thå Free Space Pooì ; Put_the_Pool Restore the Free Space Pool ; Get_Version Check CP/M version ; Call_Cold_Boot Call the Bios Cold Boot Entry Point ; Move_a_Block Move a block of memory ; ; Report_Errors Reports errors on the console ; Print_Line_Number Print the Line number ; ; Load_and_Go Load the chain file and execute ; ; Data Areas: ; Error Code Tables and Message Strings ; Key Dictionary Macro Definitions ; Key Dictionary ; General Data Area page ;---------------------------------------------------------------------- ; Equates (21_Feb_84) ;-------------------- ; ;Bios/Bdos Equates Bios_Entry equ 0 ;Bios Entry Point Bdos_Entry equ 5 ;Bdos Entry Vector Location Bdos_ConOut equ 2 ; Console Output Function Bdos_PString equ 9 ; Print a Sting on the Console Bdos_ConBuf_in equ 10 ; Read Console input buffer Bdos_Ret_Ver equ 12 ; Return CP/M version Bdos_Open_File equ 15 ; Open a File Bdos_Close_File equ 16 ; Close a File Bdos_Read_Seq equ 20 ; Read Sequential Bdos_Write_Seq equ 21 ; Write Sequential Bdos_Set_DMA equ 26 ; Set the DMA Address ;Non Printing Ascii Equates EOF equ 1Ah ;End of File Character Escape equ 1Bh ;Escape Cr equ 0Dh ;Carriage Return Lf equ 0Ah ;Line Feed Tab equ 09h ;Tab Space equ 20h ;Space ;Error Codes Missing_Key_Def equ 0FFh ;No Key Definition Bad_Key_Name equ 0FEh ;Missing Function Key Name Invalid_Key equ 0FDh ;Invalid Function Key Assignment Def_too_Long equ 0FCh ;Key Definition String is too long Temp_Overflow equ 0FBh ;Temp buffer overflowed Key_Overflow equ 0FAh ;Local Function Key Table Overflowed Table_too_Big equ 0F9h ;Function Key Table is too large No_Key_File equ 0F8h ;No Key file name Bad_Key_File equ 0F7h ;Can't open the key file Disk_Read_Error equ 0F6h ;Error occured in a disk read operation Unexpected_End equ 0F5h ;Unexpected End (Eol or Eof) Bad_Definition equ 0F4h ;Illegal Character Dict_Overflow equ 0F3h ;Dictionary Buffer has overflowed ;File Control Block Definitions Fcb1 equ 5Ch ;Start of the 1st FCB generated by the CCP Fcb2 equ 6Ch ; " " " 2nd FCB " " " " Fcb1_Extent equ Fcb1+9 ;Offset to the start of the FCB's Extent Fcb1_cr_Field equ Fcb1+32 ;Offset to the current record field ;Extended Bios Function Call Codes F_Write_Sys equ 1 ;Write to system memory F_Get_Pool equ 8 ;Get the free space pool ;Free Space Id Codes Id_FS equ 0FFh ;Id of the Free Space Pointer Id_IMS equ 0FDh ;Id of the IMS buffer Id_FC equ 0FCh ;Id of the Function Key Table ;Length defintions Record_Length equ 80h ;Length of one record Max_Temp_Length equ 100h ;Maximum Length of the Temp Buffer Max_Dict_Length equ 10h ; " " " the dictionary buffer Max_Rec_Length equ 80h ; " " " a Record Max_Key_Length equ 400h ; " " " the Local Key Table Max_Pool_Length equ 800h ; " " " the Free Space Pool Buffer Max_Stack_Space equ 20h ; " " " the main stack ;Offsets for the load and go module Load_Length equ End_Lgo - Start_Lgo LS_offset equ End_Lgo - Load_Stack SF_offset equ End_Lgo - Save_FCB2 OIL_offset equ End_Lgo - Old_Input_Line CF_offset equ End_Lgo - Command_Fcb ;Other Definitions Default_Dma equ 80h ;Start of the default dma buffer Status_EOF equ 1 ;End of file status Null equ 0FFh ;Null Key Definition Pool_off equ 43h ;offset to the pool pointer in CP/M 2 page ;====================================================================== ; Main Line Key (28_Feb_84) ;========================== ; Main_Line_Key: ld sp,Main_Stack ;Initialize the stack pointer call Save_Param ;Save the input parameters or a ;If (there was no key file input) jr nz,KeyErr ; Goto Error Return call Open_a_File ;If (file can't be opened) or a jr nz,KeyErr ; Goto Error Return KDLp1: call Parse_a_Line ;Repeat Parse a line of the input file or a jr z,KDLp1 ;Until (Parse_Result ne Continue) cp EOF ;If (Parse_result ne End of File) jr nz,KeyErr ; Goto Error Return KDSk1: ld hl,(Key_Length) inc hl ld (Key_Length),hl ;Include Number of keys byte in length call Inject_Keys ;Inject Function Key Table or a ;If (keys were successfully installed) jp z,Load_and_Go ; Goto Chain file KeyErr: call Report_Errors ;Report the error jp Bios_Entry ;Warm Boot page ;====================================================================== ; Save the Input Parameters (3_Mar_84) ;===================================== ; 1) This routine saves the command tail, located in the default dma ; buffer at location 80h, minus the first word on the line. The first ; word on the line is the key file name which is NOT passed on to the ; chain file. The first 13 bytes of the second FCB are also saved. ; 2) Register Usage: ; BC -> Current Line Length ; DE -> destination pointer ; HL -> Pointer into default dma and source pointer ; Save_Param: ld hl,Default_Dma ;HL:= Pointer into default dma buffer ld a,(hl) oò a ;if (Command line is zero length) jr nz,SPsk1 ld a,No_Key_File ; Set Returned Error Status ret ; Return ;Remove Leading White Space SPsk1: ld b,a ;B:= Line Length SPlp1: inc hl ;Repeat Move Pointer to next char ld a,(hl) cp Space ; If ( (Char ne Space) and jr z,SPsk11 cp Tab ; (Char ne Tab) ) jr nz,SPlp2 ; Break SPsk11: djnz SPlp1 ;Until (line length - 1 eq zero) jr SPsk3 ;If (line length eq 0) goto move line ;Remove the first word from the line SPlp2: dec b ;While (Line length is not zero) jr z,SPsk3 inc hl ld a,(hl) cp Space ; If ( (Char eq Space) or jr z,SPsk3 cp Tab ; (Char eq Tab) ) jr nz,SPlp2 ; Break ;Save the remainder of the input line SPsk3: ld a,b ld (Old_Input_Line),a ;save the line length or a ;If (Line length ne 0) jr z,SPsk4 ld de,Old_Input_Line+1 ; DE:= Pointer to 1st char of save line ld c,a ld b,0 ; BC:= Byte Count ldir ; Save the old input line ;Save the first 13 bytes of the second FCB SPsk4: ld hl,Fcb2 ;HL:= Source (2nd Fcb) ld de,Save_Fcb2 ;DE:= Destination (Save location) ld bc,13 ;BC:= Count (move 13 bytes) ldir ;Save the second FCB ld a,0 ;Set Returned status to OK ret ;Return page ;---------------------------------------------------------------------- ; Open a File (28_Feb_84) ;------------------------ ; Open_a_File: ld a,(Fcb1_Extent) ;If (the extent is undefined) cp Space jr nz,OFSk1 ld a,'K' ld (Fcb1_Extent),a ld a,'E' ld (Fcb1_Extent+1),a ld a,'Y' ld (Fcb1_Extent+2),a ; Set Extent to 'KEY' OFSk1: ld a,0 ld (Fcb1_cr_Field),a ;clear the current record field ld c,Bdos_Set_DMA ;C:= Set DMA Address Funtion Number ld de,Record_Buffer ;DE:= Pointer to start of Record Buffer call Bdos_Entry ld c,Bdos_Open_File ;C:= Open a File Function Number ld de,Fcb1 ;DE:= Pointer to Default FCB call Bdos_Entry ;Open the file cp 0FFh ;If (Open was UnSuccessful) jr nz,OFSk2 ld a,Bad_Key_File ; Set Returned Error Status ret ; Return OFSk2: ld a,0 ;Else Set Returned Status OK ret ; Return page ;====================================================================== ; Parse a Line (28_Feg_84) ;========================= ; 1) This routine parses one line. ; 2) It Returns an EOL to continue and an EOF to Stop. ; Parse_a_Line: call Get_Non_White ;Repeat Strip White_Space cp EOF ; If (Char eq End of File) ret z ; Return cp ';' ; If (Char eq Comment) jr nz,PLsk1 call Get_Next_Line ; Get the Next Line jr Parse_a_Line Plsk1: cp Cr jr z,Parse_a_Line ;Until ((Char ne Comment)&(Char ne Cr)) cp '*' ;If (Char eq File Spec) jr nz,PLsk2 call Get_Chain_File ; Get the Chain File Spec ret ; Return PLsk2: call Code_to_Key ;Else Move Key Code into Key Table or a ; If (Return_Status ne Continue) ret nz ; Return call Def_to_Temp ; Get Key Definition or a ; If (Return_Status ne Continue) ret nz ; Return call Temp_to_Key ; Move Temp Buffer into Key Table ret ; Return ;---------------------------------------------------------------------- ; Get Chain File (3_Mar_84) ;-------------------------- ; Get_Chain_File: call Get_Non_White ;Remove Leading White Space cp EOF ;If (End of File Encountered) ret z ; Return call Force_Upper_Case ;Force the character to upper case ld (Command_Fcb+1),a ;Save the first character of the name call Get_Next_Char ;Get the next char of the file name ld hl,Command_Fcb ;HL:= Start of Command Fcb cp ':' ;If (that was a drive spec) jr nz,GFsk1 ld a,(Command_Fcb+1) ; Convert drive letter to number sub 'A'-1 ld a,(Command_Fcb) ; Install the drive number call Get_Next_Char ; Get the next character ld b,8 ; B:= counter to 8 char max ld hl,Command_Fcb+1 ; HL:= Start of command fcb string jr GFlp1 GFsk1: ld b,7 ;Else B:= Counter to 7 char max ld hl,Command_Fcb+2 GFlp1: call Force_Upper_Case ;Repeat Force character to upper case cp EOF ; If ( (Char eq End of file) or jr z,GFdone cp Cr ; (Char eq End of Line) or jr z,GFdone cp '.' ; (Char eq Period) or jr z,GFdone cp Space ; (Char eq Space) or jr z,GFdone cp Tab ; (Char eq Tab) ) jr z,GFdone ; Break ld (hl),a ; Move char into Command_Fcb inc hl push hl push bc call Get_Next_Char ; Get the next character pop bc pop hl djnz GFlp1 ;Until (Max number of char moved) GFdone: call Get_Next_Line ld a,0 ret page ;---------------------------------------------------------------------- ; Code to Key (28_Feb_84) ;------------------------ ; 1) This routine gets the key definition string, translates it and ; then moves it into the Key Table. ; Code_to_Key: ld bc,2 ;If (Char eq Control) cp '^' ; BC:= Index to control column jr z,GkSk1 dec bc ;Else If (char eq Shifted) cp '~' ; BC:= Index to shifted column jr z,GkSk1 dec bc ;Else BC:= Index to UnShifted column call Put_Back_Char ; put character back into record GkSk1: push bc call Key_to_Dict_Buf ;Move Function Key Name into its buffer or a ;If (Def not found) ret nz ; Return Error ld hl,Key_Dictionary ;HL:= Start of the function key dict. call Lookup_Key_Name ;Find the key in the dictionary pop bc or a ;If (Key not defined) ret nz ; Return add hl,bc ;HL:= Pointer to key code ld a,(hl) ;A:= Key Code cp Null ;If (Invalid Function Key Assignment) jr nz,GkSk5 ld a,Invalid_Key ; Set the returned error status ret ; Return GkSk5: call Update_Key_Table ;Enter the key code into local buffer or a ;If (Return_Status eq Error) ret nz ; Return (table overflowed) ld a,(Number_of_Keys) inc a ld (Number_of_Keys),a ;Increment the number of keys defined ld a,0 ;Set Returned Status to OK ret page ;---------------------------------------------------------------------- ; Definition to Temp Buffer (4_Mar_84) ;------------------------------------- ; 1) This routine builds the remainder of the current line into the ; the temp buf. The line is terminated either by a carriage return ; or an End of File character. The line length is returned in the ; location Temp_Length. ; 2) Several special symbols are recognized. ; ; Ends the line (comment follows) ; ^ The character that follows is a control character ; \ The character that follows is to be taken literally ; _ Preceeds the special symbols for non-printing chars ; Def_to_Temp: ld a,0 ld (Temp_Length),a ;Initialize temp buffer length to 0 call Get_Non_White ;Strip Leading White Space DTlp1: cp Cr ;While ( (char ne End of Line) and jr z,DTend cp EOF ; (char ne End of File) ) jr nz,DTsk1 DTend: call Put_Back_Char ; (Put back Cr or EOF) ld a,0 ; (Set Return Status OK) ret ; (Return) DTsk1: cp ';' ; If (Char eq Comment) jr nz,DTsk2 call Get_Next_Line ; Get the Next Line ld a,0 ret DTsk2: cp '\' ; If (char eq Literal) jr nz,DTsk3 call Get_Next_Char ; Get the next character cp EOF ; If ( (End or File) or jr z,DTsk21 cp Cr ; (End of Line) ) jr nz,DTsto DTsk21: ld a,UnExpected_End ; Set Error Status ret ; Return DTsk3: cp '^' ; If (char eq Control) jr nz,DTsk4 call Get_Next_Char ; Get the next character call Force_Upper_Case ; Force it to upper case cp 40h ; If (Char in range) jr c,DTsk31 cp 60h jr nc,DTsk31 and 1Fh ; Convert to control jr DTsto DTsk31: ld a,Bad_Definition ; Else Set Error Status ret ; Return DTsk4: cp '_' ; If (Char eq Special) jr nz,DTsto call Put_Back_Char ; (Replace the underscore) call Non_to_Dict_Buf ; Move Symbol to Dict_Buf or a ; If (Unexpected End Err) ret nz ; Return (Error) ld hl,Non_Dictionary ; HL:= Start of Non_Dict call Lookup_Key_Name ; Find key in dictionary or a ; If (Key not defined) ret nz ; Return (Error) ld a,(hl) ; Get the key code DTsto: ld c,a ; (Save Char in C register) ld a,(Temp_Length) ld e,a ld d,0 ; DE:= Offset into temp buffer ld hl,Temp_Buffer add hl,de ; HL:= Pointer into Temp Buffer ld (hl),c ; Temp_Buffer(offset):= char ld a,e inc a ; If (temp buffer overflowed) jr nz,DTsk5 ld a,Temp_Overflow ; Set Return Error Status ret ; Return DTsk5: ld (Temp_Length),a ; Temp_Length:= Temp_Length + 1 call Get_Next_Char ; Get Next Character from record jr DTlp1 ret ;Return page ;---------------------------------------------------------------------- ; Temp to Key (2_Mar_84) ;----------------------- ; 1) This routine moves the contents of the Temp Buffer into Key Table. ; 2) If there was room for the whole Temp Buffer then the accm is ; returned equal to zero; Else its returned with the no room error ; code (Key_Overflow) generated in Update_Key_Table. ; Temp_to_Key: ld a,(Temp_Length) ld b,a ;(save length in BC) call Update_Key_Table ;Enter the Def Length into local buffer or a ;If (Return_Status eq Error) ret nz ; Return (table overflowed) ld a,b ;If (length is zero) or a ret z ; Return (Status equal OK) ld hl,Temp_Buffer TKlp1: ld a,(hl) ;Repeat Get next character from temp buffer inc hl ; Increment temp buffer pointer push hl call Update_Key_Table ; Enter the character pop hl or a ; If (Key Table has overflowed) ret nz ; Return djnz TKlp1 ;Until (character count is zero) ld a,0 ;Set Return Status to OK ret ;Return page ;====================================================================== ; Non_Printing Key to Dictionary Buffer (2_Mar_84) ;================================================= ; 1) This routine Moves a key name into the dictionary buffer. ; 2) This routine expects to read an Undescore followed by a three ; character sysmbol name for a non_printing character. ; 3) Before entering this routine the underscore has already been ; read and then put back into the input stream. ; Non_to_Dict_Buf: ld a,4 ;(length is always '_' + 3 char symbol) ld (Dict_Length),a ;Set the dictionary buffer Length ld b,a ;B:= Char Counter ld de,Dict_Buffer ;DE:= Start of temp Buffer NDlp1: push bc ;Repeat push de call Get_Next_Char ; Get the next character pop de pop bc cp Cr ; If ( (Char eq end of line) or jr z,NDerr cp EOF ; (Char eq EOF) ) jr nz,NDsk1 NDerr: ld a,UnExpected_End ; Set Error Return Status ret ; Return NDsk1: call Force_Upper_Case ; Force character to upper case ld (de),a ; Store a character inc de ; Increment the Storage Pointer djnz NDlp1 ;Until (count eq 0) ld a,0 ;Set Returned Status ret ;Return page ;---------------------------------------------------------------------- ; Key to Dictionary Buffer (2_Mar_84) ;------------------------------------ ; 1) This routine Moves a key name into the dictionary buffer. ; Key_to_Dict_Buf: call Get_Non_White ;Strip Leading White Space ld b,0 ;B:= Char Counter ld de,Dict_Buffer ;DE:= Start of temp Buffer KNlp1: cp Space ;Loop If (Char eq Space) jr z,KNDone ; Break cp Tab ; If (Char eq Tab) jr z,KNDone ; Break cp Cr ; If (Char eq end of line) jr z,KNDone ; Break cp Lf ; If (Char eq Line Feed) jr z,KNDone ; Break cp EOF ; If (Char eq EOF) jr z,KNDone ; Break call Force_Upper_Case ; Force character to upper case ld (de),a ; Store a character inc de ; Increment the Storage Pointer inc b ; Increment the char counter ld a,Max_Dict_Length cp b ; If (Dict_Buffer has Overflowed) jr nz,KNsk1 ld a,Dict_Overflow ; Set Return Error Status ret ; Return KNsk1: push bc push de call Get_Next_Char ; Get the next character pop de pop bc jr KNlp1 KNDone: call Put_Back_Char ;Put the character back ld a,b ;(get the character counter) ld (Dict_Length),a ;Update dictionary buffer Length ld a,0 ;Set Returned Status ret ;Return page ;---------------------------------------------------------------------- ; Lookup Key Name (28_Feb_84) ;---------------------------- ; 1) This routine searches the key dictionary for String matching ; the one in the dictionary buffer. ; 2) Register Usage: ; A -> Returned = 0 for NO Error ; B -> Counter for the length of the string ; HL -> Enter pointing to Start of Dictionary to search ; Lookup_Key_Name: ld a,(Dict_Length) ld c,a ;C:= current dictionary buffer length or a ;If (there's no name to look for) jr nz,SrcLp1 ld a,Missing_Key_Def ; Set Returned Error Status ret ; Return SrcLp1: ld (Save_Pointer),hl ;Loop Save the pointer to the arg inc hl inc hl inc hl ; HL:= pointer to length byte ld a,(hl) ; A:= Length of Name or a ; If (its the End of the Dict.) jr nz,SrcSk2 ld a,Bad_Key_Name ; Set Return Error Status ret ; Return SrcSk2: ld b,a ; B:= Length of dictionary string inc hl ; HL:= Pointer to Start of String cp c ; If (the Length Matches) jr nz,SrcNxt ld de,Dict_Buffer ; DE:= Start of Dict buf SrcLp2: ld a,(de) ; Repeat cp (hl) ; If (no match) jr nz,SrcNxt ; Break inc hl ; inc dict pointer inc de ; inc Temp pointer djnz SrcLp2 ; Until (Count eq 0) ld hl,(Save_Pointer) ; HL:= Pointer to arg. ld a,0 ; Flag:= Success ret ; Return SrcNxt: ld e,b ld d,0 ; DE:= Offset add hl,de ; HL:= Pointer to start next name jr SrcLp1 page ;---------------------------------------------------------------------- ; Update Key Table (28_Feb_84) ;----------------------------- ; 1) This routine enters one byte into the Local Key Table and keeps ; track of how many entries have been made. ; 2) If the Maximum Table Size is exceeded then a Key Overflow error ; code is returned; Else, the accm is returned equal to zero. ; 3) Register Usage: ; A -> Returned 0 for OK, or Key_Overflow for Error ; DE -> Used in range checking and offset generation ; HL -> Pointer into the Local Key Table ; Update_Key_Table: ld hl,Max_Key_Length ;HL:= Maximum Length of Local Key Buffer ld de,(Key_Length) ;DE:= Offset to current position or a ;(clear carry) sbc hl,de ;If (Local Key Buffer has overflowed) jr nc,UKSk1 ld a,Key_Overflow ; Set Returned Error Status ret ; Return UKSk1: ld hl,Key_Table add hl,de ;HL:= Pointer to current location ld (hl),a ;Save char in local key table inc de ld (Key_Length),de ;(Increment the current table length) ld a,0 ;Set Returned Status OK ret ;Return page ;====================================================================== ; Get Next Line (28_Feb_84) ;========================== ; 1) This routine reads characters until it finds either a carriage ; return or an End of File Mark. ; Get_Next_Line: Call Get_Next_Char ;Loop Get a Character cp Cr ; If (Character eq End of Line) jr z,GNSk1 ; Break cp EOF ; If (Character eq End of File) jr nz,Get_Next_Line ; Break GNSk1: call Put_Back_Char ;Put last char back into record buffer ret ;---------------------------------------------------------------------- ; Get Non White (29_Feb_84) ;-------------------------- ; 1) This routine reads characters until it finds a character that ; is NOT a Space, NOT a Line Feed and NOT a Tab. ; Get_Non_White: call Get_Next_Char ;Repeat cp Space ; Get the Next Character jr z,Get_Non_White cp Tab jr z,Get_Non_White ;Until ((Char ne Space) and cp Lf ; (Char ne Tab) and jr z,Get_Non_White ; (Char ne Line Feed)) ret ;Return ;---------------------------------------------------------------------- ; Force Character to Upper Case (2_Mar_84) ;----------------------------------------- ; 1) This routine forces the character passed in the accm to ; upper case if its entry value is lower case. ; Force_Upper_Case: and 7fh ;mask off parity bit cp 'a' ;If (Char lt Lower case a) ret c ; Return cp 'z'+1 ;If (Char gt Lower case z) ret nc ; Return sub 20h ;Force Character to Upper Case ret ;Return ;---------------------------------------------------------------------- ; Put Back Character (29_Feb_84) ;------------------------------- ; Put_Back_Char: ld (Put_Back_Buf),a ;Put Back Char:= current char ret ;Return page ;---------------------------------------------------------------------- ; Get Next Character (29_Feb_84) ;------------------------------- ; 1) This routine reads the next character from the source file. ; 2) If the buffer is empty (Record_Offset ge Max_Rec_Length) then it ; is filled from the previously opened file. ; 3) Carriage Returns Cause the Line Counter to be incremented. ; Get_Next_Char: ld a,(Put_Back_Buf) ;If (a character was put back) or a jr z,GCSk1 ld c,a ; (save the character ld a,0 ld (Put_Back_Buf),a ; Put Back Char:= none ld a,c ; (restore the char) ret ; Return GCSk1: ld a,(Record_Offset) ld e,a ;E:= Current offset in record ld a,Max_Rec_Length ;A:= Maximum length of record sub e ;If (We're at the end of the record) jr nz,GCSk2 push bc ld c,Bdos_Read_Seq ; C:= Read Sequential Function # ld de,Fcb1 ; DE:= Pointer to FCB call Bdos_Entry ; Read the next record pop bc or a ; If (there was a read error) ld a,Disk_Read_Error ; Set Error Return Status ret nz ; Return ld e,0 ; Re:Initialize the E reg GCSk2: ld d,0 ld hl,Record_Buffer add hl,de ;HL:= Pointer to current character ld a,e inc a ld (Record_Offset),a ;Update Record Offset ld a,(hl) ;Return Current Character cp Cr ;If (Character eq carriage return) jr nz,GCSk3 ld a,(Line_Count) inc a ld (Line_Count),a ; Increment the line count ld a,Cr ; (restore the carriage return) GCSk3: ret ;Return page ;====================================================================== ; Inject Function Keys (1_Mar_84) ;================================ ; Inject_Keys: call Get_the_pool ;Get the free space pool call Get_Pointers ;Get pointers in free space pool ld de,(FS_Length) ld hl,(FC_Length) add hl,de ;HL:= Free_space_len + Function_key_len ld de,(Key_Length) or a ;(clear the carry) sbc hl,de ;If (there's insufficient Free Space) jr nc,IKsk1 ld a,Table_too_Big ; Set Error Return Status ret ; Return IKsk1: ex de,hl ld hl,(FS_Pointer) dec hl dec hl ;(move DE to start of length pointer) ld (hl),e inc hl ld (hl),d ;Update the Free_Space Length inc hl add hl,de ;HL:= Current Position + Free Space len ld a,Id_IMS ld (hl),a ;Write Ims Buffer Code ld de,(IMS_Length) inc hl ld (hl),e inc hl ld (hl),d ;Write Ims Buffer Length inc hl push hl ex de,hl ;DE:= Destination (current pool pntr) ld hl,(IMS_Pointer) ;HL:= Source (current ims start) ld bc,(IMS_Length) ;BC:= Count (Length of the Ims buffer) call Move_a_Block ;Move the Ims Sting Body pop hl ld de,(IMS_Length) add hl,de ld bc,(Key_Length) ;BC:= Count (length of key table) ld a,Id_FC ld (hl),a ;Write Function Key Code inc hl ld (hl),c inc hl ld (hl),b ;Write Fuction Key Length inc hl ex de,hl ;DE:= Destination (current pool pntr) ld hl,Number_of_Keys ;HL:= Source (Start of local Table) ldir ;Move the Function Key Table call Put_the_Pool ;Restore the free space pool ld a,0 ;Set Returned Status to OK ret ;Return page ;---------------------------------------------------------------------- ; Get Pointers into the Free Space (1_Mar_84) ;-------------------------------------------- ; 1) This routine finds and records a) the Free Space Pointer, b) the ; Ims Buffer, and c) the Function Key Table starting address and ; Length ; 2) Register Usage: ; C -> holds the desired function key code ; DE -> holds length of desired data structure ; HL -> Enter pointing to the start of the free space pool. ; Get_Pointers: ld c,Id_FS call Find_a_Code ld (FS_Pointer),hl ;Save the Free Space Argument Pointer ld (FS_Length),de ; " " " " Length add hl,de ;HL:= Pointer to next entry ld c,Id_IMS call Find_a_Code ld (IMS_Pointer),hl ;Save the IMS Argument Pointer ld (IMS_Length),de ; " " " " Length add hl,de ;HL:= Pointer to next entry ld c,Id_FC call Find_a_Code ld (FC_Pointer),hl ;Save the Function Key Table Pointer ld (FC_Length),de ; " " " " " Length ret ; Find a Function Key Code ;------------------------- ; -This routine is only used by the Get_Pointers routine. ; Find_a_Code: ld a,(hl) ;Loop A:= Current function code inc hl ld e,(hl) inc hl ld d,(hl) ; DE:= Length of argument inc hl ; HL:= Pointer to Start argument cp c ; If (Current_FC eq Desired_FC) ret z ; Return add hl,de ; HL:= Pointer to next code jr Find_a_Code page ;---------------------------------------------------------------------- ; Geô thå Free Space Pooì (16_Apr_84) ;----------------------------------- ; 1) This routine calls the BDOS to determine the version of CP/M. ; ; For CP/M 3, this routine forces the destination to be the local ; buffer, calls the cold start (extended bios functions) entry ; point, and then saves the registers after swapping hl and de. ; ; For CP/M 2 this routine simply returns a pointer to the pool ; in the BIOS. ; Get_the_pool: call Get_Version ;check the version of CP/M jr nz,cpm2 ;jump if CP/M 2 ld a,F_Get_Pool ld de,Pool_Copy ;DE:= Pointer to Local Buffer call Call_Cold_Boot ;Move System Memory into the local buffer ld (save_BC),bc ;Save the returned registers ex de,hl ;HL:= Pointer to first xlt ld (save_DE),de ld (save_HL),hl ld hl,Pool_Copy ret ;Return cpm2: ld hl,(1) ;warm boot adress ld de,Pool_off ;offset to pool pointer add hl,de ld a,(hl) ;get pool pointer inc hl ld h,(hl) ld l,a ret ;---------------------------------------------------------------------- ; Restore the Free Space Pool (16_Apr_84) ;--------------------------------------- ; 1) This is the inverse of Get_the_pool; It replaces the system's memory ; with the contents of the local buffer. ; 2) Get_the_pool MUST be called before entering this routine. ; Put_the_Pool: call Get_Version ;check the version of CP/M ret nz ;return if CP/M 2 ld a,F_Write_Sys ;Function_1:= Write to system memory ld bc,(Save_BC) ld de,(Save_DE) ld hl,(Save_HL) ;Restore the Returned Registers call Call_Cold_Boot ;Write buffer back into system memory ret ;---------------------------------------------------------------------- ; Check the CP/M version (16_Apr_84) ;----------------------------------- ; 1) This routine checks the CP/M version. It returns with the ; Z flag = 1 if CP/M 3. ; Get_Version: ld c,Bdos_Ret_Ver ;Return version Bdos call call Bdos_Entry ld a,0f0h and l cp 30h ret ;---------------------------------------------------------------------- ; Call the Bios Cold Boot Entry Point (4_Jan_84) ;----------------------------------------------- ; 1) The Cold Boot Entry point to the bios (1st entry in the bios ; jump table) is located by looking at locations 1 & 2 which ; point to the warm boot address (the desired address + 3). ; Call_Cold_Boot: push hl ;Save the HL Register Pair ld hl,(1) ;HL:= Warm Boot Address ld l,0 ;HL:= Cold Boot Address ex (sp),hl ;Restore the HL Register Pair ret ;Goto The Cold Boot entry page ;-------------------------------------------------------------------- ; Move_a_Block (1_Mar_84) ;------------------------ ; 1) This routine moves a block of memory. The block can overlay itself. ; 2) Register Usage: ; BC -> Byte Count ; DE -> Destination ; HL -> Source ; Move_a_Block: ld a,b ;If (Length of move is zero) or c ret z ; Return push hl or a ;(clear the carry) sbc hl,de ;If (Source eq Destination) pop hl ret z ; Return jr c,MBSk1 ;Else If (Source gt Destination) ldir ; Move the Block Up ret ; Return MBSk1: push hl ex de,hl ;Else (Source lt Destination) or a ; (clear the carry) add hl,bc ; Dest:= Dest + Byte_Count dec hl ; (move pointer back to last char) ex de,hl pop hl add hl,bc ; Source:= Source + Byte_Count dec hl ; (move pointer back to last char) lddr ; Move the Block Down ret ; Return page ;====================================================================== ; Report Errors (29_Feb_84) ;========================== ; 1) Report Errors on the console. ; 2) Register Usage: ; A -> Has Error Code on entry ; B -> Counter ; C -> Holds copy of Error Code ; Report_Errors: push af ld de,ErrOpn ld c,Bdos_PString call Bdos_Entry ;Print the Start of the Opening Message ld a,(Line_Count) ld l,a ld h,0 ;HL:= Line Number call Print_Line_Number ;Print the line number pop af ld c,a ;C:= Error Code to Find ld b,Max_Error ld hl,Error_Table ;HL:= Start of the error table RELp1: ld a,(hl) ;Repeat A:= Table's Error Code inc hl ld e,(hl) inc hl ld d,(hl) ; DE:= Pointer to String inc hl ; (HL equal to start next entry) cp c ; If (Code eq table) jr z,REprn ; Goto Print djnz RELp1 ;Until (the whole tables been checked) ld de,NoCode ;(set pointer to 'Unrecognized Error') REprn: ld c,Bdos_PString ; call Bdos_Entry ; Print the Message ret page ;---------------------------------------------------------------------- ; Print Line Number (5_Mar_84) ;----------------------------- ; 1) This routine prints the 16 bit number (passed in the HL) in ascii. ; 2) Register Usage: ; HL -> 16 bit number to be printed ; Print_Line_Number: ld bc,0FFFFh push bc ;Put end flag on stack ld bc,10 ;divisor:= 10 dloop: call divide ;Repeat Divide push hl ; Save the remainder ld hl,9 or a sbc hl,de ex de,hl ; (Move quotient to dividend) jp c,dloop ;Until (quotient is less than 9) ld a,l ;Move the last result into the accm ploop: add a,'0' ;Repeat ld e,a ; Conver number to ascii ld c,2 call 5 ; Print the number pop hl ; Get the next number ld a,l cp 0FFh jr nz,ploop ;Until (end of stack flag has been read) ret ;Return ;---------------------------------------------------------------------- ; 16 bit Divide (5_Mar_84) ;------------------------- ; this routine was written by Bill Smith. ; divide 16-bit number in [hl] by [bc] ; on exit, [de] is 16-bit quotient, [hl] is remainder ; divide: add hl,hl ;hi *2 ex de,hl ;[de] becomes lo ld hl,0 ;init hi ld a,16 ;16 bits divid0: adc hl,hl ;hi *2 push hl ;save in case borrow or a ;clear borrow sbc hl,bc ;sbc hl,bc ;hi=hi-divisor ccf ;invert borrow for shift later jr c,divid1 ;if borrow { pop hl ;replace with original hi push hl ;stack phase divid1: inc sp inc sp ;drop ex de,hl ;get lo adc hl,hl ;lo *2 + remainder ex de,hl dec a ;count-- jr nz,divid0 ;while not done, loop ret page ;====================================================================== ; Load and Go (3_Mar_84) ;======================= ; Load_and_Go: ld hl,(6) ld bc,Load_Length ;BC:= Load Length or a ;(clear the carry) sbc hl,bc push hl ex de,hl ;DE:= Destination (Base Bdos - 2 pages) ld hl,Start_Lgo ;HL:= Source (beginning of Lgo) ldir ;Move the code into place pop hl jp (hl) ;Execute the Loader ; This portion of the load and Go routine is relocated into hi memory. ;--------------------------------------------------------------------- ; Start_Lgo: ld hl,(6) ;HL:= Start of Bdos ld de,LS_offset ;DE:= Offset to local stack or a sbc hl,de ld sp,hl ;Stack_Pointer:= Local Stack ld hl,(6) ;HL:= Start of Bdos ld de,CF_offset ;DE:= Offset to Command_FCB or a sbc hl,de ;HL:= start of Command_Fcb ld de,Fcb1 ;DE:= page zero 1st default FCB ld bc,33 ;BC:= Count (move the whole FCB) ldir ;Move Command_Fcb to page zero FCB1 ;Check for no Chain Command ld a,(Fcb1+1) ;If (there's no command line) cp Space jp z,Bios_Entry ;Open the Command's File ld de,Fcb1 ;DE:= Start of Command_Fcb ld c,Bdos_Open_File ;C:= Open File Function call Bdos_Entry ;Open the command file cp 0ffh ;If (file can't be opened) jp z,Bios_Entry ; Warm Start ;Read the Command File ld de,100h - Record_Length ;DE:= Dma Pointer to start Load LGlp1: ld hl,Record_Length ;Repeat add hl,de ex de,hl ; DE:= Current Addr + Record_Length push de ld c,Bdos_Set_DMA ; C:= Set DMA Address Function call Bdos_Entry ; Set the Dma Address ld de,Fcb1 ; DE:= Start of Command_Fcb ld c,Bdos_Read_Seq ; C:= Read Sequential Function call Bdos_Entry ; Read the Next record pop de or a jr z,LGlp1 ;Until (End of File or error) cp Status_EOF ;If (it was other than end of file) jp nz,Bios_Entry ; Warm Boot ;Close the command file ld de,Fcb1 ;DE:= Pointer to FCB1 ld c,Bdos_Close_File ;C:= Close file function call Bdos_Entry ;Close the command file ;Move the old command line back into place ld hl,(6) ;HL:= Start of the Bdos ld de,OIL_offset ;DE:= Offset to start of Old Input Line or a sbc hl,de ;HL:= Pointer to remainder of Old Input Line ld de,Default_Dma ;DE:= Command line buffer LGlp2: ld a,(hl) ld (de),a ;Move The Line Length into place inc de ;DE:= Pointer 1st char of Dest. inc hl ;HL:= Pointer 1st char of Source or a ;If (line length ne 0) jr z,LGsk1 ld c,a ld b,0 ldir ; Move remainder of line LGsk1: ld a,0 ld (de),a ;Enter the terminating 0 ;Move the old 2nd Default FCB into the 1st FCB's place in page zero ld hl,(6) ld de,SF_offset or a sbc hl,de ;HL:= Source (old FCB2) ld de,Fcb1 ;DE:= Destination (1st Fcb) ld bc,13 ;BC:= Count (move 12 bytes) ldir ;Move the FCB into place ld hl,Fcb2 ld (hl),0 ;Set FCB2's Drive to current drive ld b,11 LGlp3: inc hl ;Repeat Move pointer to next position ld (hl),Space ; Set next position to a Space djnz LGlp3 ;Until (File name has been Filled) inc hl ld (hl),0 ;Set FCB2's next record field to zero ld a,0 jp 100h page ;---------------------------------------------------------------------- ; Save_Input_Param and Load_and_Go Data Areas (3_Mar_84) ;------------------------------------------------------- ; ds 10h ;Define some stack space Load_Stack: dw 0 Save_FCB2: db 0,' ',0 ;original FCB2 destined for FCB1 Old_Input_Line: ds 80h,0 ;Remainder of Command Line Command_Fcb: db 0,' COM',0 ds 33 - 13,0 ;Chain Command's FCB End_Lgo: page ;====================================================================== ; Error Code Tables and Message Strings (29_Feb_84) ;================================================== ; ;Error Message String Lookup Table ;--------------------------------- ; Error_Table: db Missing_Key_Def ;No Key Definition dw MKDmsg db Bad_Key_Name ;Missing Function Key Name dw BKNmsg db Invalid_Key ;Invalid Function Key Assignment dw IKmsg db Def_too_Long ;Key Definition String is too long dw DTLmsg db Temp_Overflow ;Temp buffer overflowed dw TOmsg db Key_Overflow ;Local Function Key Table Overflowed dw KOmsg db Table_too_Big ;Function Key Table is too large dw TTBmsg db No_Key_File ;No Key file name dw NKFmsg db Bad_Key_File ;Can't open the key file dw BKFmsg db Disk_Read_Error ;Error occured in a disk read operation dw DREmsg db UnExpected_End ;Unexpected End (Eol or Eof) dw UEmsg db Bad_Definition ;Illegal Character in definition dw BDmsg db Dict_Overflow ;Dictionary Buffer has overflowed dw DOmsg End_Table: Max_Error equ ( (End_Table - Error_Table)/3 ) + 1 page ; Error Message Strings (29_Feb_84) ;---------------------------------- ; MKDmsg: db ' No Key Definition $' BKNmsg: db ' Missing Function Key Name $' IKmsg: db ' Invalid Function Key Assignment $' DTLmsg: db ' Key Definition String is too long $' TOmsg: db ' Temp buffer overflowed $' KOmsg: db ' Local Function Key Table Overflowed $' TTBmsg: db ' Function Key Table is too large $' NKFmsg: db ' No Key file name $' BKFmsg: db ' Unable to open the key file $' DREmsg: db ' Error occured in a disk read operation $' UEmsg: db ' Unexpected End (Eol or Eof) $' BDmsg: db ' Illegal Character $' DOmsg: db ' Dictionary Buffer has overflowed $' NoCode: db ' Unrecognized Error $' ErrOpn: db Cr,Lf, 'Error on line $' page ;====================================================================== ; Key Dictionary Macro Definitions (28_Feb_84) ;============================================= ; ; Generate a Function Key Dictionary Entry (28_Feb_84) ;----------------------------------------------------- ; 1) This macro generates an entry in the function key dictionary. ; 2) Each entry in the dictionary has the following form ; 1 byte Length of the name string ; 3 bytes Key definitions (normal, shifted and contol) ; n bytes Name of function key ; DfKey macro Name, K1, K2, K3 local L1, L2 db K1 ;Key Output for UnShifted db K2 ; " " " Shifted db K3 ; " " " Control db l2 - l1 ;length of Name string l1: db '&Name' ;Name of function key l2: endm ; Terminate the Key Dictionary (28_Feb_84) ;----------------------------------------- ; DfEnd macro ds 4,0 ;4 bytes of zero to end the table endm page ;---------------------------------------------------------------------- ; Key Dictionary (28_Feb_84) ;--------------------------- ; 1) This Dictionary contains all of the Function Key Codes ; Key_Dictionary: DfKey F1, 40h, 60h, 0h DfKey F2, 41h, 61h, 1h DfKey F3, 42h, 62h, 2h DfKey F4, 43h, 63h, 3h DfKey F5, 44h, 64h, 4h DfKey F6, 45h, 65h, 5h DfKey F7, 46h, 66h, 6h DfKey F8, 47h, 67h, 7h DfKey F9, 48h, 68h, 8h DfKey F10, 49h, 69h, 9h DfKey FA, 5Ch, 7Ch, 1Ch DfKey FB, 5Dh, 7Dh, 1Dh DfKey FC, 5Eh, 7Eh, 1Eh DfKey FD, 5Fh, 7Fh, 1Fh DfKey ERASE, 49h, 69h, 9h DfKey UP, 4Ah, 6Ah, 0Ah DfKey DOWN, 4Bh, 6Bh, 0Bh DfKey LEFT, 4Ch, 6Ch, 0Ch DfKey RIGHT, 4Dh, 6Dh, 0Dh DfKey HOME, 4Eh, 6Eh, 0Eh DfKey HELP, 4Fh, 6Fh, 0Fh DfKey TAB, Null, 1Ah, 1Bh DfKey 0, 30h, 20h, 10h DfKey 1, 31h, 21h, 11h DfKey 2, 32h, 22h, 12h DfKey 3, 33h, 23h, 13h DfKey 4, 34h, 24h, 14h DfKey 5, 35h, 25h, 15h DfKey 6, 36h, 26h, 16h DfKey 7, 37h, 27h, 17h DfKey 8, 38h, 28h, 18h DfKey 9, 39h, 29h, 19h DfKey <.>, 2Ah, 2Bh, 2Ch DfKey ENTER, 2Dh, 2Eh, 2Fh DfKey <->, 3Ah, 3Bh, 3Ch DfKey <,>, 3Dh, 3Eh, 3Fh DfEnd ;End of the table ;---------------------------------------------------------------------- ; Non_Printing Key Dictionary (2Mar_84) ;-------------------------------------- ; 1) This Dictionary contains all of the Special Key names for non- ; printing keys. These names only can appear on the right side of ; the definition. ; Non_Dictionary: DfKey _TAB, 9, 0, 0 ;Tab DfKey _ESC, 1Bh, 0, 0 ;Escape DfKey _DEL, 7Fh, 0, 0 ;Delete DfKey _RTN, 0Dh, 0, 0 ;Carriage Return DfEnd ;End of the table page ;====================================================================== ; General Data Area (29_Feb_84) ;============================== ; 1) Note that the Key_Length during the run time of the translator ; is always equal to the function key table length - 1. The - 1 ; condition is forced because the Number_of_Keys byte is not included. ; ;Local Variables Save_Pointer: dw 0 ;Temp pntr storage (Lookup_Key_Name) Line_Count: db 0 ;Current Line Count (Get_Next_Char) Put_Back_Buf: db 0 ;Character put back (Put_Back_Char) ;Free Space Pointers and Lengths FS_Pointer: dw 0 ;Free space pointer FS_Length: dw 0 ; " " length IMS_Pointer: dw 0 ;Ims pointer IMS_Length: dw 0 ; " length FC_Pointer: dw 0 ;Function Key Table pointer FC_Length: dw 0 ; " " " length ;Register Storage (for get and put pool functions) Save_BC: dw 0 ;Save Location for the BC register pair Save_DE: dw 0 ; " " " " DE " " Save_HL: dw 0 ; " " " " HL " " ;Temporary Buffer Temp_Length: db 0 ;Current Length of the Temp Buffer Temp_Buffer: ds Max_Temp_Length ;Temporary Buffer (init to spaces) ;Dictionary Buffer Dict_Length: db 0 ;Length of Dictionary Buffer Dict_Buffer: ds Max_Dict_Length ;Dictionary buffer (see Lookup_Dict) ;Local Copy of Key Table Key_Length: dw 0 ;Offset into the Function Key Table Number_of_Keys: db 0 ;Number of function key definitions Key_Table: ds Max_Key_Length ;Local Function Key Table ;Source Buffer Record_Offset: db Max_Rec_Length ;Current Record Position (init end rec) Record_Buffer: ds Max_Rec_Length ;Current Record from disk Pool_Copy: ds Max_Pool_Length ;Copy of the free space pool ds Max_Stack_Space ;Main Stack Main_Stack: end