;---------------------------------------------------------- ;Option ROM Header must be ORGed at 0 by the assembler ;or linked at 0 by the linker. ;---------------------------------------------------------- ;Routine to turn on the Option ROM OPON: EQU 0FAA4H ;Globals on the Telcom Back Page to temporarily hold HL and ;DE registers during a CALL to Standard ROM, or during an ;Interrupt. HOLDH: EQU 0FCC0H HOLDD: EQU 0FCC2H INTH: EQU 0FCC4H INTD: EQU 0FCC6H ;Entry point arrived at by CALL 63012 RST0?: INX SP INX SP JMP PROGRAM DB 0,0,0 RST1?: ;Not used RET DB 0,0,0,0,0,0,0 RST2?: ;Not used RET DB 0,0,0,0,0,0,0 RST3?: ;Not Used RET DB 0,0,0,0,0,0,0 RST4?: ;Not Used RET DB 0,0,0 TRAP?: DI JMP INTRAP RST5?: ;Not Used RET DB 0,0,0 RST55?: DI JMP INT55 ;RST 6 used as short call to a Standard ROM routine. RST6?: JMP STDCALL DB 0 ;Replaces the 6.5 interrupt and sets up a call to 6.5 in ;Standard ROM RST65?: DI JMP INT65 RST7?: ;Not Used RET DB 0,0,0 ;Replaces the 7.5 interrupt and sets up a call to 7.5 in ;Standard ROM RST75?: DI JMP INT75 ;An image of the OPON routine copied to FAA4H by the ;Model 100 power up logic. OPONIMG: PUSH PSW MVI A,1 OUT 0E0H POP PSW RET DB 0 ;--------------------------------------------------------- ;The STDCALL routine allows a program running in the ;the Option ROM to call and return to an address in the ;Option ROM. ;Syntax is to use a RST 6 plus the address to be called. ; ; RST 6 ; DW 04B44H ;--------------------------------------------------------- STDCALL: DI SHLD HOLDH ;Caller's HL XCHG SHLD HOLDD ;Caller's DE POP H ;(HL)=Routine to Call MOV E,M INX H MOV D,M ;DE=Routine to Call INX H ;HL=Return Address PUSH H LXI H,OPON ;return through OPON PUSH H PUSH D ;Return Address LHLD HOLDD ;Caller's DE XCHG LHLD HOLDH ;Caller's HL EI JMP STDON ;Routines for each of the hardware traps. INTRAP: CALL INTCALL DW 0024H RET INT55: CALL INTCALL DW 002CH RET INT65: CALL INTCALL DW 0034H RET INT75: CALL INTCALL DW 003CH RET OPX: ;Turns off the Option ROM (or turns on Standard ROM) ;Depending on your viewpoint. ;This routine must be ORGed at 85H. Ensure the the previous ;Code does not overlap into 85H ORG 85H STDON: PUSH PSW PUSH H LXI H,26C8H XTHL XRA A OPEXIT: OUT 0E0H RET ;--------------------------------------------------------- ;The INTCALL routine allows a program running in the Option ;ROM to call an interrupt routine. ;Syntax: CALL INTCALL plus the address to be called. ; ; CALL INTCALL ; DW 24H ;--------------------------------------------------------- INTCALL: SHLD INTH ;Caller's HL XCHG SHLD INTD ;Caller's DE POP H ;(HL)=Routine to Call MOV E,M INX H MOV D,M ;DE=Routine to Call INX H ;HL=Return Address PUSH H LXI H,OPON ;return through OPON PUSH H PUSH D ;Return Address LHLD INTD ;Caller's DE XCHG LHLD INTH ;Caller's HL JMP STDON ;END OF ROM HEADER PORTION OF CODE ;================Model 100 Routines=============== ;Poll the keyboard and return with or without key ;Entry: None ;Exit: Z if no key. Carry set if afunction key pressed KYREAD: EQU 07242H ;------ ;Clear The Screen CLS: EQU 04231H ;------ ;Output a character to LCD ;Entry Character in A Reg CHROUT: EQU 04B44H ;------ ;Retrieve next directory entry of an active file ;Entry: HL should point to one directory entry less than the ; point at which to begin the search. The search routine ; starts by incrementing to the next entry ;Exit: Z set = no more entries ; else ; HL points to the next directory entry with an ; active file. NXTDIR: EQU 020D5H ;------ ;Locate an empty directory slot. ;Entry: none ;Exit: HL points to a free slot FREDIR: EQU 020ECH ;------ ;Position the cursor ;Entry: H=Column 1-40 ; L=Row 1-8 ;Exit: None CURPOS: EQU 0427CH ;------ ;Erase to end of the current line ERAEOL: EQU 0425DH ;------ ;Turn Cursor On CURSON: EQU 04249H ;------ ;Turn Cursor Off CUROFF: EQU 0424EH ;------ ;Position the cursor to 1 of 24 bar cursor positions ;Entry HL = position 0-23 BARPOS: EQU 059C9H ;------ ;Toggle bar cursor to opposite state at poisition ;Specified in HL ;Entry: HL = Position 0-23 BARCUR: EQU 059E5H ;------ ;Convert Model 100 directory name 'FILE DO' to ;Displayable name 'FILE.DO' ;Entry: DE points to Directory name ; HL points to buffer for formatted output MKPNAM: EQU 059ADH ;------ ;Sound the beeper BEEP: EQU 04229H ;------ ;Make a hole (space) in RAM file ;Entry: HL = where to make the hole ; BC = Size of the hole MAKHOL: EQU 06B6DH ;------ ;Delete bytes in a file ;Entry: HL= where to delete ; BC= number of bytes to delete MASDEL: EQU 06B9FH ;------ ;Reorganize directory pointers DIROK: EQU 02146H ;------ ;=============Model 100 Addresses=============== ;Beginning of the User Directory Area USRDIR: EQU 0F9BAH ;------ ;Beginning of free space MOAT: EQU 0FBB6H ;------ ;=====Globals Allocated to TELCOM back page==== ;Pointer to the start of the search string. ;And its length SEARCH: EQU 0FCCAH SEARCHLEN: EQU 0FCCCH ;------ ;Pointer to the Replace String and its length REPLACE: EQU 0FCCEH REPLACELEN: EQU 0FCD0H ;------ ;Current location in the TEXT file LOC: EQU 0FCD2H ;------ ;============================================== ;MAIN PROGRAM BEGINS HERE ;============================================== ;------ PROGRAM: ;------ ;Check Stack, Install the ROM name and call the search ;and replace routine. ;1. Check that at least 512 bytes of free space ; Exists. LXI H,0 DAD SP XCHG LHLD MOAT ;2. Subtract High bytes of Moat from Stack. Result ; Must be at least 2 (0200H = 512) MOV A,D SUB H JC OMEM CPI 2 JC OMEM ;3. Install The ROM name LXI H,ROMNAME ;Name to appear on Menu CALL TRGINS ;Install it ;4. Execute the main program CALL SANDR ;5. Return JMP STDON ROMNAME: DB 'SandR',0 ;------ OMEM: ;------ ;Print insufficient Memory message and exit LXI H,NOMEM CALL DSPMSG CALL GETCH JMP STDON NOMEM: DB 12,'Insufficient Memory',13,10 DB 'Any Key to Exit',0 ;------ TRGINS: ;------ ;Installs a 6 OR LESS character name as a ROM trigger file on the ;Model 100 directory. ;Entry: HL points to 6 OR LESS null TERMINATED ; character string to use for the name. ;Exit: None ;1. Test if a Trigger file exists PUSH H ;Save New File name. CALL FOTRG ;Find an old trigger file POP D ;File Name ;2. If so then install over it JNZ TRGINS1 ;If found install over it. ;3. Otherwise locate a free directory PUSH D ;else RST 6 ;Call Std ROM to DW FREDIR ;Find an empty Slot. POP D ;and install ;4. Copy in 0F0H file type and 0FFFFH start TRGINS1: MVI M,0F0H ;Trigger File type INX H ;Step past start MVI M,0FFH ;Set start to 0FFFFH INX H MVI M,0FFH INX H ;5. Copy the name to the first null and then ; nulls to the rest of the name. MVI C,8 ;and copy in the name TRGINS2: LDAX D MOV M,A INX H ;Fill the rest of the ORA A ;name with nulls when we JZ TRGINS3 ;hit the null terminator INX D TRGINS3: DCR C ;directory name with nulls JNZ TRGINS2 RET ;------ FOTRG: ;------ ;Searches the directory for an already existing trigger ;file and returns a pointer to it in HL if found. ;Entry: None ;Exit: Z set if none found ; else ; HL points to the directory entry ;1. Starting behind the free directory LXI H,USRDIR-11 ;Free dir - 1 entry ;2. Get the next in use File FOTRG1: RST 6 ;Call Std ROM to DW NXTDIR ;get Next Live File RZ ;no file found ;3. Return Pointing to it if it is a ROM ; trigger file. MOV A,M ;is it a ROM Trigger CPI 0F0H ;Type JNZ FOTRG1 ;No - Go again ANA A ;Clear Z flag RET ;------ SANDR: ;------ ;This routine calls a menu display like the Model 100 ;System Menu but only including visible .DO files. ;The user may position the bar cursor over a file ;name and press enter to select a file for search ;and replace operations. ;1. Allocate Stack space for 24 words and ; save the pointer to the space. LXI H,-48 DAD SP SPHL SANDR1: PUSH H ;2. Set all 48 bytes to 0FFH MVI C,48 SANDR2: MVI M,0FFH INX H DCR C JNZ SANDR2 ;3. Locate all DO files and save pointers to ; Directory entries for each POP H ;Pointer in HL PUSH H CALL FINDDO ;4. Display an empty menu CALL DISPEMPTY ;5. Write any active .DO files over the empty ; slots. POP H ;Pointer PUSH H CALL DISPDO ;6. Let user position the cursor and pick POP H ;Pointer PUSH H CALL PICKDO POP D ;Pointer ;7. If User selected F8 (7 in a reg) then exit CPI 7 JZ SANDR3 ;8. The only other posibility is ENTER. Check ; That the cursor was over a valid entry ; Not 0FFFFH as user could have been looking ; At a display with no .DO files. Directory user is ; pointing to is returned in HL PUSH D ;Pointer MOV A,L ANA H INR A ;9. If it is legal then call the search and ; Replace routine CNZ SR POP H ;10. And Redisplay the menu JMP SANDR1 SANDR3: ;7. Deallocate the stack space. LXI H,48 DAD SP SPHL RET ;------ FINDDO: ;------ ;Entry: HL points to a memory area for the storage of up to ; 24 pointers. ;Exit: The memory area has been loaded with pointers to ; Directory entries if any of .DO files in the ; system. PUSH H ;Save Pointer ;1. Starting from one behind the first free ; user directory slot. LXI H,USRDIR-11 ;Start back one ;2. Find the next active file and return if none found FINDDO1: RST 6 ;Call Std ROM DW NXTDIR ;To locate next active file POP D ;Pointer RZ ;No more files ;3. Test the type byte for C0H = .DO file MOV A,M ;Get File Type CPI 0C0H ;Is it .DO type JNZ FINDDO2 ;Skip if not ;4. And save it if it is XCHG ;else save pointer MOV M,E INX H MOV M,D INX H XCHG FINDDO2: PUSH D JMP FINDDO1 ;------ DISPEMPTY: ;------ ;Display a menu and screen of .DO Files ;1. Clear Screen RST 6 ;Call Std ROM to DW CLS ;Clear The Screen ;2. Display the Logo LXI H,LOGO ;Display MSG CALL DSPMSG ;3. Position to the last line CALL ROW8 ;4. Display a mini-menu (Exit Option Only) LXI H,MINIMENU CALL DSPMSG ;5. Display 24 empty slots CALL SLOTS RET ;1234567890123456789012345678901234567890 LOGO: DB ' Search and Replace (c)1988 KCSI',0 MINIMENU: DB ' -- -- -- -- -- -- -- Exit',0 ;------ SLOTS: ;------ ;Display 24 Empty slot positions on the bar cursor ;style screen ;1. From 0 to 23 XRA A ;Starting from 0 SLOTS1: CPI 24 ;Stop when A passes 23 RZ ;2. Position to that slot MVI H,0 MOV L,A PUSH PSW ;Save slot count RST 6 ;Call Std ROM DW BARPOS ;to move to bar position ;3. And print the '-.-' empty entry LXI H,EMPTY ;and print an empty CALL DSPMSG ;4. Next Slot POP PSW ;Slot count INR A JMP SLOTS1 EMPTY: DB '-.-',0 ;------ DISPDO: ;------ ;Display .DO files at bar cursor positions. ;Entry HL points to memory holding up to 24 ; pointers to directory entries of .DO files ;1. Save pointer and Allocate 10 bytes for formatted name XCHG LXI H,-10 DAD SP SPHL XCHG ;2. For 0 to 23 entries MVI C,0 DISPDO1: MOV A,C CPI 24 JZ DISPDO2 ;3. Or until the pointer points to 0FFFFH MOV A,M INX H ANA M INR A JZ DISPDO2 ;4. Get the Directory Entry PUSH H ;Pointer to Pointers MOV A,M DCX H MOV L,M MOV H,A ;5. Step to the file name portion INX H INX H INX H ;6. Format The Name PUSH D ;Buffer PUSH B ;Slot Number XCHG RST 6 ;Call Std ROM DW MKPNAM ;to Format the name POP H ;Slot Number PUSH H ;7. Position the cursor RST 6 ;Call Std ROM DW BARPOS ;for bar position POP B ;Position POP H ;Pointer to Buffer PUSH H PUSH B ;8. Display the formatted name CALL DSPMSG ;Display The Name ;9. Square up and go again POP B ;Bar Position POP D ;Buffer Again POP H ;Pointer to Pointers INX H ;Adjusted INR C JMP DISPDO1 DISPDO2: ;10. Clean up the stack LXI H,10 DAD SP SPHL RET ;------ PICKDO: ;------ ;Allows bar cursor to be moved with left and right ;Arrows only ;Entry: HL Contains base of array of pointers to ; to directory entries ;Exit: HL Points to the Directory Entry the Bar Cursor ; Was Over. XCHG ;Pointer to DE ;1. Turn the cursor on at 0 LXI H,0 ;Starting from 0 PUSH D PICKDO1: CALL BARTOG JMP PICKDO3 ;This entry is used to ring the beeper if the ;Key stroke is an error. PICKDO2: PUSH H RST 6 ;Call Std ROM DW BEEP ;to BEEP POP H ;2. Get User Key stroke and dispatch accordingly PICKDO3: PUSH H CALL GETCH ;3. Carry set indicates a function Key ; If it is F8 (A=7) then bail out JNC PICKDO4 POP H CPI 7 JNZ PICKDO2 ;Beep and try again POP D ;Else clear the stack RET ;3. Left Arrow can move only if not at position zero. PICKDO4: CPI 29 ;Left Arrow JNZ PICKDO5 POP H MOV A,H ORA L JZ PICKDO2 ;Can't move CALL BARTOG ;else current position off DCX H JMP PICKDO1 ;4. Right Arrow can move if new pointer is valid ; If not valid, the cursor wraps to position 0 PICKDO5: CPI 28 ;Right Arrow JNZ PICKDO7 POP H ;Can always move CALL BARTOG ;SO toggle off POP D ;Now Where do we go INX H ;Up one PUSH H DAD H ;Double it DAD D ;Offset into table MOV A,M ;If not FFFFH INX H ;Then Move is legal ANA M INR A POP H JNZ PICKDO6 ;Legal LXI H,0 ;Not legal, wrap to zero PICKDO6: PUSH D ;Restore the pointer JMP PICKDO1 ;5. Last chance is for an ENTER key. If it is enter ; Then return what is being pointed to. PICKDO7: CPI 13 POP H JNZ PICKDO2 ;Invalid Key POP D DAD H ;Position times 2 DAD D ;Plus Table base MOV A,M ;and load the value INX H MOV H,M MOV L,A RET ;------ BARTOG: ;------ ;Toggles the bar cursor at the position specified in HL ;Hl is preserved and restored. PUSH H RST 6 ;Call Std ROM DW BARCUR ;to toggle BAR POP H RET ;------ GETCH: ;------ ;Poll the keyboard until a key is hit. ;Return the value in A register. ;C set if its a function key and A will = ;0=F1, 1=F2 ... 7=F8,8=LABEL,9=PRINT,10=SHIFT-PRINT,11=PASTE RST 6 ;Call Std ROM to DW KYREAD ;Poll the keyboard JZ GETCH ;Keep at it til something RET ;gotten ;------ DSPMSG: ;------ ;Display a NULL terminated message on the LCD ;Entry HL points to the message ;Exit HL points to the NULL at the end of the message ;1. Until the Character is null MOV A,M ;Get char ORA A RZ ;Return if NULL ;2. Send it to the screen PUSH H ;Save pointer RST 6 ;Call Std ROM to DW CHROUT ;Display it POP H ;Restore Pointer ;3. Point to the next character INX H ;Next char JMP DSPMSG ;------ ROW8 ;------ ;Position Cursor to Column 1, Row 8 LXI H,(256*1)+8 ;Col 1 Row 8 RST 6 ;Call Std ROM DW CURPOS ;to position cursor RET ;------------------------------------------------------ ;Search and Replace Routine. ;------------------------------------------------------ ;------ SR: ;------ ;Ask User for Search and Replace strings and execute. ;Entry: HL Points to a directory Entry for a TEXT ;File to be processed. ;1. Retrieve the start pointer from the directory ; and save it INX H LXI D,LOC MOV A,M STAX D INX H INX D MOV A,M STAX D ;2. Allocate two 21 byte buffers on the stack to hold ; The search and Replace Strings and save pointers LXI H,-42 DAD SP SPHL SHLD SEARCH LXI D,21 DAD D SHLD REPLACE ;3. At ROw 8 Ask user for a search string and erase ; the rest of Row 8 CALL ROW8 LXI H,SPROMPT CALL DSPMSG RST 6 ;Call Std ROM DW ERAEOL ;To clear to EOL ;4. Point to the search buffer and allow the user to ; enter up to 20 bytes LXI D,20 LHLD SEARCH CALL GETSTR ;5. The GETSTR routine returns the length of the ; entered string in HL so save it SHLD SEARCHLEN ;6. If the length is 0 (no search string) then ; exit MOV A,L ORA H JZ SR1 ;7. At Row 8 ask the user for a replace string ; and erase to end of line. CALL ROW8 LXI H,RPROMPT CALL DSPMSG RST 6 ;Call Std ROM DW ERAEOL ;To clear to EOL ;8. Point to the replace buffer and allow 20 ; characters of replace text LXI D,20 LHLD REPLACE CALL GETSTR ;9. Save the length SHLD REPLACELEN ;10. And do the search and replace CALL SANDRPL ;11. Square up stack for the exit. SR1: LXI H,42 DAD SP SPHL RET SPROMPT: DB 'Search for :',0 RPROMPT: DB 'Replace with :',0 ;------ SANDRPL: ;------ ;1. Retrieve start of the file. LHLD LOC ;2. If it is CTRLZ then we're all done. MOV A,M CPI 26 JZ SANDRPL1 ;3. Load file into HL and search string to DE XCHG LHLD SEARCH XCHG ;4. And look for it CALL CMPSTR ;5. Replace it there's a match CZ RPL ;6. Step forward one in the file and try again LHLD LOC INX H SHLD LOC JMP SANDRPL ;7. On exit reorganize the directory before returning. SANDRPL1: RST 6 ;Call Std ROM DW DIROK ;to re-organize RET ;------ RPL: ;------ ;Replace routine. ;Entry: LOC = Where to replace. ;This routine could probably be improved since ;MASDEL and MAKHOL supposedly preserve the HL ;Register. It wouldn't be necessary to keep ;reloading. ;1. Delete the length of the search string from the ; The file LHLD SEARCHLEN PUSH H POP B LHLD LOC RST 6 ;Call Std ROM DW MASDEL ;To Delete bytes ;2. Make a hole the length of the replace string LHLD REPLACELEN PUSH H POP B LHLD LOC RST 6 ;Call Std ROM DW MAKHOL ;to make the hole ;3. Copy the replacement string to the hole LHLD REPLACELEN PUSH H POP B LHLD LOC XCHG LHLD REPLACE CALL MEMCPY ;4. Increment the LOC pointer by Length - 1 ; So that we don't end up with recursive ; Replacement LHLD REPLACELEN XCHG LHLD LOC DAD D DCX H SHLD LOC RET ;------ GETSTR ;------ ;Allows entry of a string of the specified length (1-255) ;Entry: HL points to the receiving buffer ; DE contains the maximum length allowed ;Exit: HL contains actual length entered. PUSH H ;Buffer ;1. Get the pointer to the end of the string on ; the stack END = Start + Length and the start ; over that. PUSH H ;Buffer DAD D ;Limit or end of the buffer XTHL ;2. Turn on the cursor PUSH H RST 6 ;Call Std ROM DW CURSON ;to turn it on. POP D ;Buffer ;3. Save the Buffer PUSH D ;4. Get a character GETSTR1: CALL GETCH ;5. Ignore Function keys (Carry Set) Beep and go again JC GETSTR4 ;6. Carriage Return is the end of user input GETSTR2: CPI 13 JZ GETSTR6 ;7. A backspace can only be done if ; The current buffer pointer not = ; the start of the buffer CPI 8 JNZ GETSTR3 POP D ;Current pointer POP B ;Buffer end POP H ;Buffer Start PUSH H PUSH B PUSH D CALL CMPHLDE ;Compare HL and DE JZ GETSTR4 ;Ignore if HL=DE ;8. If Okay then decrement the current buffer ; pointer POP D DCX D PUSH D ;9. And display BS-SPACE-BS to clear the character ; on the screen and go again. LXI H,RUBOUT CALL DSPMSG JMP GETSTR1 ;10. Ignore all other control characters GETSTR3: CPI ' ' JC GETSTR4 ;11. And hex 7FH CPI 07FH JZ GETSTR4 ;12. So we have a valid ASCII character. Check if the ; The current pointer is at the end of the buffer. ; If it is then ignore the input. MOV C,A ;Save The Character POP D ;Current Pointer POP H ;End of Buffer PUSH H PUSH D CALL CMPHLDE ;Compare JZ GETSTR4 ;Ignore if equal ;13. The character is placed in the buffer and the ; Buffer is incremented. MOV A,C POP D STAX D INX D PUSH D ;14. Display the character and go again. RST 6 ;Call Std ROM DW CHROUT ;to Display it JMP GETSTR1 ; Jumping to this address causes a beep and ; a jump back to the top, used for invalid characters GETSTR4: RST 6 ;Call Std ROM DW BEEP ;to beep JMP GETSTR1 ;And jump to the top ;15. This is the exit when CR is pressed. First ; Turn the cursor off GETSTR6: RST 6 ;Call Std ROM DW CUROFF ;to turn it off ;16. Store a null at the current buffer pointer. POP H ;Buffer pointer XRA A MOV M,A ;17. Get the length in HL and exit POP D ;Limit or end of buffer POP D ;Start of Buffer MOV A,L SUB E MOV L,A MOV A,H SBB D MOV H,A RET RUBOUT: DB 8,' ',8,0 ;------ CMPHLDE ;------ ;Compare HL and DE ;Entry: HL and DE with value to compare ;Exit: Z flag set if HL=DE ; Carry Set if DE>HL MOV A,H CMP D RNZ MOV A,L CMP E RET ;------ CMPSTR: ;------ ;Compare strings pointed to by HL and DE ;Comparison stops when (DE)=0 success ;Or (DE)<>(HL) = nomatch ;Entry: DE points to null terminated string to search for ; HL points to where in the file to match ;Exit: NZ if the match fails or Z if successful ;1. Retrieve a character from the search string. ; If it is null, then the search is successful LDAX D ORA A RZ ;2. Otherwise compare and return for mismatch CMP M INX H INX D RNZ ;3. Go again JMP CMPSTR ;------ MEMCPY ;------ ;Copy (HL) to (DE) for BC bytes ;1. Exit when BC exhausted MOV A,C ORA B RZ ;2. Otherwise move it and increment MOV A,M STAX D INX H INX D DCX B JMP MEMCPY END