; Uploaded to simtel-20 by Ralph Hyre (ralphw@c.cs.cmu.edu)
; Sent to Ralph by Chris Peck (chris@bingvaxb.bitnet)
; You will need one of the follwing items to use these drivers:
;	the PCPI OEM package (bucks involved - order from PCPI)
;	the assembled output of the PCPI OEM package assembler.
;	(this will be made available here as soon as I can assemble it)
;************************************
;ROUTINE: GAMEPRT.A65
;PURP:  USE THE GAME I/O PORT FOR A SERIAL OUTPUT PORT
;
;       06/09/83 CREATED (FPM)
;       06/30/83 ADDED PARITY GENERATING ROUTINE
;
TRUE:     .EQU  0FFH
FALSE:    .EQU  0
;************************ USER EQUATES ***************************
;BE SURE TO SET ONLY ONE BAUD TRUE
BAUD300:     .EQU  FALSE        ;TRUE=300  BAUD
BAUD600:     .EQU  FALSE        ;TRUE=600  BAUD
BAUD1200:    .EQU  TRUE         ;TRUE=1200 BAUD
BAUD2400:    .EQU  FALSE        ;TRUE=2400 BAUD
BAUD4800:    .EQU  FALSE        ;TRUE=4800 BAUD
BAUD9600:    .EQU  FALSE        ;TRUE=9600 BAUD

PUSHBUTTON:  .EQU  0            ;BUSY INPUT LINE ->SET TO 0, 1 OR 2
ANNUNCIATOR: .EQU  0            ;DATA OUTPUT LINE ->SET TO 0, 1, 2 OR 3
STOPBITS:    .EQU  1            ;NUMBER OF STOP BITS ->SET TO 1 OR 2
PARITY:      .EQU  FALSE        ;TRUE=GENERATE PARITY  FALSE=NO PARITY
ODD:         .EQU  TRUE         ;TRUE TO GENERATE ODD PARITY
EVEN:        .EQU  FALSE        ;TRUE TO GENERATE EVEN PARITY
;If parity if set to TRUE either ODD or EVEN must be TRUE!!!
;******************************************************************
;DISCUSSION:
;This experimental driver can be used to output bytes to some RS-232
;compatible devices.  Specifically it has been tested on a QUME Sprint 5/45,
;a Chyron VP-1 character generator and a CVC Intelligent controller.  For
;proper operation only 3 lines are necessary.  One is for sending the
;characters, one for a handshake line, and finally a signal ground.
;For this discussion assume a QUME serial printer is to be used.

;PIN CONFIGURATION: See figure 16 ->Apple II Reference Manual pp.100
;-------------------------------------------------------------------
;       SIGNAL NAME             GAME I/O CONNECTOR      QUME PRINTER
;-------------------------------------------------------------------
;        Ground                    Pin #8 (Gnd)           Pin #7
;        RTS(Clear to Send)        Pin #2 (PB0)           Pin #4
;        RXD(Receive Data)         Pin #15(AN0)           Pin #3
;--------------------------------------------------------------------
;The QUME will accept characters until its buffer is full, at which time
;it will lower the RTS line to signal the sending computer showing it is
;is no longer ready for characters.  This line is wired to push-button
;#0 of the Game I/O connector.  When this line goes low, the hi bit of
;pushbutton #0 is reset(0).  The output routine will wait until this bit
;is high(1) before outputting a character.
;
;Character output is accomplished by breaking each character into
;a start bit, its normal 8 bits, and a stop bit.  Annunciator #0
;is used here (however any of the annunciators would work).  First a
;start bit(Space or +5) is sent by turning on AN0(LDA $C059).
;Then each bit of the character is sent starting with the LSB.
;If the bit is a 1,  the annunciator is turned off and is it is a 0
;it is turned on.  Finally 1(or 2) stop bits(Mark or 0 volts) are sent by
;turning off AN0(LDA $C058).  A software timing loop is implemented
;to control the speed of sending.  Since the RS-232 standard is from
;+3 to +12 volts and -3 to -12 volts, many receiving devices will
;see the change from 0 to 5 volts (or 5 to 0 volts) as a change
;in state and read it as such.  Some RS-232 receivers may, however, not
;recognize these signal levels, so you'll just have to experiment.
;
;["Editor's" note: you may get better results by using a the 1488 and 1489
; line driver and receiver chips, which convert RS-232 <-> TTL levels.
; These chips also provide a measure of protection for your Apple.]
;
;Since the RS-232 standard allows for about a 2% error on the receiving
;end, slight timing differences from a clock crystal on the transmitting
;end can usually be ignored.  The transmitting error for this driver
;is lower than 1.0%.  The 300, 600, and 1200 baud rates were tested
;on a QUME printer and a Televideo 950 terminal.  The 2400, 4800,
;and 9600 baud rates were tested on the Televideo, VP1 character
;generator, and CVC units.  9600 baud is the fastest rate possible
;with this algorithm.
;
;If parity is desired, first set the PARITY equate to TRUE.  Then
; set either ODD or EVEN to true.  Even parity makes the total number
;of 1-bits in the stream of bits even;  ;odd parity makes the total
;number of 1-bits odd.  Be sure to set the receiving device for the
;proper parity if it is enabled.

;GET EQUATES
.NOLIST
        .INCLUDE DRVREQUS.A65
.LIST

BUSYIN:      .EQU 0C061H+PUSHBUTTON
SPACE:       .EQU 0C059H+(ANNUNCIATOR*2)
MARK:        .EQU 0C058H+(ANNUNCIATOR*2)
BITNUMBER:   .EQU 1+8+STOPBITS  ;1START+8DATA+STOPBITS=NUMBER BITS TO SEND
        .IF PARITY AND ODD
PARTYPE:     .EQU 1
        .ENDC

        .IF PARITY AND EVEN
PARTYPE:     .EQU 0
        .ENDC

;TIMER VALUE TABLE:
;-------------------------------------
;     BAUD RATE        VALUE
;-------------------------------------
;       300             241
;       600             120
;       1200             59
;       2400             29
;       4800             14
;       9600              6
;-------------------------------------
    .IF BAUD300
TIMER:    .EQU  241             ;300 BAUD TIMING VALUE
    .ENDC
    .IF BAUD600
TIMER:    .EQU  120             ;600 BAUD TIMING VALUE
    .ENDC
    .IF BAUD1200
TIMER:    .EQU  59              ;1200 BAUD TIMING VALUE
    .ENDC
    .IF BAUD2400
TIMER:    .EQU  29              ;2400 BAUD TIMING VALUE
    .ENDC
    .IF BAUD4800
TIMER:    .EQU  14              ;4800 BAUD TIMING VALUE
    .ENDC
    .IF BAUD9600
TIMER:    .EQU  6               ;9600 BAUD TIMING VALUE
    .ENDC

;*****************************************************************

BASEP0:  .QUERY "ENTER BASE OF PAGE 0: "
LENP0:   .EQU   0

;HEADER FOR RELOCATION
TOP:
        .WORD   0               ;IF THIS WORD IS 0 THEN
                                ;   RELOCATABLE DRIVER
                                ;   AND A RELOCATING BIT MAP IS EXPECTED
                                ;ELSE
                                ;   THE DRIVER STORED WHERE INDICATED
        .WORD   ((BOTTOM-TOP)+0FFH) AND 0FF00H ;LENGTH OF THIS CODE
                                ;                TO NEXT PAGE BOUNDRY
        .BYTE   LENP0           ;THIS IS THE NUMBER OF PAGE 0 BYTES
                                ; REQUIRED. IF ITS NO ZERO THEN A RELOCATING
                                ; BIT MAP IS EXPECTED FOR PAGE 0
        .BYTE   0               ;TAG FIELD
        .WORD   14H             ;DEVICE NUMBER (14=CHARACTER DEVICE 4=UL1:)
        .WORD   1               ;NUMBER OF DEVICES THIS DRIVER WILL SERVICE
        .WORD   INITENTRY       ;INIT ENTRY POINT
        .WORD   INENTRY         ;INPUT ENTRY POINT
        .WORD   OUTENTRY        ;OUTPUT ENTRY POINT
        .WORD   OTHERENTRY      ;OTHER ENTRY POINT
        .WORD   POLLENTRY       ;POLL ENTRY POINT
        .WORD   2               ;VERSION NUMBER
  .IF BAUD300
NAME:   .BYTE   13,"GAME PORT 300" ;NAME OF DRIVER
  .ENDC
  .IF BAUD600
NAME:   .BYTE   13,"GAME PORT 600" ;NAME OF DRIVER
  .ENDC
  .IF BAUD1200
NAME:   .BYTE   14,"GAME PORT 1200" ;NAME OF DRIVER
  .ENDC
  .IF BAUD2400
NAME:   .BYTE   14,"GAME PORT 2400" ;NAME OF DRIVER
  .ENDC
  .IF BAUD4800
NAME:   .BYTE   14,"GAME PORT 4800" ;NAME OF DRIVER
  .ENDC
  .IF BAUD9600
NAME:   .BYTE   14,"GAME PORT 9600" ;NAME OF DRIVER
  .ENDC

;*************************************
;ROUTINE: INITENTRY
;PURP:  INITIALIZE
;ENTRY: NONE
;USED:  ALL
;*************************************
INITENTRY:
        RTS

;***********************************
;ROUTINE: INENTRY:
;PURP:  INPUT A CHARACTER
;ENTRY: Y = n0
;       X = Cn
;       WHERE n IS THE SLOT NUMBER
;EXIT:  A = CHARACTER
;USED:  ALL
;***********************************

INENTRY:
        RTS                             ;RETURN TO CALLER

;***********************************
;ROUTINE: OUTENTRY
;PURP:  OUTPUT A CHARACTER TO THE DEVICE
;ENTRY: A = CHARACTER
;       Y = n0
;       X = Cn
;       WHERE n  IS THE SLOT NUMBER
;EXIT:  NONE
;USED:  ALL
;************************************

OUTENTRY:
        BIT     BUSYIN                  ;READ PUSH-BUTTON (BUSY INPUT)
        BPL     OUTENTRY                ;NOT READY IF VOLTAGE IS LOW - SO WAIT
;***THANKS TO BOB SANDER-CEDERLOF OF S-C SOFTWARE FOR THE PARITY ROUTINE***
  .IF PARITY                    ;ON ENTRY A=CHAR
        LDX     #PARTYPE                ;1=ODD  0=EVEN
        ASL     A                       ;SHIFT PARITY POSITION OUT
        PHA                             ;SAVE SHIFTED CHARACTER
$1:     BPL     $2                      ;IF NEXT BIT=0, DON'T COUNT
        INX                             ;IF NEXT BIT=1, COUNT IT
$2:     ASL     A                       ;SHIFT IN NEXT BIT
        BNE     $1                      ;IF ANY REMAINING BITS = 1
        TXA                             ;GET COUNT OF 1-BITS
        LSR     A                       ;EVEN/ODD BIT OF COUNT IN TO CARRY
        PLA                             ;ORIGINAL CHAR BUT SHIFTED
        ROR     A                       ;SHIFT PARITY BIT INTO BIT 8
   .ENDC                        ;ON EXIT A=CHAR WITH PARITY
        PHP                             ;SAVE PROCESSOR STATUS(W/INTERPT STAT)
        SEI                             ;DISABLE INTERRUPTS ALWAYS
        LDY     #BITNUMBER              ;# BITS TO SEND
        CLC                             ;SET UP FOR START BIT(ALWAYS SPACE)
$3:     PHA             ;3\             ;SAVE CHAR
        BCS     $4      ;2 \            ;1-BIT, SEND MARK
        LDA     SPACE   ;4  \           ;0-BIT, SEND SPACE
        BCC     $5      ;2   > =13 cycles
$4:     LDA     MARK    ;  /            ;MARK
$5:     LDA     #TIMER  ;2/             ;TIMING LOOP COUNTER

$6:     PHA             ;3\
        NOP             ;2 \
        PLA             ;4  >=14xTIMER cycles
        SBC     #1      ;2 /
        BNE     $6      ;3/
        PHA             ;3\
        PLA             ;4 \
        PLA             ;4  \           ;GET CHAR (CARRY IS SET FOR STOPS)
        ROR     A       ;2  / =18 cycles;NEXT BIT INTO CARRY
        DEY             ;2 /
        BNE     $3      ;3/             ;SEND NEXT BIT
        PLP             ;RESTORE PROCESSOR STATUS(&INTERRUPTS IF ANY)
        RTS

;1200 BAUD TIMING
  ;AVERAGE BIT TRANSMISSION TIME (1200)-> 13+(14x59)+18=857 cycles/bits
  ;EXACT TIMING IS  1.023E6/1200=852 cycles/bit +/- 2% (+/-8 cycles)
;300 BAUD TIMING
  ;AVERAGE BIT TRANSMISSION TIME (300)-> 13+(14x241)+18=3405 cycles/bit
  ;EXACT TIMING IS  1.023E6/300=3410 cycles/bit +/- 2%  (+/-34 cycles)

;***********************************
;ROUTINE: OTHERENTRY
;PURP:  HANDLE OTHER COMMANDS
;ENTRY: A = OTHER COMMAND
;       X = N0
;       Y = CN
;EXIT:  A = ERROR CODE
;USED:  ALL
;***********************************

OTHERENTRY:
        CMP     #0
        BEQ     OUTSTAT         ;BRANCH IF OUTPUT STATUS COMMAND
        CMP     #1
        BEQ     INSTAT          ;BRANCH IF INTPUT STATUS COMMAND
        CMP     #2
        BEQ     VIDEOON         ;BRANCH IF VIDEO ON COMMAND
        CMP     #3
        BEQ     APLEON          ;BRANCH IF APPLE ON COMMAND
        CMP     #4
        BEQ     WIDTH           ;BRANCH IF WIDTH COMMAND
        CMP     #SNDNAMECMD
        BEQ     SENDNAME        ;BRANCH IF SEND NAME COMMAND

        ;ERROR BAD COMMAND
        LDA     #0FFH           ;ELSE ERROR
        RTS


OUTSTAT:
        ;TEST IF THE DEVICE IS READY TO SEND ANOTHER CHARACTER
        BIT     BUSYIN          ;CHECK INPUT STATUS
        BPL     NOTRDY          ;BIF NOT READY TO SEND
        BMI     RDY             ;BIF READY TO SEND

INSTAT:
        ;TEST IF THE DEVICE HAS A CHARCTER TO INPUT
        ;SHOW NOT READY AT ALL TIMES
NOTRDY:
        LDA     #0
        RTS

RDY:
        LDA     #0FFH
        RTS


VIDEOON:
        ;DO SOMETHING TO TURN ON YOUR VIDEO
        ; THIS IS PROBABLY NOTHING UNLESS THIS IS A CONSOLE DEVICE
        RTS

APLEON:
        ;DO SOMETHING TO TURN ON THE APPLE VIDEO ON
        ; THIS IS PROBABLY NOTHING UNLESS THIS IS A CONSOLE DEVICE
        RTS

WIDTH:
        ;RETURN THE WIDTH OF THIS DEVICE
        LDA     #80     ;80 COLUMNS ?
        RTS


SENDNAME:
        ;SEND THE NAME COMMAND
        LDA     NAME            ;GET LENGTH
        STA     CNT             ;SAVE AS COUNT
        JSR     WR1Z80BYTE      ;SEND IT TO HOST
        LDA     #1
        STA     IDX
        LDA     CNT
        CLC
        BEQ     EXIT

$LP:    LDX     IDX
        LDA     NAME,X          ;GET NEXT CHARACTER
        JSR     WR1Z80BYTE
        INC     IDX
        DEC     CNT
        BNE     $LP             ;CONTINUE UNTIL ALL BYTES ARE SENT
EXIT:   BCS     ERRXIT
        LDA     #0
        RTS
ERRXIT: TAY
        BNE     RET
ERROR:  LDA     #0FFH
RET:    RTS
;***********************************
;ROUTINE: POLLENTRY
;PURP:  HANDLE POLLING, THIS ENTRY POINT
;       IS CALLED PERIODICALY WHILE THE APPLE IS
;       WAITING FOR A COMMAND FROM THE Z-80. THIS
;       CODE SHOULD BE VERY SHORT AS THE Z-80 IS
;       IGNORED WHILE THIS CODE IS BEING EXECUTED
;ENTRY: NONE
;EXIT:  NONE
;USED:  ALL
;***********************************

POLLENTRY:
        RTS

;TEMPORARY DATA
IDX:    .BLOCK  1       ;TEMPORARY
CNT:    .BLOCK  1       ;TEMPORARY

BOTTOM:
        .END
