; ;================================================================================================== ; ASCI DRIVER (Z180 SERIAL PORTS) ;================================================================================================== ; ; SETUP PARAMETER WORD: ; +-------+---+-------------------+ +---+---+-----------+---+-------+ ; | |RTS| ENCODED BAUD RATE | |DTR|XON| PARITY |STP| 8/7/6 | ; +-------+---+---+---------------+ ----+---+-----------+---+-------+ ; F E D C B A 9 8 7 6 5 4 3 2 1 0 ; -- MSB (D REGISTER) -- -- LSB (E REGISTER) -- ; ; STAT: ; 7 6 5 4 3 2 1 0 ; R O P F R C T T ; 0 0 0 0 0 0 0 0 DEFAULT VALUES ; | | | | | | | | ; | | | | | | | +-- TIE: TRANSMIT INTERRUPT ENABLE ; | | | | | | +---- TDRE: TRANSMIT DATA REGISTER EMPTY ; | | | | | +------ DCD0/CTS1E: CH0 CARRIER DETECT, CH1 CTS ENABLE ; | | | | +-------- RIE: RECEIVE INTERRUPT ENABLE ; | | | +---------- FE: FRAMING ERROR ; | | +------------ PE: PARITY ERROR ; | +-------------- OVRN: OVERRUN ERROR ; +---------------- RDRF: RECEIVE DATA REGISTER FULL ; ; CNTLA: ; 7 6 5 4 3 2 1 0 ; M R T R E M M M ; 0 1 1 0 0 1 0 0 DEFAULT VALUES ; | | | | | | | | ; | | | | | | | +-- MOD0: STOP BITS: 0=1 BIT, 1=2 BITS ; | | | | | | +---- MOD1: PARITY: 0=NONE, 1=ENABLED ; | | | | | +------ MOD2: DATA BITS: 0=7 BITS, 1=8 BITS ; | | | | +-------- MPBR/EFR: MULTIPROCESSOR BIT RECEIVE / ERROR FLAG RESET ; | | | +---------- RTS0/CKA1D: CH0 RTS, CH1 CLOCK DISABLE ; | | +------------ TE: TRANSMITTER ENABLE ; | +-------------- RE: RECEIVER ENABLE ; +---------------- MPE: MULTI-PROCESSOR MODE ENABLE ; ; CNTLB: ; 7 6 5 4 3 2 1 0 ; T M P R D S S S ; 0 0 X 0 X X X X DEFAULT VALUES ; | | | | | | | | ; | | | | | + + +-- SS: SOURCE/SPEED SELECT (R/W) ; | | | | +-------- DR: DIVIDE RATIO (R/W) ; | | | +---------- PEO: PARITY EVEN ODD (R/W) ; | | +------------ PS: ~CTS/PS: CLEAR TO SEND(R) / PRESCALE(W) ; | +-------------- MP: MULTIPROCESSOR MODE (R/W) ; +---------------- MPBT: MULTIPROCESSOR BIT TRANSMIT (R/W) ; ; ASEXT: ; 7 6 5 4 3 2 1 0 ; R D C X B F D S ; 0 1 1 0 0 1 1 0 DEFAULT VALUES ; | | | | | | | | ; | | | | | | | +-- SEND BREAK ; | | | | | | +---- BREAK DETECT (RO) ; | | | | | +------ BREAK FEATURE ENABLE ; | | | | +-------- BRG MODE ; | | | +---------- X1 BIT CLK ASCI ; | | +------------ CTS0 DISABLE ; | +-------------- DCD0 DISABLE ; +---------------- RDRF INT INHIBIT ; ASCI_PREINIT: ; ; SETUP THE DISPATCH TABLE ENTRIES ; LD B,2 ; ALWAYS 2 ASCI UNITS ON Z180 LD C,0 ; PHYSICAL UNIT INDEX ASCI_PREINIT1: PUSH BC ; SAVE LOOP CONTROL LD D,C ; PHYSICAL UNIT LD E,CIODEV_ASCI ; DEVICE TYPE LD BC,ASCI_DISPATCH ; BC := DISPATCH ADDRESS CALL CIO_ADDENT ; ADD ENTRY, BC IS NOT DESTROYED POP BC ; RESTORE LOOP CONTROL INC C ; NEXT PHYSICAL UNIT DJNZ ASCI_PREINIT1 ; LOOP UNTIL DONE ; LD DE,-1 ; DE := -1 TO INIT DEFAULT CONFIG CALL ASCI0_INITDEV ; INIT DEVICE ; LD DE,-1 ; DE := -1 TO INIT DEFAULT CONFIG CALL ASCI1_INITDEV ; INIT DEVICE ; XOR A ; SIGNAL SUCCESS RET ; ; ; ASCI_INIT: ; ; ASCI0 CALL NEWLINE ; FORMATTING PRTS("ASCI0: IO=0x$") ; PREFIX LD A,Z180_TDR0 ; LOAD TDR PORT ADDRESS CALL PRTHEXBYTE ; PRINT IT CALL PC_COMMA ; FORMATTING LD A,Z180_RDR0 ; LOAD RDR PORT ADDRESS CALL PRTHEXBYTE ; PRINT IT CALL PC_SPACE ; FORMATTING LD DE,(ASCI0_CONFIG) ; LOAD CONFIG CALL PS_PRTSC0 ; PRINT IT ; ; ASCI1 CALL NEWLINE ; FORMATTING PRTS("ASCI1: IO=0x$") ; PREFIX LD A,Z180_TDR1 ; LOAD TDR PORT ADDRESS CALL PRTHEXBYTE ; PRINT IT CALL PC_COMMA ; FORMATTING LD A,Z180_RDR1 ; LOAD RDR PORT ADDRESS CALL PRTHEXBYTE ; PRINT IT CALL PC_SPACE ; FORMATTING LD DE,(ASCI1_CONFIG) ; LOAD CONFIG CALL PS_PRTSC0 ; PRINT IT ; XOR A RET ; ; DISPATCH TO SPECIFIC ASCI UNIT ; ASCI_DISPATCH: PUSH IY ; PUSH UNIT DATA WORD POP AF ; POP TO AF, A := DEVICE NUM OR A ; SET FLAGS JP Z,ASCI0 DEC A JP Z,ASCI1 CALL PANIC ; ; ASCI 0 FUNCTIONS ; ASCI0: LD A,B ; GET REQUESTED FUNCTION AND $0F ; ISOLATE SUB-FUNCTION JP Z,ASCI0_IN DEC A JP Z,ASCI0_OUT DEC A JP Z,ASCI0_IST DEC A JP Z,ASCI0_OST DEC A JP Z,ASCI0_INITDEV DEC A JP Z,ASCI0_QUERY DEC A JP Z,ASCI0_DEVICE CALL PANIC ; ASCI0_IN: CALL ASCI0_IST OR A JR Z,ASCI0_IN IN0 A,(Z180_RDR0) ; READ THE CHAR LD E,A RET ; ASCI0_IST: ; CHECK FOR ERROR FLAGS IN0 A,(Z180_STAT0) AND 70H ; PARITY, FRAMING, OR OVERRUN ERROR JR Z,ASCI0_IST1 ; ALL IS WELL, CHECK FOR DATA ; ; CLEAR ERROR(S) OR NOTHING FURTHER CAN BE RECEIVED!!! IN0 A,(Z180_CNTLA0) RES 3,A ; CLEAR EFR (ERROR FLAG RESET) OUT0 (Z180_CNTLA0),A ; ASCI0_IST1: ; CHECK FOR STAT0.RDRF (DATA READY) IN0 A,(Z180_STAT0) ; READ LINE STATUS REGISTER AND $80 ; TEST IF DATA IN RECEIVE BUFFER JP Z,CIO_IDLE ; DO IDLE PROCESSING AND RETURN XOR A INC A ; SIGNAL CHAR READY, A = 1 RET ; ASCI0_OUT: CALL ASCI0_OST OR A JR Z,ASCI0_OUT LD A,E OUT0 (Z180_TDR0),A RET ; ASCI0_OST: IN0 A,(Z180_STAT0) AND $02 JP Z,CIO_IDLE ; DO IDLE PROCESSING AND RETURN XOR A INC A ; SIGNAL BUFFER EMPTY, A = 1 RET ; ASCI0_INITDEV: ; TEST FOR -1 WHICH MEANS USE CURRENT CONFIG (JUST REINIT) LD A,D ; TEST DE FOR AND E ; ... VALUE OF -1 INC A ; ... SO Z SET IF -1 JR NZ,ASCI0_INITDEV1 ; IF NEW CONFIG (NOT -1), IMPLEMENT IT LD DE,(ASCI0_CONFIG) ; OTHERWISE, LOAD EXISTING CONFIG ; ASCI0_INITDEV1: ; DETERMINE APPROPRIATE CNTLB VALUE (BASED ON BAUDRATE & CPU SPEED) LD A,D ; BYTE W/ ENCODED BAUD RATE AND $1F ; ISOLATE BITS LD L,A ; MOVE TO L LD H,0 ; CLEAR MSB PUSH DE ; SAVE CONFIG CALL ASCI_CNTLB ; DERIVE CNTLB VALUE POP DE ; RESTORE CONFIG ;CALL TSTPT RET NZ ; ABORT ON ERROR LD (ASCI0_CONFIG),DE ; RECORD UPDATED CONFIG ; ; IMPLEMENT CONFIGURATION LD A,66H ; LOAD DEFAULT ASEXT VALUE OUT0 (Z180_ASEXT0),A ; SET IT LD A,64H ; LOAD DEFAULT CNTLA VALUE OUT0 (Z180_CNTLA0),A ; SET IT LD A,C ; LOAD CNTLB VALUE DETERMINED ABOVE OUT0 (Z180_CNTLB0),A ; SET IT ; XOR A ; SIGNAL SUCCESS RET ; DONE ; ASCI0_QUERY: LD DE,(ASCI0_CONFIG) XOR A RET ; ASCI0_DEVICE: LD D,CIODEV_ASCI ; D := DEVICE TYPE LD E,0 ; E := PHYSICAL UNIT XOR A ; SIGNAL SUCCESS RET ; ; ASCI 1 FUNCTIONS ; ASCI1: LD A,B ; GET REQUESTED FUNCTION AND $0F ; ISOLATE SUB-FUNCTION JR Z,ASCI1_IN DEC A JR Z,ASCI1_OUT DEC A JR Z,ASCI1_IST DEC A JR Z,ASCI1_OST DEC A JP Z,ASCI1_INITDEV DEC A JP Z,ASCI1_QUERY DEC A JP Z,ASCI1_DEVICE CALL PANIC ; ASCI1_IN: CALL ASCI1_IST OR A JR Z,ASCI1_IN IN0 A,(Z180_RDR1) ; READ THE CHAR LD E,A RET ; ASCI1_IST: ; CHECK FOR ERROR FLAGS IN0 A,(Z180_STAT1) AND 70H ; PARITY, FRAMING, OR OVERRUN ERROR JR Z,ASCI1_IST1 ; ALL IS WELL, CHECK FOR DATA ; ; CLEAR ERROR(S) OR NOTHING FURTHER CAN BE RECEIVED!!! IN0 A,(Z180_CNTLA1) RES 3,A ; CLEAR EFR (ERROR FLAG RESET) OUT0 (Z180_CNTLA1),A ; ASCI1_IST1: ; CHECK FOR STAT0.RDRF (DATA READY) IN0 A,(Z180_STAT1) ; READ LINE STATUS REGISTER AND $80 ; TEST IF DATA IN RECEIVE BUFFER JP Z,CIO_IDLE ; DO IDLE PROCESSING AND RETURN XOR A INC A ; SIGNAL CHAR READY, A = 1 RET ; ASCI1_OUT: CALL ASCI1_OST OR A JR Z,ASCI1_OUT LD A,E OUT0 (Z180_TDR1),A RET ; ASCI1_OST: IN0 A,(Z180_STAT1) AND $02 JR Z,ASCI1_OST JP Z,CIO_IDLE ; DO IDLE PROCESSING AND RETURN XOR A INC A ; SIGNAL BUFFER EMPTY, A = 1 RET ; ASCI1_INITDEV: ; TEST FOR -1 WHICH MEANS USE CURRENT CONFIG (JUST REINIT) LD A,D ; TEST DE FOR AND E ; ... VALUE OF -1 INC A ; ... SO Z SET IF -1 JR NZ,ASCI1_INITDEV1 ; IF NEW CONFIG (NOT -1), IMPLEMENT IT LD DE,(ASCI1_CONFIG) ; OTHERWISE, LOAD EXISTING CONFIG ; ASCI1_INITDEV1: ; DETERMINE APPROPRIATE CNTLB VALUE (BASED ON BAUDRATE & CPU SPEED) LD A,D ; BYTE W/ ENCODED BAUD RATE AND $1F ; ISOLATE BITS LD L,A ; MOVE TO L LD H,0 ; CLEAR MSB PUSH DE ; SAVE CONFIG CALL ASCI_CNTLB ; DERIVE CNTLB VALUE POP DE ; RESTORE CONFIG ;CALL TSTPT RET NZ ; ABORT ON ERROR LD (ASCI1_CONFIG),DE ; RECORD UPDATED CONFIG ; ; IMPLEMENT CONFIGURATION LD A,66H ; LOAD DEFAULT ASEXT VALUE OUT0 (Z180_ASEXT1),A ; SET IT LD A,64H ; LOAD DEFAULT CNTLA VALUE OUT0 (Z180_CNTLA1),A ; SET IT LD A,C ; LOAD CNTLB VALUE DETERMINED ABOVE OUT0 (Z180_CNTLB1),A ; SET IT ; XOR A ; SIGNAL SUCCESS RET ; DONE ; ASCI1_QUERY: LD DE,(ASCI1_CONFIG) XOR A RET ; ASCI1_DEVICE: LD D,CIODEV_ASCI ; D := DEVICE TYPE LD E,1 ; E := PHYSICAL UNIT XOR A ; SIGNAL SUCCESS RET ; ; LOCAL DATA ; ASCI0_CONFIG .DW DEFSERCFG ; SAVED CONFIG FOR ASCI0 ASCI1_CONFIG .DW DEFSERCFG ; SAVED CONFIG FOR ASCI1 ; ; DERIVE A CNTLB VALUE BASED ON AN ENCODED BAUD RATE AND CURRENT CPU SPEED ; ENTRY: HL = ENCODED BAUD RATE ; EXIT: C = CNTLB VALUE, A=0/Z IFF SUCCESS ; ; DESIRED DIVISOR == CPUHZ / BAUD ; DUE TO ENCODING BAUD IS ALWAYS DIVISIBLE BY 75 ; Z180 DIVISOR IS ALWAYS A FACTOR OF 160 ; ; X = CPU_HZ / 160 / 75 ==> SIMPLIFIED ==> X = CPU_KHZ / 12 ; X = X / (BAUD / 75) ; IF X % 3 == 0, THEN (PS=1, X := X / 3) ELSE PS=0 ; IF X % 4 == 0, THEN (DR=1, X := X / 4) ELSE DR=0 ; SS := LOG2(X) ; ASCI_CNTLB: LD DE,1 ; USE DECODE CONSTANT OF 1 TO GET BAUD RATE ALREADY DIVIDED BY 75 CALL DECODE ; DECODE THE BAUDATE INTO DE:HL, DE IS DISCARDED ;CALL TSTPT RET NZ ; ABORT ON ERROR PUSH HL ; HL HAS (BAUD / 75), SAVE IT LD HL,(HCB + HCB_CPUKHZ) ; GET CPU CLK IN KHZ ;LD HL,CPUKHZ ; CPU CLK IN KHZ ;LD HL,9216 ; *DEBUG* ; DUE TO THE LIMITED DIVISORS POSSIBLE WITH CNTLB, YOU PRETTY MUCH ; NEED TO USE A CPU SPEED THAT IS A MULTIPLE OF 128KHZ. BELOW, WE ; ATTEMPT TO ROUND THE CPU SPEED DETECTED TO A MULTIPLE OF 128KHZ ; WITH ROUNDING. THIS JUST MAXIMIZES POSSIBILITY OF SUCCESS COMPUTING ; THE DIVISOR. LD DE,$0040 ; HALF OF 128 IS 64 ADD HL,DE ; ADD FOR ROUNDING LD A,L ; MOVE TO ACCUM AND $80 ; STRIP LOW ORDER 7 BITS LD L,A ; ... AND PUT IT BACK LD DE,12 ; PREPARE TO DIVIDE BY 12 CALL DIV16 ; BC := (CPU_KHZ / 12), REM IN HL, ZF ;CALL TSTPT POP DE ; RESTORE (BAUD / 75) RET NZ ; ABORT IF REMAINDER PUSH BC ; MOVE WORKING VALUE POP HL ; ... BACK TO HL CALL DIV16 ; BC := X / (BAUD / 75) ;CALL TSTPT RET NZ ; ABORT IF REMAINDER ; ; DETERMINE PS BIT BY ATTEMPTING DIVIDE BY 3 PUSH BC ; SAVE WORKING VALUE ON STACK PUSH BC ; MOVE WORKING VALUE POP HL ; ... TO HL LD DE,3 ; SETUP TO DIVIDE BY 3 CALL DIV16 ; BC := X / 3, REM IN HL, ZF ;CALL TSTPT POP HL ; HL := PRIOR WORKING VALUE LD E,0 ; INIT E := 0 AS WORKING CNTLB VALUE JR NZ,ASCI_CNTLB1 ; DID NOT WORK, LEAVE PS==0, SKIP AHEAD SET 5,E ; SET PS BIT PUSH BC ; MOVE NEW WORKING POP HL ; ... VALUE TO HL ; ASCI_CNTLB1: ;CALL TSTPT ; DETERMINE DR BIT BY ATTEMPTING DIVIDE BY 4 LD A,L ; LOAD LSB OF WORKING VALUE AND $03 ; ISOLATE LOW ORDER BITS JR NZ,ASCI_CNTLB2 ; NOT DIVISIBLE BY 4, SKIP AHEAD SET 3,E ; SET PS BIT SRL H ; DIVIDE HL BY 4 RR L ; ... SRL H ; ... RR L ; ... ; ASCI_CNTLB2: ;CALL TSTPT ; DETERMINE SS BITS BY RIGHT SHIFTING AND INCREMENTING LD B,7 ; LOOP COUNTER, MAX VALUE OF SS IS 7 LD C,E ; MOVE WORKING CNTLB VALUE TO C ASCI_CNTLB3: BIT 0,L ; CAN WE SHIFT AGAIN? JR NZ,ASCI_CNTLB4 ; NOPE, DONE SRL H ; IMPLEMENT THE RR L ; ... SHIFT OPERATION INC C ; INCREMENT SS BITS DJNZ ASCI_CNTLB3 ; LOOP IF MORE SHIFTING POSSIBLE ; ; AT THIS POINT HL MUST BE EQUAL TO 1 OR WE FAILED! DEC HL ; IF HL == 1, SHOULD BECOME ZERO LD A,H ; TEST HL OR L ; ... FOR ZERO RET NZ ; ABORT IF NOT ZERO ; ASCI_CNTLB4: ;CALL TSTPT XOR A RET ;