	PROCESSOR 6502
        LIST    ON

	ORG	$0800
; constants
COUT1	EQU	$FDED
CLEAR	EQU	$FC58
KEYBOARD	EQU	$C000
KBCLEAR	EQU	$C010
COLUM80 EQU	$C300	; assume 80 column card in slot 3
PRIMMON EQU 	$C058
SECMON  EQU	$C059
STORE80	EQU	$C001	; enable aux mem
PAGE2OF	EQU	$C054	; page 1 first
PAGE2ON	EQU	$C055	; now do aux mem


WINDOWWID EQU	33	; window width
WINDOWTOP EQU	34	; input window top
HORLOC	EQU 	36	; vertical location
VERTLOC	EQU 	37	; vertical location
BASL	EQU	40	; base address low
BASH	EQU	41	; ...high
NCOUNT 	EQU	$35	; counter used in bit out and in routines
BELL 	EQU	$438	; bell counter  0 = don't ring bell
BAUDCONST EQU	$3B8
STATUS 	EQU	$4B8	; status saved at init time
BYTE	EQU	$5B8	; data byte
NO	EQU	$6F8	; slot < 4
PARITY	EQU	$778	; parity accumulator
SLOTADDRESS EQU	$C2	; serial interface slot address
SLOT	EQU 	2	; hard code slot

; flow for Apple IIe Teletype emulation
START:
	JSR	COLUM80		; set 80 colum video mdoe (assumes prescence of 80 column card)
	STA	STORE80	; enable aux mem
	LDA	SECMON		; use correct monitor
	LDA	#0
	STA	WINDOWTOP	; new top
	LDA	#72
	STA	WINDOWWID	; set width to 72
	LDA	#25		; home 
	JSR	COUT1		;

; serial output  (110 baud)
; 7F8 and X = 0xCN  (where N = slot number)
; Y = 0xN0 (where N = slot number) - this is used to access device I/O space on card
; 6F8/N0 - where N = slot number
; 778/PARITY = random - used as scratch pad
; 3B8,X/BAUDCONST  where X = N (slot number) = baud rate constant  (B0 for 110)
; 4B8,X/STATUS where X = N (slot number) = 
; 5B8,X/BTYE
; initialize serial params

	LDX	#SLOTADDRESS
	LDA	#$AF
	STA	BAUDCONST,X
	LDA	#$6		; status - no parity, no checksum
	STA	STATUS,X
	LDA	#$0
	STA	BELL,X		; don't ring ring bell 
	LDA	#100		; bell delay counter
	STA	NCOUNT

; main loop	
; set 80 column mode and clear screen
GETNEXTCHAR:
	LDX	#SLOTADDRESS
	LDY	#$20		; slot << 4
	STY	NO
;
; buzz speaker- routine comes here 
;
GETNEXTCHARLOOP2:
; check for serial input?
	LDA 	$C081,Y		; serial input going low?
	BPL	SERIAL_START	; serial input check true - branch

; check for input que
	JSR	GETINPUT
	BCC	DEQUE_INPUT	; got a byte, let's display it

; check for keyboard input?
	LDA	KEYBOARD
	BMI	KEYIN

; is bell sounding?
	LDA	BELL,X		; don't ring ring bell 
	BEQ	GETNEXTCHARLOOP2 ; if zero

; the bell is sounding -delay to create decent fequency
	DEC	NCOUNT	
	BNE	GETNEXTCHARLOOP2 ; nope, continue polling

	LDA	#100		; reset bell delay counter
	STA	NCOUNT

; toggle bell until counter goes to zero
	LDA	$C030
	DEC	BELL,X
	JMP	GETNEXTCHARLOOP2 ; continue withl poll loop
;
; serial start bit detected
; X and Y are already initialized
;
SERIAL_START:
	JSR	I_GOT_START	; call serial input routine
	JSR	GETINPUT
	BCS	GETNEXTCHAR	; should always fall through

DEQUE_INPUT:
	JSR	DISPLAYONSCREEN ; display it on the screen
	JMP	GETNEXTCHAR	; continue with poll loop

;
; read character from keyboard, display on screen and echo to serial port
; character from keyboard  in A
;
KEYIN:
	STA	KBCLEAR		; clear keyboard strobe
	STA	BYTE,X		; save byte in buffer
	JSR 	DISPLAYONSCREEN	; call display on screen

	LDX	#SLOTADDRESS	; set up regs for serial output
	LDY	#$20		; slot << 4
	STY	NO
	LDA	BYTE,X		; save byte in buffer
	JSR	PUTSERIAL	; call serial output
	JMP	GETNEXTCHAR 	; return to getnextchar


; display character on screen (input reg A = character)
DISPLAYONSCREEN:
	CMP	#$8D		; CR return only returns cursor to column 0
	BEQ     DOS_CR
	CMP	#$87		; Bell Character?
	BEQ	DOS_RING_BELL 	; yes, branch to poll loop that rings bell
	CMP	#$A0		; SPACE
	BEQ	DOS_SPACE	; just advance printer head
	CMP	#$8A		; LF
	BEQ	DOS_LF		; - if at end of screen - use fast scroll routine
	CMP	#$FF		; Rubout 
	BEQ	DOS_RO		; - just transmit this one, don't print
	CMP	#$A0		; remaining control characters
	BMI	DOS_RO		; - just transmit, don't print
	JSR	PRINT

DOS_SPACE:			; space comes here to just advance print head
				; advance print head
	LDA	#71		; make sure it stops at 72 column
	CMP	HORLOC
	BEQ	PRTDONE		; not there
	INC	HORLOC		; keep it in column 72
DOS_RO:
PRTDONE:
; return to caller
	RTS
;
; Need to flag to return to bell routine
;
DOS_RING_BELL
	LDA	#100	
	STA	BELL,X		; save bell ring count in buffer, signal bell ringing function to start
	RTS

DOS_CR:
	LDA	#0		; start of line
	STA	HORLOC		;
	RTS

DOS_LF:
	LDA	VERTLOC		;
	CMP	#23		; last line?
	BNE	DOS_LF_EXIT	; no, use usual char output function
	JSR	FAST_SCROLL	; scroll screen
	RTS	
DOS_LF_EXIT:
	INC	VERTLOC		;
	RTS


;
; Line starting addresses
;
LINE1	EQU	$400
LINE2	EQU	$480
LINE3	EQU	$500
LINE4	EQU	$580
LINE5	EQU	$600
LINE6	EQU	$680
LINE7	EQU	$700
LINE8	EQU	$780
LINE9	EQU	$428
LINE10	EQU	$4A8
LINE11	EQU	$528
LINE12	EQU	$5A8
LINE13	EQU	$628
LINE14	EQU	$6A8
LINE15	EQU	$728
LINE16	EQU	$7A8
LINE17	EQU	$450
LINE18	EQU	$4D0
LINE19	EQU	$550
LINE20	EQU	$5D0
LINE21	EQU	$650
LINE22	EQU	$6D0
LINE23	EQU	$750
LINE24	EQU	$7D0

PRINT:
	PHA		;save character to print


; now calculate row base address
	LDA	VERTLOC	; fetch vertical row
	LSR	
	AND	#$03	; 0<=line no. <=23
	ORA	#$04	; ARG = 000ABCDE, GENERATE
	STA	BASH	; BASH = 000001CD
	LDA	VERTLOC	; fetch vertical row
	AND	#$18	; BASL = EABAB000
	BCC	BSCLC2
	ADC	#$7F
BSCLC2:
	STA	BASL
	ASL	
	ASL	
	ORA	BASL
	STA	BASL

; set correct page for 80 column output
	LDA	HORLOC  ;fetch current column
	AND	#$01
	BNE	PRT_OD
	STA	PAGE2ON	; nope, it's aux mem
PRT_OD:
	LDA	HORLOC		; divide horizontal by 2 to get location in page
	LSR	
	TAY
	
	PLA	
	AND	#$3F
	ORA	#$80		; not invert, not flash
	STA	(BASL),Y	; save character
	STA	PAGE2OF		; move back to page 1
	RTS

PAGEFLG DC.B	0		; page flag
; X preserved, caller must conserve other registers
FAST_SCROLL
	STA	STORE80		; enable aux mem
	JSR	FS_DOIT

	INC	PAGEFLG		; page aux
	STA	PAGE2ON		; now do aux mem
	JSR	FS_DOIT
	STA	PAGE2OF		; move back to page 1
	DEC	PAGEFLG		; 

	RTS

FS_DOIT:
	LDY	#35
FS_L1:
;
; check for data in, while scrolling
;
	STY	YSAV
	LDY 	NO
	LDA 	$C081,Y			; read input, waiting for start bit
	BMI	FS_CHK_START_RET

	LDA	PAGEFLG
	BEQ	FS_GOT_START
	STA	PAGE2OF		; page 1 for this routine
FS_GOT_START:
	JSR	I_GOT_START	; get input
	LDA	PAGEFLG
	BEQ	FS_CHK_START_RET
	STA	PAGE2ON		; return to page 2
FS_CHK_START_RET:
	LDY	YSAV

	LDA	LINE2,Y
	STA	LINE1,Y
	LDA	LINE3,Y
	STA	LINE2,Y
	LDA	LINE4,Y
	STA	LINE3,Y
	LDA	LINE5,Y
	STA	LINE4,Y
	LDA	LINE6,Y
	STA	LINE5,Y
	LDA	LINE7,Y
	STA	LINE6,Y
	LDA	LINE8,Y
	STA	LINE7,Y
	LDA	LINE9,Y
	STA	LINE8,Y
	LDA	LINE10,Y
	STA	LINE9,Y
	LDA	LINE11,Y
	STA	LINE10,Y
	LDA	LINE12,Y
	STA	LINE11,Y
	LDA	LINE13,Y
	STA	LINE12,Y
	LDA	LINE14,Y
	STA	LINE13,Y
	LDA	LINE15,Y
	STA	LINE14,Y
	LDA	LINE16,Y
	STA	LINE15,Y
	LDA	LINE17,Y
	STA	LINE16,Y
	LDA	LINE18,Y
	STA	LINE17,Y
	LDA	LINE19,Y
	STA	LINE18,Y
	LDA	LINE20,Y
	STA	LINE19,Y
	LDA	LINE21,Y
	STA	LINE20,Y
	LDA	LINE22,Y
	STA	LINE21,Y
	LDA	LINE23,Y
	STA	LINE22,Y
	LDA	LINE24,Y
	STA	LINE23,Y
	LDA	#$A0		; clear last line
	STA	LINE24,Y
	DEY
	BMI	FS_DONE
;
; scrolled one column of one text and checked for serial in, now move to next column
;
	JMP	FS_L1

FS_DONE:
	RTS


YSAV:	DC.B	0
	
; 7F8 and X = 0xCN  (where N = slot number)
; Y = 0xN0 (where N = slot number) - this is used to access device I/O space on card
; 6F8/N0 - where N = slot number
; 778/PARITY = random - used as scratch pad
; 438,X/BELL 
; 4B8,X/STATUS where X = N (slot number) = 
; 5B8,X/BTYE

; serial input (110 baud)
; X preserved, caller must conserve other registers, as necessary

I_GOT_START:
	SEI
	LDA 	#$07			;7 bits, plus stop bit
	STA 	NCOUNT
	LDY NO
	LDA $C081,Y			; read input, waiting for start bit
	BPL I_STRT_CHK_OK
	RTS				; start bit not stable, return
I_STRT_CHK_OK:
	LDA BAUDCONST,X
	LDY #$09
I_IWAIT:				;inner delay
	DEY
	BNE I_IWAIT
	SBC #$01
	BEQ I_GETBIT			; done delaying, branch to start getting data
	LDY #$0E
	BNE I_IWAIT

I_GETBIT:
	LDY NO
	LDA $C081,Y			; read input, waiting for start bit

	ROL
	ROR BYTE,X
	DEC NCOUNT			; all bits recieved?
	BEQ I_MOD

	LDA BAUDCONST,X			; fetch baud rate constant
	SEC
I_WAIT1:
	SBC #$01
	BEQ I_GETBIT
	LDY #$09
I_WAIT53:				; delay = 53X(BRATE-1) CYCLES
	DEY
	BNE I_WAIT53
	BEQ I_WAIT1

I_MOD:
	SEC
	ROR BYTE,X			; MSB is one
 ; wait for stop bit before returning
I_WSTOP:
	LDA $C081,Y
	BPL I_WSTOP

	LDA	BYTE,X		; get byte read
	JMP	PUTINPUT	; sav it for later, and return


; Hijacked from standard serial card ROMs
;
; serial output  (110 baud)

PUTSERIAL:
	SEI
	CLC			; clear carry
	PHP			; for second pass (after sending stop bits)
	SEC			; set carry indicating first pass and
	PHP			; save it for later on stack
	LDY #$09		; counting start bit - 9 bits
	STY NCOUNT		; save in COUNTER

	LDA #$00
	ASL BYTE,X		; 5B8 + X (CN) ???
O_NEXTBIT:
	ROR BYTE,X
	ROL			;  a bit
	ORA NO			; 
	TAY
O_STOP:
	SEC
	LDA $C080,Y		; output bit
	LDA BAUDCONST,X		; fetch baud rate delay
O_OUTER_DELAY:
	SBC #$1			; outer delay loop
	BEQ O_DELAY_DONE
	LDY #$09		; inner delay loop
O_INNER_DELAY:
	DEY			; 9 x (00 + 00)
	BNE O_INNER_DELAY	;
	BEQ O_OUTER_DELAY	;

O_DELAY_DONE:
	LDY #2			; 2 stop bits
	DEC NCOUNT		; count bits
	BNE O_NEXTBIT		; next bit

	PLP			; check flag set a beginning
	BCC O_DONE		; not set, all done

	STY NCOUNT		; save counter for stop bits
	SEC			; set up second stop bit
	ROL BYTE,X		; 5B8 + X (CN) ???
	LDY NO
	INY
	JMP O_STOP		; send stop bits
O_DONE:
	RTS
;
; INPUT FIFO MGMT
;
	ALIGN	256
INFIFO	DS	256
INFHD	DC.B	0
INFTL	DC.B	0
INFXSAV	DC.B	0

; move character into input fifo
; A = char to save
; other registers preserved
; return carry set if fail
PUTINPUT:
; is there room
	STX	INFXSAV		; save X
	
	LDX	INFHD		;
	INX
	CPX	INFTL
	BNE	PI_ADD

	LDX	INFXSAV		; restore X
	SEC
	RTS
PI_ADD:
	STX	INFHD		; save next head ptr
	DEX			; save in previous spot
	STA	INFIFO,X	; save byte

	LDX	INFXSAV		; restore X
	CLC			; all is good
	RTS
	
; get character from input fifo
; character, if available, returned in A
; other registers preserved
; return carry clear if success
GETINPUT:
	LDA	INFTL
	CMP	INFHD 		; is there a character?
	BNE	GI_GET
	SEC			; nothing available
	RTS
GI_GET:
	STX	INFXSAV		; save X
	LDX	INFTL		; fetch ptr
	LDA	INFIFO,X	; get character
	INC	INFTL		; bump ptr
	LDX	INFXSAV		; restore X
	CLC			; all is good
	RTS			; A has character





