; B5AN-1.ASM - Apple // with PCPI Applicard and MTN CPS Serial Card
;
;               2651 with internal baudrate generator
;
; This insert version is for the Apple ][+ with the Mountain Computer
; CPS Serial Interface Card and PCPI Applicard. Additional routines
; are included to support the TIME routines in BYE5nn.
;
; Thanks to Norman Beeler for previous versions of this insert.
;
;-----------------------------------------------------------------------
;
; 12/23/85  Written for BYE5            - H. Middlebrook
;
;-----------------------------------------------------------------------
;
;                    BYE5xx Insert Information
;
; The following information regarding BYE5xx inserts is included for
; reference purposes and may be removed and saved in a separate file.
;
; HARDWARE (Serial I/O) --
;
; BYE5 program calls a number of hardware routines, listed below:
;
; MODEM Specific --
;
; If IMODEM is set true in BYE5nn, then MDINIT and MDQUIT routines
; should should call IMxxxx routines in BYE5xx core program.
;
; USEFUL BYE ROUTINES --
;
;       DELAY:    100 msec delay routine (uses BC and A registers)
;       KDELAY:   1 msec delay routine (uses BC and A registers)
;
; ROUTINES called from BYE core program code --
;
;       ** Routines may use A register but must preserve all others
;          (if used).  Flags must be set as indicated for status
;          routines.
;
; MDCARCK       Carrier check.
;               Flags:  Set Zero if No Carrier is present
;
; MDQUIT        Leaving BYE...reset modem.  Called when SYSOP types
;               Ctrl-C.  If IMODEM is TRUE then call IMQUIT and
;               fall through to MDSTOP; else just fall through to
;               MDSTOP.
;
; MDSTOP        Drop DTR permanently.
;               Disable DTR...MDINIT and SETnnnn will re-enable DTR.
;
; MDINIT        Initialize modem (serial I/O).
;               For CPS card, drop then raise DTR, set PSW = 8N1,
;               and set baud to current HSnnnn. If IMODEM is TRUE,
;               then CALL IMINIT after initializing CPS card.
;
; MDINP         Receive character from serial (modem) interface.
;               Regs:   A = Character received
;
; MDOUTP        Send character to serial (modem) interface.
;               Regs:   A = Character to send to modem
;
; MDOUTST       Output status of serial (modem) interface.
;               Flags:  Set Zero if I/O not ready for character
;
; MDINST        Input status of serial (modem) interface.
;               Flags:  Set Zero if I/O does not have character
;               Regs:   A = 00H if I/O does not have character
;               This routine requires that both A = 00H and zero
;               set if a character is not available.  Your routine
;               should clear zero and return with A = 0FFH if
;               character is available.
;
; MDCRDL        Carrier check with 2 second delay.  Returns with
;               carrier status ON or BEFORE about a 2 second delay.
;               This routine may be required for modems which are
;               slow in returning carrier status after ATA command.
;               Replace the following code in BYE502:
;
;       Was --          FINISH: CALL    MDCARCK
;
;       Now --          FINISH: CALL    MDCRDL
;
; SETnnnn       Set serial I/O to specified baud rate.  Only one
;               routine is called depending on HSnnnn EQUATE in
;               BYE core.  Should init CPS card to PSW=8N1 and
;               Baud = nnnn.
;
;
;-----------------------------------------------------------------------
;
;               CPS Serial Interface Routines
;
SLOT    EQU     2                       ; CPS card slot number
;
;
; CPS Serial Port and Register Equates
;
DATREG  EQU     0C0FAH + SLOT * 100H    ;Serial Data Register
STAREG  EQU     0C0FBH + SLOT * 100H    ;Serial Status Register
SCRCTL  EQU     0C0FEH + SLOT * 100H    ;CPS Serial Ctl Register
CLKREG  EQU     0C0F9H + SLOT * 100H    ;CPS Clock Data Register
;
RDBYTEAPPL      EQU     0FFE0H          ;Read byte from Apple
WRBYTEAPPL      EQU     0FFE3H          ;Write byte to Apple
RDWORD          EQU     0FFE6H          ;Read 2 bytes  (DE = Bytes)
WRWORD          EQU     0FFE9H          ;Write 2 bytes (DE = Bytes)
;
PEEK1BYTE       EQU     6               ;Command to Peek 1 byte to Apple
POKE1BYTE       EQU     7               ;Command to Poke 1 byte to Apple
;
;
; The following routines communicate with hardware in Apple Slots
; directly from Applicard.
;
; Read the UART Status Register
;
RD$STAREG:
       PUSH    D
       LXI     D,STAREG
       CALL    PEEK
       POP     D
       RET
;.....
;
;
; Write to the UART Status Register
;
WR$STAREG:
       PUSH    D
       LXI     D,STAREG
       CALL    POKE
       POP     D
       RET
;.....
;
;
; Write to the UART Command Port
;
WR$SCRCTL:
       PUSH    D
       LXI     D,SCRCTL
       CALL    POKE
       POP     D
       RET
;.....
;
;
; Read the UART Data Register
;
RD$DATREG:
       PUSH    D
       LXI     D,DATREG
       CALL    PEEK
       POP     D
       RET
;.....
;
;
; Write to the UART Data Register
;
WR$DATREG: PUSH D
       LXI     D,DATREG
       CALL    POKE
       POP     D
       RET
;.....
;
;
; Read a byte from CPS clock register
;
RD$CLKDATA:
       PUSH    D
       LXI     D,CLKREG        ; Select clock data
       CALL    PEEK
       POP     D
       RET
;.....
;
;
; PEEK at 1 byte in Apple address space
;    ENTRY  DE = Address in 6502 RAM/ROM
;    EXIT   A  = Data from 6502
;
PEEK:   PUSH    B
       MVI     C,PEEK1BYTE
       CALL    WRBYTEAPPL
       CALL    WRWORD
       CALL    RDBYTEAPPL
       POP     B
       RET
;.....
;
;
; POKE 1 byte to Apple address space
;    ENTRY  DE = Address in 6502 RAM/ROM
;    EXIT   A  = data to 6502
;
POKE:   PUSH    B
       MOV     B,A
       MVI     C,POKE1BYTE
       CALL    WRBYTEAPPL
       CALL    WRWORD
       MOV     C,B
       CALL    WRBYTEAPPL
       POP     B
       RET
;.....
;
;
;----------------------------------------------------------------------
;
; This routine intializes Serial Port of CPS card and (optionally)
; initializes ASCII commanded modem.  NOTE: PSW and BAUD must be set
; by two sequential writes to DATREG with SCRCTL access open.
;
MDINIT: MVI     A,80H
       CALL    WR$SCRCTL
       MVI     A,15H           ; Drop DTR and reset serial I/O
       CALL    WR$STAREG
       MVI     B,20
;
MDDLOP: CALL    DELAY           ; 2 second delay
       DCR     B
       JNZ     MDDLOP
       MVI     A,27H           ; Now re-enable serial port
       CALL    WR$STAREG
       MVI     A,4EH           ; Set PSW = 8N1  (1st DATREG write)
       CALL    WR$DATREG
       MVI     A,03AH          ; Default to 2400 baud
;
        IF     HS1200
       MVI     A,037H
        ENDIF                  ; HS1200
;
        IF     HS300
       MVI     A,035H
        ENDIF                  ; HS300
;
       CALL    WR$DATREG       ; Set baud (2nd DATREG write)
       XRA     A               ; Close BAUD/PSW access
       CALL    WR$SCRCTL
;
        IF     IMODEM
       CALL    IMINIT          ; Initialize smartmodem
        ENDIF                  ; IMODEM
;
       RET
;.....
;
;
; This routine is called when BYE is to go off the air
;
MDQUIT:  IF     IMODEM
       CALL    IMQUIT
        ENDIF                  ; IMODEM
;
;
; This routine will shut everything down permanently.
;
MDSTOP: MVI     A,80H           ; Enable UART command register
       CALL    WR$SCRCTL
       MVI     A,05H           ; Disable DTR and RTS (UART Cmd Reg)
       CALL    WR$STAREG
       XRA     A               ; Enable CPS status register
       CALL    WR$SCRCTL
       CALL    DELAY           ; 100 msec delay
       RET
;.....
;
;
; The following is a routine to determine if there is a character wait-
; ing to be received.  If none are there, the Zero flag will be set,
; otherwise, 255 will be returned in register A.
;
MDINST: CALL    RD$STAREG       ; Read UART command register
       ANI     02H             ; Mask everything but RxRDY, char ready?
       RZ                      ; No, then return
       ORI     0FFH            ; Yes, be sure to set flag and A reg
       RET
;.....
;
;
; The following is a routine to determine if the transmit buffer is
; empty.  If it is empty, it will return with the Zero flag clear.  If
; the transmitter is busy, then it will return with the Zero flag set.
;
;
MDOUTST:CALL    RD$STAREG       ; Read status register
       ANI     01H             ; Mask everything but TxRDY and...
       RET                     ; Return with flags set
;.....
;
;
; The following is a routine that will check to make sure we still have
; carrier.  If there is no carrier, it will return with the Zero flag
; set.  There are two entry points to this section: the 1st MDCRDL delays
; for 2 seconds or until carrier is detected.  The second is the normal
; entry for carrier check.
;
MDCRDL: PUSH    B
       MVI     B,20            ; Set for 2 sec delay max
;
MDCK2:  CALL    DELAY           ; Wait 100 msecs
       CALL    MDCARCK
       JNZ     MDCK1           ; If carrier, then return
       DCR     B
       JNZ     MDCK2           ; If not 2 secs, then continue timing
;
MDCK1:  POP     B               ; When done fall thru to carrier check
;
;
; This is normal carrier check routine.
;
MDCARCK:CALL    RD$STAREG       ; Read status register
       ANI     080H            ; Use DSR bit instead of DTR bit
       RET
;.....
;
;
; The following is a routine that will input one character from the
; CPS UART register.
;
MDINP:  CALL    RD$DATREG       ; Get character
       RET
;.....
;
;
; The following is a routine that will output one character in register
; A to the CPS UART data register.
;
MDOUTP: CALL    WR$DATREG       ; Send character to CPS UART
       RET
;.....
;
;
; The following routines set the CPS card to a specified baud rate. A
; common setup routine is jumped to after baud setup byte in local
; storage.
;
SET300: MVI     A,35H           ; 300 baud setup byte
       STA     MBSET
       JMP     BPSET           ; Jump to psw/baud set routine
;
SET1200:MVI     A,37H           ; 1200 bps byte
       STA     MBSET
       JMP     BPSET
;
SET2400:MVI     A,3AH           ; 2400 bps byte
       STA     MBSET
;
BPSET:  MVI     A,80H           ; Open command register
       CALL    WR$SCRCTL       ; By storing 80H in SCRCTL
       MVI     A,27H           ; Initialize the serial chip
       CALL    WR$STAREG       ; By storing 27H in STAREG
       MVI     A,4EH           ; Set default format 8N1
       CALL    WR$DATREG
       LDA     MBSET           ; Get baud rate byte from local storage
       CALL    WR$DATREG
       XRA     A
       CALL    WR$SCRCTL       ; Close command port by storing 0
       RET
;.....
;
;
MBSET:  DB      0               ; Storage for baud setup byte
;.....
;
;
;-----------------------------------------------------------------------
;
; WARNING:  This section uses code in the PORT insert above.  Use care
;           care if altering it or if you change the code above.
;
; This TIME routine is adapted from TIME14.ASM (Nov 85 - HMM).  The
; routine uses a burst read of time from CPS clock chip (OKI 5832).
; The raw data is stored in CLKBUF then assembled and placed into
; RTCBUF in BYE.
;
; Real-Time clock buffer is organized as HH:MM:SS  YYYY/MM/DD
;
;RTCBUF:DB      99H,99H,99H     ;HH:MM:SS (BCD 24hr) 00:00:00-23:59:59
;       DB      19H,84H,01H,31H ;YYYY/MM/DD  (BCD ISO DATE)
;
;
; BYE5 save and restores registers before/after calling TIME.
;
        IF     CLOCK OR RSPEED
TIME:   MVI     A,040H          ; Get byte to stop clock
       CALL    WR$SCRCTL       ; Send to CPS card
       LXI     D,CLKBUF        ; Put CLKBUF address in DE
       MVI     B,0             ; Set clock index to 0
;
TMLOOP: MVI     A,050H          ; Get byte to read clock
       ORA     B               ; Add clock index to read (50H - 5CH)
       CALL    WR$SCRCTL       ; Send to CPS card
       CALL    RD$CLKDATA      ; Read clock (SEC1 --> YEAR10)
       ANI     0FH             ; Mask garbage in high nibble
       STAX    D               ; Save value read in CLKBUF
       INX     D               ; Bump CLKBUF address value in DE
       INR     B               ; Bump clock index in BC
       MVI     A,0DH           ; Fetch table length + 1
       CMP     B               ; Are we beyond end of table...
       JNZ     TMLOOP          ; No, then go back again
       XRA     A               ; Yes, then zero A reg to turn on clock
       CALL    WR$SCRCTL
;
;
; Now move data from CLKBUF to RTCBUF.
;
FIXRTC: LDA     CLKBUF+1        ; Seconds
       ANI     7
       MOV     B,A
       LDA     CLKBUF+0
       CALL    SHFTIT
       STA     RTCBUF+2
       LDA     CLKBUF+3        ; Minutes
       ANI     7
       MOV     B,A
       LDA     CLKBUF+2
       CALL    SHFTIT
       STA     RTCBUF+1
       LDA     CLKBUF+5        ; Hours
       ANI     3
       MOV     B,A
       LDA     CLKBUF+4
       CALL    SHFTIT
       STA     RTCBUF+0
       MVI     A,19H           ; Century
       STA     RTCBUF+3
       LDA     CLKBUF+12       ; Year
       MOV     B,A
       LDA     CLKBUF+11
       CALL    SHFTIT
       STA     RTCBUF+4
       LDA     CLKBUF+10       ; Month
       ANI     1
       MOV     B,A
       LDA     CLKBUF+9
       CALL    SHFTIT
       STA     RTCBUF+5
       LDA     CLKBUF+8        ; Day
       ANI     3
       MOV     B,A
       LDA     CLKBUF+7
       CALL    SHFTIT
       STA     RTCBUF+6
       LDA     RTCBUF          ; Put current hour
       CALL    BCDBIN
       STA     CCHOUR          ; And minute into CCHOUR
       LDA     RTCBUF+1
       CALL    BCDBIN          ; And CCMIN in Binary
       STA     CCMIN
       RET                     ; To BYE
;
SHFTIT: PUSH    PSW             ; Routine to put A & B registers
       MOV     A,B             ; Together (low order nibbles)
       RLC
       RLC                     ; Return with result in A.
       RLC
       RLC
       MOV     B,A
       POP     PSW
       ANI     0FH
       ORA     B
       RET
;.....
;
;
; The CLKBUF is fixed, initialized area used to store time as
; read from CPS clock hardware.  Must be DB 0 for proper relocation
; when using BYE.
;
CLKBUF: DB      0               ; S1
       DB      0               ; S10
       DB      0               ; MIN1
       DB      0               ; MIN10
       DB      0               ; H1
       DB      0               ; H10
       DB      0               ; Day of Week (not used here in BYE)
       DB      0               ; D1
       DB      0               ; D10
       DB      0               ; MON1
       DB      0               ; MON10
       DB      0               ; Y1
       DB      0               ; Y10
        ENDIF                  ; CLOCK OR RSPEED
;.....
;
;                              end
;-----------------------------------------------------------------------