Title Talk to an Md3 through the Aux Port (14_Aug_84) ; ; Copyright 1984 ; Morrow Designs, Inc. ; San Leandro Ca. ; .z80 Aseg org 0100h page 60 ;---------------------------------------------------------------------- ; Equates (14_Aug_84) ;-------------------- ; Rev equ 10h ;Revision Number ;Bdos Functions Bdos_Entry equ 5 ;Entry Point into the Bdos Bdos_PString equ 9 ;Bdos Print String Function Bdos_ConIn equ 1 ;Bdos Console Input ;Error Message Codes Err_OverFlow1 equ 10 ;Que 1 Has OverFlowed Err_OverFlow2 equ 11 ;Que 2 Has OverFlowed ;Normal Message Codes Title_Block equ 20 ;Title Block Device1_Select equ 21 ;Device 1 Selection Message Device2_Select equ 22 ;Device 2 Selection Message Device1_Baud equ 23 ;Device 1 Baud Rate Selection Message Device2_Baud equ 24 ;Device 2 Baud Rate Selection Message Baud_Table equ 25 ;Baud Rate Selection Table Device_Table equ 26 ;Device Selection Table Startup equ 27 ;Start Up Message ;I/O Port Addresses s1data equ 60h ;serial port 1 data (dart1 = con port) s1stat equ 61h ;serial port 1 status s2data equ 62h ;serial port 2 data (dart2 = prn port) s2stat equ 63h ;serial port 2 status s3data equ 70h ;serial port 3 data (sio) s3stat equ 71h ;serial port 3 status (sio) ;Uart Flags $TxRdy equ 00000100b ;Uart Transmitter Ready Bit $RcvRdy equ 00000001b ;Uart Reciever Ready Bit ;Non Printing Ascii Character Equates Tab equ 09h ;Tab Lf equ 0Ah ;Line Feed Cr equ 0Dh ;Carriage Return Esc equ 1Bh ;Escape Character ;Limits Max_Escapes equ 2 ;(Serves as a print code as well) Max_Assgn equ 3 ;Number of Device Assignment Selections Max_Baud equ 10 ;Number of Baud Rate Selections ;Extended Bios Function Numbers E_Get_Chr_Tbl equ 6 ;Get the Character Table E_Write_Sys equ 1 ;Write to system memory E_Set_Baud equ 19 ;Set the Baud Rates page ;---------------------------------------------------------------------- ; Main Line (13_Aug_84) ;---------------------- ; Main_Line: call Get_Parameters ;Get the Initial Parameters call Initialize_Baud ;Set the Port's Baud Rate call Setup_Pointers ;Set the Vector Tables ld a,StartUp call Print_Message ;Print the StartUp Message MlLp1: call Dev1_to_Que1 ;Loop Dev_Que1:= Device1 or a ; If (Error or Return) jr nz,MlDone ; Break call Que1_to_Dev2 ; Device2:= Dev_Que1 call Dev2_to_Que2 ; Dev_Que2:= Device2 or a ; If (Error or Return) jr nz,MlDone ; Break call Que2_to_Dev1 ; Device1:= Dev_Que2 jr MlLp1 MlDone: call Print_Message ;Print the Closing Message jp 0 ;Warm Boot page ;====================================================================== ; Get the Initial Parameters (14_Aug_84) ;======================================= ; Get_Parameters: ld a,Title_Block ;Title Block call Print_Message ld a,Device_Table ;Device Selection Table call Print_Message ld a,Device1_Select ;Device 1 Selection Message call Print_Message ld b,Max_Assgn ;B:= Device Number Limit for Assignment call Get_Response ld (Dev1_Id),a ;Install Device Assignment for Device 1 ld a,Device2_Select ;Device 2 Selection Message call Print_Message ld b,Max_Assgn ;B:= Device Number Limit for Assignment call Get_Response ld (Dev2_Id),a ;Install Device Assignment for Device 2 ld a,(Dev1_Id) ;If (Device 1 ne Console) or a jr z,MlSk1 ld a,Baud_Table ; Print Baud Rate Selection Table call Print_Message ld a,Device1_Baud ; Print Dev 1's Baud Rate Message call Print_Message ld b,Max_Baud ; B:= Max Number of Response call Get_Response ; Get the User's Response ld (Dev1_Baud_Rate),a ; Update the Baud Rate Value ld a,0FFh MlSk1: ld b,a ;B:= Flag (Not Zero means Table Printed) ld a,(Dev2_Id) ;If (Device 2 ne Console0 or a jr z,MlSk3 ld a,b or a ; If (Table hasn't been Printed) jr nz,MlSk2 ld a,Baud_Table ; Print Baud Select Table call Print_Message MlSk2: ld a,Device2_Baud ; Print Dev 2's Baud Rate Message call Print_Message ld b,Max_Baud ; B:= Max Number of Response call Get_Response ; Get the User's Response ld (Dev2_Baud_Rate),a ; Update the Baud Rate Value MlSk3: ret ;Return page ;---------------------------------------------------------------------- ; Get the Response From the User (14_Aug_84) ;------------------------------------------- ; Get_Response: ld c,Bdos_ConIn ;C:= Console Input Function GrLp1: push bc ;Repeat call Bdos_Entry ; Get Character from Console pop bc and 01111111b ; Mask off the parity sub '0' ; Adjust Response to 0 base cp b jr nc,GrLp1 ;Until (Response is in Range) ret page ;====================================================================== ; Initialize the Baud Rates (14_Aug_84) ;====================================== ; Initialize_Baud: ld a,E_Get_Chr_Tbl ;A:= Read Character Table Function ld de,Dev_Que1 ;DE:= Pointer to Local Buffer call Extended_Bios ;Read the Character Table push hl push de ld a,(Dev1_Id) ;If (Device 1 is NOT the Console) or a jr z,IaSk1 ld e,a ld d,0 ; DE:= Offset ld hl,Dev_Que1 add hl,de ; HL:= Pointer to Dev_1's Baud ld a,(Dev1_Baud_Rate) ld (hl),a ; Install Device 1's Baud Rate IaSk1: ld a,(Dev2_Id) ;If (Device 1 is the Console) or a jr z,IaSk2 ld e,a ld d,0 ; DE:= Offset ld hl,Dev_Que1 add hl,de ; HL:= Pointer to Dev_2's Baud ld a,(Dev2_Baud_Rate) ld (hl),a ; Install Device 2's Baud Rate IaSk2: poš de pop hl ld a,E_Write_Sys ;A:= Write to System Memory Function ex de,hl ;Swap source and destination call Extended_Bios ;Restore the Character Table ld a,E_Set_Baud ;A:= Set Baud Rate Function call Extended_Bios ;Set the Baud Rates ret ;Return page ;---------------------------------------------------------------------- ; Call the Bios Cold Boot Entry Point (10_Aug_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). ; Extended_Bios: 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 ;====================================================================== ; Initialize the Pointer Blocks (14_Aug_84) ;=========================================== ; 1) This routine installs the vectors for Input/Output Data/Status for ; both devices 1 and 2. ; Setup_Pointers: ld a,(Dev1_Id) call Get_Vector ;HL:= Base of Device's Vectors ld de,Dev1_In_Stat ;DE:= Start of Device 1's Vector Table ld bc,8 ;BC:= Length of Vector Table ldir ;Move the Vector Table into Place ld a,(Dev2_Id) call Get_Vector ;HL:= Base of Device's Vectors ld de,Dev2_In_Stat ;DE:= Start of Device 2's Vector Table ld bc,8 ;BC:= Length of Vector Table ldir ;Move the Vector Table into Place ret ;Return ;---------------------------------------------------------------------- ; Set the HL Pointing to the Desired Vector Parameters (14_Aug_84) ;----------------------------------------------------------------- ; 1) This routine uses the Device Id (passed in the accm) to set ; the HL pair pointing to the start of its vector table. ; 2) Register Usage: ; A -> On Entry is the Device Id (0 to 2) ; DE -> Used in calculating offsets ; HL -> Returned pointing to the start of the Device's Vectors ; Get_Vector: sla a ;Id:= Id * 2 ld e,a ld d,0 ;DE:= Device Id * 2 ld hl,Dev_Lookup add hl,de ;HL:= Vector to Table ld e,(hl) inc hl ld d,(hl) ex de,hl ;HL:= Pointer to Devices Vectors ret ;Return page ;---------------------------------------------------------------------- ; Read a Byte from Device 1 and EnQue it (13_Aug_84) ;--------------------------------------------------- ; Dev1_to_Que1: ld hl,(Dev1_In_Stat) ;If (Device 1 Input ne ready) call Indirect_HL or a ret z ; Return ld hl,(Dev1_Input) call Indirect_HL ;Read the Character and 01111111b ;(mask off parity bit) ld b,a ld a,(Que1_In_Pntr) ;A:= Pointer to Device 1's Que ld c,a inc c ;C:= Next Que Position ld a,(Que1_Out_Pntr) ;Inc the Input Pointer cp c ;If (There's an OverRun) jr nz,D1qSk1 ld a,Err_OverFlow1 ; A:= Que 1 Overflow Error ret ; Return D1qSk1: ld a,c ld (Que1_In_Pntr),a ld hl,Dev_Que1 ;HL= Base of Que ld l,a ;HL:= Current Que Position ld (hl),b ;Enque the Character ld a,Esc ;If (Character ne Escape) cp b jr z,D1qSk2 ld a,0 ld (Esc1_Counter),a ; Reset the Escape Counter ret ; Return D1qSk2: ld a,(Esc1_Counter) ;Else inc a ld (Esc1_Counter),a ; Increment the Escape Count cp 2 ; If (Escape Count eq 2) ret z ; Return (Not 0) ld a,0 ; Else ret ; Return (0) page ;---------------------------------------------------------------------- ; Read a Byte from Dev_Que1 and Write it to Device 2 (13_Aug_84) ;--------------------------------------------------------------- ; Que1_to_Dev2: ld a,(Que1_Out_Pntr) ;HL:= Pointer to Input Pointer ld c,a ld a,(Que1_In_Pntr) cp c ;If (Input Pointer eq Output Pointer) ret z ; Return ld hl,(Dev2_Out_Stat) ;If (Device 2 eq Busy) call Indirect_HL or a ret z ; Return inc c ld a,c ld (Que1_Out_Pntr),a ;Update the Output Que Pointer ld hl,Dev_Que1 ;HL:= Pointer to Base of Que ld l,c ;HL:= Pointer to Current Element ld c,(hl) ld hl,(Dev2_Output) ;Output the Current Character call Indirect_HL ret ;Return page ;---------------------------------------------------------------------- ; Read a Byte from Device 2 and EnQue it (13_Aug_84) ;--------------------------------------------------- ; Dev2_to_Que2: ld hl,(Dev2_In_Stat) ;If (Device 2 Input ne ready) call Indirect_HL or a ret z ; Return ld hl,(Dev2_Input) call Indirect_HL ;Read the Character and 01111111b ;(mask off parity bit) ld b,a ld a,(Que2_In_Pntr) ;A:= Pointer to Device 2's Que ld c,a inc c ld a,(Que2_Out_Pntr) ;Inc the Input Pointer cp c jr nz,D2qSk1 ld a,Err_OverFlow2 ; Que 2 Overflow ret ; Return D2qSk1: ld a,c ld (Que2_In_Pntr),a ld hl,Dev_Que2 ;HL= Base of Que ld l,a ;HL:= Current Que Position ld (hl),b ;Enque the Character ld a,Esc ;If (Character ne Escape) cp b jr z,D2qSk2 ld a,0 ld (Esc2_Counter),a ; Reset the Escape Counter ret ; Return D2qSk2: ld a,(Esc2_Counter) ;Else inc a ld (Esc2_Counter),a ; Increment the Escape Count cp 2 ; If (Escape Count eq 2) ret z ; Return (Not 0) ld a,0 ; Else ret ;Return page ;---------------------------------------------------------------------- ; Read a Byte from Dev_Que2 and Write it to Device 1 (13_Aug_84) ;--------------------------------------------------------------- ; Que2_to_Dev1: ld a,(Que2_Out_Pntr) ;HL:= Pointer to Input Pointer ld c,a ld a,(Que2_In_Pntr) cp c ;If (Input Pointer eq Output Pointer) ret z ; Return ld hl,(Dev1_Out_Stat) ;If (Device 2 eq Busy) call Indirect_HL or a ret z ; Return inc c ld a,c ld (Que2_Out_Pntr),a ;Update the Output Que Pointer ld hl,Dev_Que2 ;HL:= Pointer to Base of Que ld l,c ;HL:= Pointer to Current Element ld c,(hl) ld hl,(Dev1_Output) ;Output the Current Character call Indirect_HL ret ;Return page ;---------------------------------------------------------------------- ; Execute Indirectly through the HL register pair (11_Aug_84) ;------------------------------------------------------------ ; Indirect_HL: jp (hl) page ;---------------------------------------------------------------------- ; Serial Port 1 - (Default Console Device) Drivers (11_Jul_84) ;------------------------------------------------------------ ; Ser1_Input_Status: in a,(S1Stat) and $RcvRdy ;If (Reciever Status ne Ready) ret z ; Return 0 ld a,0FFh ;Else ret ; Return 0FFh Ser1_Input: call Ser1_Input_Status ;Repeat jr z,Ser1_Input ;Until (Input Port is Active) in a,(S1Data) ;A:= Input Character ret Ser1_Output_Status: in a,(S1Stat) and $TxRdy ;If (Transmitter Buffer ne Ready) ret z ; Return 0 ld a,0FFh ;Else ret ; Return 0FFh Ser1_Output: call Ser1_Output_Status ;Repeat jr z,Ser1_Output ;Until (Transmitter Buffer eq Ready) ld a,c ;(move character to output to Accm) out (s1data),a ;Output the Character ret ;Return page ;---------------------------------------------------------------------- ; Serial Port 2 - (Default List Device) Drivers (11_Jul_84) ;---------------------------------------------------------- ; Ser2_Input_Status: in a,(S2Stat) and $RcvRdy ;If (Reciever Buffer ne Ready) ret z ; Return 0 ld a,0FFh ;Else ret ; Return 0FFh Ser2_Input: call Ser2_Input_Status ;Repeat jr z,Ser2_Input ;Until (Reciever Buffer eq Ready) in a,(S2Data) ;A:= Input Character ret ;Return Ser2_Output_Status: in a,(S2Stat) and $TxRdy ;If (Transmitter Buffer ne Ready) ret z ; Return 0 ld a,0FFh ;Else ret ; Return 0FFh Ser2_Output: call Ser2_Output_Status ;Repeat jr z,Ser2_Output ;Until (Transmitter Buffer eq Ready) ld a,c ;(move character to output into Accm) out (S2Data),a ;Output the Character ret ;Return page ;---------------------------------------------------------------------- ; Serial Port 3 (Default Auxilary Device) Drivers (11_Jul_84) ;------------------------------------------------------------ ; Ser3_Input_Status: in a,(S3Stat) and $RcvRdy ;If (Reciever Buffer ne Ready) ret z ; Return 0 ld a,0FFh ;Else ret ; Return 0FFh Ser3_Input: call Ser3_Input_Status ;Repeat jr z,Ser3_Input ;Until (Reciever Buffer eq Ready) in a,(s3data) ;A:= Input Character ret ;Return Ser3_Output_Status: in a,(S3Stat) and $TxRdy ;If (Transmitter Buffer ne Ready) ret z ; Return 0 ld a,0FFh ;Else ret ; Return 0FFh Ser3_Output: call Ser3_Output_Status ;Repeat jr z,Ser3_Output ;Until (Transmitter Buffer eq Ready) ld a,c ;(move character to output into Accm) out (S3Data),a ;Output the Character ret ;Return page ;====================================================================== ; Print a Message on the Console (4_Jun_84) ;========================================== ; 1) This routine prints the message string, whose code is passed in the ; accm, on the console. ; 2) Register Usage: ; A -> Has Message Code on entry ; B -> Counter ; C -> Holds copy of Message Code ; DE -> Used to hold pointers/Bdos print string functions ; HL -> Used to hold pointers ; Print_Message: push af ld de,CrLf ;DE:= Pointer to Cr/Lf String ld c,Bdos_PString ;C:= Print String Function call Bdos_Entry ;Print Carriage Return Line Feed pop af ld c,a ;C:= Message Code to Find ld b,Max_Message ld hl,Message_Table ;HL:= Start of the Message Table PmLp1: ld a,(hl) ;Repeat A:= Table's Message 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,Pmprn ; Goto Print djnz PmLp1 ;Until (the whole tables been checked) ld de,NoCode ;(Pointer:= 'Unrecognized Message') PmPrn: ld c,Bdos_PString ; call Bdos_Entry ; Print the Message ret page ;---------------------------------------------------------------------- ; Data Area for Report Errors (14_Aug_84) ;---------------------------------------- ; Message_Table: db Title_Block ;Title Block dw TBmsg db Device1_Select ;Device 1 Selection Message dw D1msg db Device2_Select ;Device 2 Selection Message dw D2msg db Device1_Baud ;Device 1 Baud Rate Selection Message dw B1msg db Device2_Baud ;Device 2 Baud Rate Selection Message dw B2msg db Baud_Table ;Baud Rate Selection Table dw BSmsg db Device_Table ;Device Selection Table dw DSmsg db Err_OverFlow1 ;Que 1 Has OverFlowed dw O1err db Err_OverFlow2 ;Que 2 Has OverFlowed dw O2err db StartUp ;StartUP Message dw STmsg db Max_Escapes ;Blank Line dw CrLf End_Table: Max_Message equ ( (End_Table - Message_Table)/3 ) + 1 page ;---------------------------------------------------------------------- ; Message Strings (14_Aug_84) ;---------------------------- ; O1err: db 'Error -> Device 2 Has not Responded in Time $' O2err: db 'Error -> Device 1 Has not Responded in Time $' TBmsg: db 1Ah,'MD-HD Serial Port ReDirection Program Rev ' db ((rev and 0F0h) shr 4) + '0', '.', (rev and 0Fh) + '0' db Tab,Tab,Tab,' Copyright 1984' db cr,lf,'Morrow Designs Inc.' db Tab,Tab,Tab,Tab,Tab,Tab,'San Leandro, Ca' db Cr,Lf,'$' DSmsg: db Lf,'Device Assignment Selection:' db Cr,Lf db Cr,Lf,Tab,' 0 Console 1 List 2 Aux' db Cr,Lf,'$' D1msg: db Tab,'Select Device 1''s Assignment $' D2msg: db Tab,'Select Device 2''s Assignment $' BSmsg: db Cr,Lf,Lf,'Baud Rate Selection:' db Cr,Lf db Cr,Lf,Tab,' 0 110 3 1200 6 9600' db Cr,Lf,Tab,' 1 300 4 2400 7 19200' db Cr,Lf,Tab,' 2 600 5 4800' db Cr,Lf,'$' B1msg: db Tab,'Select Device 1''s Baud Rate $' B2msg: db Tab,'Select Device 2''s Baud Rate $' STmsg: db 1Ah,'Type Two Escapes to Exit',Cr,Lf,'$' NoCode: db 'Unrecognized Message $' CrLf: db Cr,Lf,'$' page ;---------------------------------------------------------------------- ; Data Area (14_Aug_84) ;---------------------- ; ; Initialization Data ;-------------------- ; ;Device Id's (0=Console, 1=List, 2=Aux) Dev1_Id: db 0 Dev2_Id: db 2 ;Baud Rate Settings Dev1_Baud_Rate: db 0 ;Baud Rate Setting For Device 1 Dev2_Baud_Rate: db 0 ;Baud Rate Setting For Device 2 ;Device Vector Lookup Table Dev_Lookup: dw Dev1_Tbl dw Dev2_Tbl dw Dev3_Tbl Dev1_Tbl: dw Ser1_Input_Status dw Ser1_Input dw Ser1_Output_Status dw Ser1_Output Dev2_Tbl: dw Ser2_Input_Status dw Ser2_Input dw Ser2_Output_Status dw Ser2_Output Dev3_Tbl: dw Ser3_Input_Status dw Ser3_Input dw Ser3_Output_Status dw Ser3_Output ; Run Time Variables ;------------------- ; ;Device 1 Vector Table (Default is Console) Dev1_In_Stat: dw Ser1_Input_Status ;Input Status Dev1_Input: dw Ser1_Input ;Input a Character Dev1_Out_Stat: dw Ser1_Output_Status ;Output Status Dev1_Output: dw Ser1_Output ;Output a Character ;Device 2 Vector Table (Default is Aux) Dev2_In_Stat: dw Ser3_Input_Status ;Input Status Dev2_Input: dw Ser3_Input ;Input a Character Dev2_Out_Stat: dw Ser3_Output_Status ;Output Status Dev2_Output: dw Ser3_Output ;Output a Character ;Escape Counters Esc1_Counter: db 0 ;Escape Counter for Device 1 Esc2_Counter: db 0 ;Escape Counter for Device 2 ;Que Pointers Que1_In_Pntr: db 0 ;Device 1 Input Que Position Que1_Out_Pntr: db 0 ; " 2 Output " " Que2_In_Pntr: db 0 ;Device 1 Input Que Pointer Que2_Out_Pntr: db 0 ; " 2 Output " " ; Local Data Storage ;------------------- ; ;Ques ds ( ($ and 0FF00h) + 100h) - $,0 Dev_Que1: ds 100h,55h Dev_Que2: ds 100h,55h end