; WSF.AZM ; Gaspari's changes to Wordstar 4.0 10-15-87 ; Assemble with Z80MR. Overlay the hex file with DDT. ; This program provides function key processing for Wordstar. ; It will send a new BIOS into memory without ; using SYSGEN & DDT to place it permanently on disk. ; It injects USER15.AZM for Northstar Advantage, which is replacement ; lower BIOS that embeds function key processing as part of N* BIOS. ; The function key definitions are sent to the MORPAT area of WS. LDEST EQU 0F400H ; location of eventual destination ; *********************************************** ; PART I - LOAD REPLACEMENT BIOS ; *********************************************** ORG 0100H JP LOADUSER ; jmp to end of WS to run code below ; *********************************************** ; PART II - SET UP KEY DEFINITIONS ; *********************************************** ORG 046BH ; point to unused area in MORPAT KEYDATA: DEFB 0,0 ; 80h cmnd - DEFB 0,0 ; 81h cmnd . DEFB 05H,0 ; 82h up arrow DEFB 03H,0 ; 83h 3 arrow DEFB 1AH,0 ; 84h 1 arrow DEFB 11H,0 ; 85h 5 arrow (center) DEFB 04H,0 ; 86h rt arrow DEFB 17H,0 ; 87h 7 arrow DEFB 13H,0 ; 88h lf arrow DEFB 12H,0 ; 89h 9 arrow DEFB 18H,0 ; 8Ah dn arrow DEFB 0,0 ; 8Bh undefined DEFB 0,0 ; 8Ch cntl , DEFB 0,0 ; 8Dh SHFT ENTER DEFB 0,0 ; 8Eh cntl . DEFB 0,0 ; 8Fh cntl - DEFB 0,0 ; 90h cntl 0 DEFB 0,0 ; 91h cntl 1 arrow DEFB 0,0 ; 92h cntl 2 arrow DEFB 0,0 ; 93h cntl 3 arrow DEFB 01H,0 ; 94h cntl 4 arrow DEFB 11H,0 ; 95h cntl 5 arrow DEFB 06H,0 ; 96h cntl 6 arrow DEFB 0,0 ; 97h cntl 7 arrow DEFB 0,0 ; 98h cntl 8 arrow Š DEFB 0,0 ; 99h cntl 9 arrow ; DEFB 0,0 ; 9Ah cntl ENTER ; DEFB 0AH,09H ; 9Bh cmnd F1 ; DEFB 0AH,13H ; 9Ch cmnd F2 ; DEFB 0AH,06H ; 9Dh cmnd F3 ; DEFB 0AH,08H ; 9Eh cmnd F4 ; DEFB 0AH,02H ; 9Fh cmnd F5 ; DEFB 0AH,0DH ; A0h cmnd F6 KFNTBL: DEFB 0BH,04H ; F1 DEFB 0BH,13H ; F2 DEFB 10H,13H ; F3 DEFB 10H,02H ; F4 DEFB 15H,00H ; F5 DEFB 0FH,09H ; F6 DEFB 0FH,03H ; F7 DEFB 10H,0CH ; F8 DEFB 0BH,02H ; F9 DEFB 0BH,0BH ; F10 DEFB 0CH,00H ; F11 DEFB 10H,16H ; F12 DEFB 10H,14H ; F13 DEFB 16H,00H ; F14 DEFB 07H,00H ; F15 DEFB 0BH,11H ; SH-F1 DEFB 0BH,13H ; DEFB 0FH,0AH ; DEFB 0AH,00H ; DEFB 02H,00H ; DEFB 0FH,0EH ; DEFB 0FH,07H ; DEFB 0FH,00H ; DEFB 0BH,16H ; DEFB 0BH,03H ; DEFB 11H,06H ; DEFB 0FH,13H ; DEFB 0FH,04H ; DEFB 0EH,00H ; DEFB 19H,00H ; SH-F15 KTBLSZ EQU $-KEYDATA ; the size of this replacement table KREF EQU $ ; last addr must be below 04DBh ; *********************************************** ; PART III - LOAD NEW BIOS ; *********************************************** LCURR EQU 02000H ; start of code to be moved ORG 1D00H ; at end of normal WS 4.0 LOADUSER: ; load the new USER.ASM Š LD DE,LDEST ; spot in BIOS to put revised code LD HL,LCURR ; point to data we'll put there LD BC,CSIZE ; size of code block to be moved LDIR ; LOADKEYDATA: ; installed via ORG 046Bh JP 1A1Fh ; return back to WORDSTAR ; *********************************************** ; PART IV - THE NEW BIOS CODE ; *********************************************** ; LOADUSER.AZM Version C2 10-15-87 ; A replacement USER.ASM for N* Adv by R. Gaspari, Los Angeles, 10-15-87. ; Puts function key processing in N* bios. See NS-USER.DOC for more info. ORG LCURR ; O EQU LDEST-LCURR ; offset ; ; JUMP VECTOR (SEMI-TRADITIONAL) ; USERORG EQU $+O ; ORIGIN FOR REFERENCE JP INIT ; INITIALIZATION CODE JP CONST ; CONSOLE READY TEST JP CONIN ; CONSOLE INPUT JP CONOUT ; CONSOLE OUTPUT JP LIST ; LIST DEVICE JP LIST ; PUNCH ## (deleted to make room) JP LIST ; READER (deleted to make room) JP LISTST ; LIST DEVICE READINESS TEST ; ; CONCLUDE VECTOR WITH BAUD RATES ; THE PRINTER RATE (BAUDA) IS ALTERED BY CPMGEN BAUDA EQU $+O ; Start-up baud rate for Adv slot 1 DEFB 112 ; 112 = 1200 baud BAUDB EQU $+O ; Start-up baud rate for slot 2 DEFB 126 ; 126 = 9600 baud BAUDC EQU $+O ; Startup for slot 3 DEFB 120 ; 127=19200; 124=4800; 120=2400; 96=600 ; ; ********** END OF VECTOR *********************** ENDVECT EQU $ ; MARK FOR LATER ORIGIN ; ; ; ***** ENTRY POINTS INTO "UPPER" BIOS *********************** ; ; ORG USERORG+200H ; JUST BEYOND USER AREA ; ACTUAL CONSOLE ROUTINES ARE ENTERED ABOVE USER AREA CONSLI EQU USERORG+200H ; ACTUAL KEYBOARD INPUT ROUTINE CONSLO EQU USERORG+200H+3 ; ACTUAL KEYBOARD OUTPUT ROUTINE ; ; MACHINE REGISTERS MAP0,MAP1,MAP2,CONTROL,TOP-SCAN-LINE ; ARE MANAGED THROUGH THE ROUTINES BELOW: ; ENTER WITH REG C=REG# 0 TO 4 RESPECTIVELY Š; VALUE RETURNED/SUPPLIED IN REG B RDREG EQU USERORG+200H+6 ; READ MACHINE REGISTER WRREG EQU USERORG+200H+9 ; WRITE MACHINE REGISTER ; ; MUST SERVICE OFTEN WHILE HUNG IN I/O WAIT LOOPS: OFTENS EQU USERORG+200H+12 ; CALL TO SERVICE OFTEN ; ROUTINE TOGGLES SPEAKER CONE SPTOG EQU USERORG+200H+15 ; TOGGLE SPEAKER ; ***************************************************** ; ; ; ; ************ BOARDLET I/O PORT DEFINITIONS *********** ; ; THE CP/M LIST DEVICE IS DEFINED AS PORT "A" ; IT IS HERE ASSIGNED TO BOARDLET 1 PORTAB EQU 1 ; BOARDLET 1 PORTA EQU (6-PORTAB)*16 ; BEGINNING OF BLOCK PORTAT EQU 76H-PORTAB ; INTERROGATE FOR TYPE ; ; THIS INITIALIZES ADVANTAGE SLOT 2 PORTBB EQU 2 ; BOARDLET 2 PORTB EQU (6-PORTBB)*16 ; BEGINNING OF BLOCK PORTBT EQU 76H-PORTBB ; SERIAL OR PARALLEL? ; ; THIS INITIALIZES ADVANTAGE SLOT 3 PORTCB EQU 3 ; BOARDLET 3 PORTC EQU (6-PORTCB)*16 ; FIRST PORT IN BOARDLET PORTCT EQU 76H-PORTCB ; DETERMINES BOARLET TYPE ; ; ; WHEN THE PORT TYPE IS INTERROGATED, VALUES INPUT ARE: BLTSER EQU 0F7H ; BOARDLET IS SERIAL BLTPAR EQU 0DBH ; BOARDLET IS PARALLEL ; ******************************************************* ; ORG ENDVECT ; RESUME AT ABOVE MARKED LOCATION ; ; ; ; *** CONSOLE STATUS TEST FOR DATA READY CONST EQU $+O LD A,(KEYINF) OR A JR NZ,CONS2 ; return non-zero if data is waiting CALL 0F60Ch ; SERVICE OFTEN FOR SCROLL, ETC. IN A,(0D0H) ; INTERROGATE KEYBOARD STATUS AND 040H ; TEST KEYBOARD READY BIT RET Z ; NO DATA, RETURN WITH A=0 CONS2 EQU $+O LD A,0FFH ; DATA WAITING, SEND FF RET ; ; Š; *** CONSOLE INPUT ## Complete overhaul of CONIN routine. ## CONIN EQU $+O LD HL,KEYINF ; get the counter of keys waiting LD A,(HL) OR A JR NZ,KEYWAT ; go process the keys waiting CONIN2 EQU $+O CALL CONST ; no keys waiting, so proceed with normal CONIN JR Z,CONIN2 ; loop until status says we're ready CALL 0F600H ; get the byte using upper bios CP 7FH ; see if it's a "delete" RET C ; if less than 7F, return with it JR NZ,KEYFNI ; if greater than 7F, prep for function key LD A,(KEYDEL) ; if equal to 7F, replace with a ^H RET ; KEYFNI EQU $+O LD B,A ; store the function key LD A,(KEYLEN) ; get the length of replacement byte string OR A ; see if zero LD A,B ; get the function key back RET Z ; if len=0, don't process function keys KEYFN EQU $+O CP 0DBH ; now see if its F1 - F15 or if its cursor JR NC,KEY2 ; if no carry, its greater (F1 - F15) SBC A,7FH ; subtract to point to offset in our table LD HL,(KEYNMP© ; get address of the cursor replacements JR KEYX ; go to the exchange routine KEY2 EQU $+O SBC A,0DBH ; subtract to get the offset for our table LD HL,(KEYFNP) ; get address of the fn key replacements KEYX EQU $+O LD C,A ; store offset temporarily in C LD A,(KEYLEN) ; get the length of each replacement string DEC A ; LD (KEYINF),A ; store the number of remaining bytes LD D,A ; put the number of times to add A to itself in B LD A,C ; get the offset back from C KEYX2 EQU $+O ADD A,c ; by adding N times, adjust offset for # of bytes DEC D ; JR NZ,KEYX2 ; repeat till D=0 LD E,A ; put the offset in DE to prepare for "DAD D" LD D,0 ; ditto ADD HL,DE ; HL now points to the replacement bytes LD D,(HL) ; get first replacement byte INC HL ; point to next byte LD (KEYPTR),HL ; store pointer to the next byte LD A,(HL) ; get next byte OR A JR NZ,KNXTZ ; if next byte NZ skip, otherwise... LD (KEYINF),A ; notify keyinf that there's no more KNXTZ EQU $+O LD A,D ; get the replacement key back OR A ; check that it's not a null RET NZ ; if no null, return with it Š LD (KEYINF),A ; otherwise notify keyinf that no more RET ; return with function key replacement KEYWAT EQU $+O DEC A ; decrement count of keys waiting LD (HL),A ; store for future use LD HL,(KEYPTR) ; get address of next byte waiting LD A,(HL) ; get the byte there INC HL ; update the pointer to the next byte LD (KEYPTR),HL ; and store it RET ; return with the byte that was waiting KEYPTR EQU $+O DEFW 0 ; pointer to the next replacement byte KEYINF EQU $+O DEFB 0 ; temp storage for number of keys waiting ; ; *** CONSOLE OUTPUT CONOUT EQU $+O JP 0F603H ; SO SEND CHAR TO CONSOLE ; ; ; ***** BOARDLET I/O HANDLING ************************** ; ***** CP/M'S "LIST" DEVICE - USES "PORTA" DEFINED ABOVE ; LIST EQU $+O CALL LISTST ; USE STATUS TEST BELOW JR Z,LIST ; LOOP UNTIL READY IN A,(PORTAT) ; DETERMINE TYPE OF PORT CP BLTSER ; SEE IF SERIAL JR Z,LISTSER ; YES, SKIP INSTRUCTION BELOW OUT (PORTA+4),A ; RESET PO-FLAG LISTSER EQU $+O LD A,C ; STAGE BYTE INTO A OUT (PORTA),A ; SEND IT RET ; AND EXIT ; ; *** LIST DEVICE STATUS TEST *** USES PORTA LISTST EQU $+O CALL OFTENS ; SERVICE OFTEN FOR SCROLL LD B,1 ; READY BIT FOR SERIAL PORT IN A,(PORTAT) ; DETERMINE TYPE OF PORT A CP BLTSER ; SEE IF SERIAL JR Z,LTTSER ; YES SKIP NEXT INSTR LD B,4 ; PARALLEL PORT READY MASK LTTSER EQU $+O IN A,(PORTA+1) ; INTERROGATE CONTROL PORT AND B ; VS. READY MASK RET Z ; DONE, Z=NOT READY OR 0FFH ; READY, MAKE ALL ONES RET ; ; ; Š;***** CP/M'S "READER" DEVICE - Code deleted to make room ; ;READER ; ;***** CP/M "PUNCH" DEVICE - Code deleted to make room ; ;PUNCH ; ; ; ****** INITIALIZATION ROUTINE ******************* ; INIT EQU $+O ; INITIALIZATION ; TRADITIONALLY, NORTHSTAR CP/M'S DONT FUTZ WITH THE IOBYTE XOR A ; INITIALIZE BYTE 3 & 4 LD (3),A ; SET THE "IOBYTE" TO "STANDARD" LD (4),A ; SET CURRENT DISK TO A: & USER=0 ; ; INITIALIZE "BOARDLET"S FOR SERIAL OR PARALLEL I/O ; START WITH PORT A - NORMALLY THE PRINTER LD A,(BAUDA) ; STAGE BAUD RATE IN CASE SERIAL LD D,A ; IN D REGISTER IN A,(PORTAT) ; TEST PORT A TYPE LD HL,INITAS ; SERIAL INIT STRING LD BC,5*256+PORTA+1 ; B=5 COUNT, C=UART CMD PORT CALL INITCOM ; USE COMMON ROUTINE IN A,(PORTA) ; CLEAR ANY JUNK JR NZ,INITB0 ; DONE IF NOT PARALLEL OUT (PORTA+5),A ; SET PO-FLAG FOR PARALLEL PORT ; ; INITIALIZE ADV SLOT 2 INITB0 EQU $+O LD A,(BAUDB) ; STAGE BAUD RATE IN CASE SERIAL LD D,A ; IN D REGISTER IN A,(PORTBT) ; GET BOARD TYPE LD HL,INITBS ; SERIAL INIT STRING LD BC,5*256+PORTB+1 ; B=5 COUNT, C=UART CMD PORT CALL INITCOM IN A,(PORTB) ; CLEAR ANY JUNK JR NZ,INITC0 ; DONE IF NOT PARALLEL OUT (PORTB+6),A ; RESET PI-FLAG ; INITIALIZE ADV SLOT 3 INITC0 EQU $+O LD A,(BAUDC) ; STAGE BAUD RATE IN CASE SERIAL LD D,A ; IN D REGISTER IN A,(PORTCT) ; GET PORT C TYPE LD HL,INITCS ; SERIAL INIT STRING LD BC,5*256+PORTC+1 ; B=5 COUNT, C=UART CMD PORT CALL INITCOM IN A,(PORTC) ; CLEAR ANY JUNK JR NZ,INITC9 ; DONE IF NOT PARALLEL OUT (PORTC+5),A ; INIT PO-FLAG ON AS IF JUST ACK'ED INITC9 EQU $+0 ; END OF BOARDLET INITIALIZATION ; Š RET ; END OF INITIALIZATION ; COMMON SUBROUTINE TO TEST BOARDLET TYPE ## Patch to known board type ## ; IF SERIAL, OUTPUT INITIALIZATION STRING ; REGS MUST BE: A=BOARDLET-TYPE, B=INITSTRING-LENGTH, C=COMMAND PORT ; D=BAUD-RATE-FACTOR, HL@INITSTRING INITCOM EQU $+O CP BLTSER ; SEE IF SERIAL PORT JR NZ,INITCP ; NOT SERIAL, GO TEST IF PARALLEL DEFB 0EDH,0B3H ; Z80 OTIR INSTRUCTION, SENDS INIT STRING LD A,C ; NOW CHANGE I/O PORT ADD A,7 ; FROM UART COMMAND TO BAUD RATE LD C,A ; C=BAUD RATE PORT DEFB 0EDH,51H ; Z80 OUT (C),D (BAUD RATE FROM D) RET ; EXIT (NOTE Z FLAG IS OFF) INITCP EQU $+O CP BLTPAR ; SEE IF PARALLEL PORT RET ; SO Z ON IFF PARALLEL PORT ; INITIALIZATION STRINGS FOR 8251 USARTS ON SERIAL BOARDLETS INITAS EQU $+O INITBS EQU $+O INITCS EQU $+O DEFB 80H,80H ; FILLERS TO INSURE KNOWN STATE DEFB 40H ; INTERNAL RESET COMMAND DEFB 0CEH ; 2 STOPS, NO PARITY, 8 DATA BITS, 16X CLOCK DEFB 37H ; RTS, ER, RXE, DTR, TXE COMMAND ;INITBS: DEFB 80H,80H,40H,0CEH,37H ; SAME AS FOR A ;INITCS: DEFB 80H,80H,40H,0CEH,37H ; SAME AS FOR A KEYREF EQU $+O ; the stuff above should end BEFORE F515h DEFS 2 ; F514 starts an unused area in ; the existing floppy BIOS KEYDEL EQU $+O DEFB 8 ; at startup, delete = ^H KEYLEN EQU $+O DEFB 2 ; permanent storage for length of repl string KEYFNP EQU $+O DEFW KFNTBL KEYNMÐ EQÕ $+O DEF× KEYDATA CSIZE EQU $-LCURR ; the size of this code segment END ; end WSF.AZM 10-15-87