;************************************************************************
;*	PROJECT:		JAGUAR					*
;*	FUNCTION:		DRIVER FOR CORTINA			*
;*	PROGRAMMER:		Andreas Binner				* 
;*	UPDATED BY:		Hans-Martin Krober (12/95)		*
;*	DATE:			8/95					*
;*									*
;*              COPYRIGHT 1994,1995 Atari U.S. Corporation              *
;*          UNATHORIZED REPRODUCTION, ADAPTATION, DISTRIBUTION,         *
;*          PERFORMANCE OR DISPLAY OF THIS COMPUTER PROGRAM OR          *
;*        THE ASSOCIATED AUDIOVISUAL WORK IS STRICTLY PROHIBITED.       *
;*                            ALL RIGHTS RESERVED.                      *
;*									*
;************************************************************************


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

	.include	'jaguar.inc'

;************************************************************************
	.extern		GPU_Go
	.extern		CORTINA_COPY
	.extern		cortina_go
	.extern		crt_gpu_buffer

	.globl		_crt_gen_buf
	.globl		_crt_gen_wrix

	.globl		_init_jag_uart
	.globl		_crt_sndcmd
	.globl		_crt_kbdstat
	.globl		_crt_getkbd
	.globl		_crt_getaux
	.globl		_crt_putaux
	.globl		_crt_mouse
	.globl		_crt_auxstat
	.globl		_crt_init


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

PCLK		equ     26590906        	; system clock speed
UARTBAUD       	equ     4860			; startup JAG UART Baud Rate
N_ACLK          equ     ((PCLK/(16*UARTBAUD))-1)

;
;*** Jaguar UART Baud Rate Setup
;

ACLK_46K        equ     35		; 46 KBaud
ACLK_93K	equ	17		; 93 KBaud
ACLK_18K	equ	89		; 18 KBaud
ACLK_4860	equ	341		; 4860 Baud

HI_ACLK		equ	ACLK_46K	; Current Setting
 
;
;*** Cortina Buffer Sizes
;
CRT_KBD_BUFSIZE	equ	4096
CRT_AUX_BUFSIZE	equ	4096
CRT_STD_BUFSIZE	equ	4096


;
;*** PC Keyboard Codes
;
KBDCODE_SHIFT1	equ	$12
KBDCODE_SHIFT2	equ	$59

;**************************************************************************
; Low Level Routines
;**************************************************************************

;**************************************************************************
; _init_jag_uart
;		
;	Init JAGUAR UART for use by Cortina
;
;	Returns $88 if successful!
;**************************************************************************

_init_jag_uart:
	movem.l	a1-a5/d1-d6,-(sp)
	jsr	UART_INIT
	move.l	#crt_init_str,a0
	move.l	#2,d0
	jsr	UART_SEND

; wait for byte to finish transmit at old rate
.2:
	move.w  ASISTAT,d1
	btst    #U_TBE,d1
	beq     .2

	move.w  #1094,d0		; 1.5ms ;4bits?on an 010 ; 3283=2.5 ms?
.4:
	dbra    d0,.4              	; short wait to ensure that 

	move.w  #HI_ACLK,ASICLK		; Set up new baud rate

; wait for reply

.1:
	move.l	_crt_gen_wrix,d1
	move.l	_crt_gen_rdix,d2
	cmp.l	d2,d1
	beq	.1

	movea.l	#_crt_gen_buf,a2
	add.l	d2,a2
	move.l	d1,_crt_gen_rdix
	clr.l	d0
	move.b	(a2)+, d0
	move.l	#3, _crt_mouse_rdix		;big kludge DEBUG

	movem.l	(sp)+,a1-a5/d1-d6
	rts

;**************************************************************************
; UARTS COMANDS
;**************************************************************************

;**************************************************************************
; UART_INIT
;
; Use this routine to initialise the Uart and also to clear any errors
; detected. It is very important that no other code asserts the CLRERR
; bit in the ASICTRL (F10032) register
;
; Parameters:- None
; Returns :- None
;**************************************************************************

UART_INIT:
	move.w  #N_ACLK,ASICLK       ;Set up baud rate
	move.w  #-1,d0
ui_wt1:
	dbra    d0,ui_wt1               ;Long wait to ensure that 
					;the last char is finished.
ui_wt:
	move.w  ASISTAT,d0
	btst    #U_SERIN,d0         ;Wait for serial input data to be
								;inactive
	beq     ui_wt               ;IF input data is NOT inactive, 
					;as you assign CLRERR, the UART 
					;WILL LOCK UP AND CAN ONLY BE 
					;RESTARTED BY POWER CYCLING


	move.w  #U_MCLRERR,ASICTRL ;now we can deal with errors nicely
	move.w  #U_MODD+U_MRINTEN,ASICTRL
	move.w	#16,J_INT
	move.w  ASIDATA,d0               ;Read out any old data
	move.w  ASIDATA,d0
	rts


;**************************************************************************
; UART_SEND
;
; Pointer to data to send in a0. Data as words, $ffff terminated
; 
;**************************************************************************


UART_SEND:
	clr.l	d1
	move.l	#crt_gpu_buffer,a1
.fill_buf:
	move.w	(a0)+,d1
	move.l	d1,(a1)+
	cmp.w	#$ffff,d1
	bne	.fill_buf
	move.l	#1, cortina_go
.cwait:
	move.l	cortina_go,d1
	cmp.w	#0,d1
	bne	.cwait
	rts

UART_68K_SEND:
	clr.l	d1
.send_loop:
	move.w  ASISTAT,d1
	btst    #U_TBE,d1
	beq     .send_loop
	move.w	(a0)+,d1
	cmp.w	#$ffff,d1
	beq	.nowait
	move.w	d1,ASIDATA
	bra	.send_loop
.nowait:	
	rts

;**************************************************************************
; UART_RECV
;**************************************************************************

UART_RECV:
	subq.l	#1,d0
recv_loop:
	move.w  ASISTAT,d1
	btst    #U_RBF,d1	  	; Wait for serial input data
	beq     recv_loop 
	move.w	ASIDATA,d1
	move.b	d1,(a0)+
	dbra	d0,recv_loop
	rts


UART_REC_ACK:
	move.w  ASISTAT,d1
	btst    #U_RBF,d1		; Wait for serial input data
	beq     UART_REC_ACK 
	move.w	ASIDATA,d0
	rts



;**************************************************************************
;***  Init Cortina
;**************************************************************************
_crt_init::
	move.l	#$00000008,$00f02114			; Stop the GPU

; break Cortina
	move	#U_MTXBRK,ASICTRL
; Copy the GPU program
	move.l	#CORTINA_COPY,a0
	move.l	(a0)+,a1				; Get load address
	move.l	(a0)+,d1				; and length
	asr.l	#2,d1
	subq.l	#1,d1
.1:
	move.l	(a0)+,(a1)+
	dbra	d1,.1

; zero all buffers and buffer pointers
	move.l	#__crt_buf_start,a0
	move.l	#(__crt_buf_end-__crt_buf_start)/4,d0
.2:
	move.l	#0,(a0)+
	dbra	d0,.2

	move.l	#0,_crt_kbd_stat
	
	move.l	#GPU_Go,$00f02110
	move.l	#$00000011,$00f02114	; Set the GPU going


	move.w  #2188,d0		; 3ms
.4:
	dbra    d0,.4           	; short wait to ensure that 
	move.w  #0,ASICTRL		;end the silly break

	move.w  #0,mouseDatTop		; empty mouse data buffer
 
	rts


;************************************************************************
;*** _crt_sndcmd(char *command, short response, short timeout)
;************************************************************************
 
_crt_sndcmd:
	link	a6, #0
	movem.l	a2-a5/d2-d6,-(sp)

.sendIt:
	move.l	8(a6),a0
	jsr	UART_SEND

	; wait for reply
	move.w	12(a6),d0
	movea.l	#_crt_gen_buf,a2
	move.l	_crt_gen_rdix,d2
	add.l	d2,a2
.1:
	move.l	d0,d3		;to avoid div by 0
	divs	d3,d4		;get the hell off the bus
	move.l	_crt_gen_wrix,d1
	cmp.l	d2,d1
	beq	.1

; get it!!
	move.b	(a2)+, d1
	addq.l	#1,d2
	cmp.w	d0,d1	;is it it?
	beq	.done

; check for bad stuf
	cmpi.w	#$8a,d1
	beq	.badxmit
	cmpi.w	#$8b,d1
	beq	.badxmit
	cmpi.w	#$8c,d1
	beq	.badxmit
;it something else .. ? ... keep looking
	bra	.1
.done:
	move.l	d2,_crt_gen_rdix
	movem.l	(sp)+,a2-a5/d2-d6
	unlk	a6
	rts

;go here if something bad was recieved
.badxmit:
	move.l	#$ffff,d1
.icky:
	nop
	dbra	d1,.icky
	move.l	d2,_crt_gen_rdix
	bra	.sendIt

;************************************************************************
;*** _crt_getkbd()
;************************************************************************

#define DATA		d0
#define COUNT		d1
#define NBYTES		d2
#define READINDX	d3
#define INCMD		d4
#define BREAK		d5
#define KSTAT		d6
#define FLAG		d7

#define KEYBDPTR	a0
#define SCANCODE	a1
#define TMP		a2

_crt_getkbd:
	movem.l	d1-d7/a0-a1,-(sp)
	clr.l	FLAG
	clr.l	INCMD
	clr.l	BREAK
	clr.l	NBYTES
	clr.l	DATA
.kwait:
	move.l	_crt_kbd_wrix, COUNT		;is data in the buffer?
	move.l	_crt_kbd_rdix,  READINDX
	ext.l	READINDX
	sub.w	READINDX, COUNT
	bpl	.l0
	add.w	#CRT_KBD_BUFSIZE, COUNT
.l0:
	cmp.w	#0, COUNT
	beq	.kwait				; no data, then wait
	subq.w	#1, COUNT

	lea	_crt_kbd_buf,KEYBDPTR
.loop:

	move.b	(KEYBDPTR,READINDX),DATA	; get data
	addq.w	#1, READINDX
	cmp.w	#CRT_KBD_BUFSIZE, READINDX		; wrapped?
	blt	.l1
	move.w	#0, READINDX			; reset index
.l1:
	cmp.w	#1, INCMD
	beq	.incmd
	
	move.b 	DATA, NBYTES
	sub.w	#($a7), NBYTES	  ; get number of following bytes ($a8 - $1)
	move.w	#1, INCMD
	bra	.loopend
.incmd:
	subq.w	#1, NBYTES

	cmp.b	#$f0, DATA			; is it a break code?
	bne	.l2
	move.w	#1, BREAK
	bra	.loopend
.l2:	
	cmp.w	#KBDCODE_SHIFT1, DATA			; is it shift
	beq	.l2x
	cmp.w	#KBDCODE_SHIFT2, DATA			; is it shift
	bne	.l3
.l2x:
	cmp.w	#1, BREAK			; release?
	bne	.l2a
	bclr	#0, _crt_kbd_stat+3
	move.w	#0, BREAK
	bra	.loopend
.l2a:
	bset	#0, _crt_kbd_stat+3
	bra	.loopend
.l3:	
	lea	scan_code,SCANCODE	;get right scancode table
	move.l	_crt_kbd_stat,KSTAT	;(according to the keyboard state)
	asl.l	#7,KSTAT
	add.l	KSTAT,SCANCODE
	move.w	DATA, TMP
	swap	DATA
	move.w	TMP, DATA
	move.b	(SCANCODE, DATA), DATA
	move.w	#1, FLAG
	bra	.loopout
.loopend:
	cmp.w	#0, NBYTES
	bne	.l4
	clr.w	INCMD
.l4:
	dbra COUNT, .loop
.loopout:
	move.l	READINDX,_crt_kbd_rdix
	cmp.w	#0, NBYTES		; did we get everything?
	bne	.kwait	

	cmp.w	#1, FLAG		; anything real?
	bne	.kwait	


	movem.l	(a7)+,d1-d7/a0-a1
	rts

;************************************************************************
;*** _crt_getaux()
;************************************************************************

#define DATA		d0
#define COUNT		d1
#define NBYTES		d2
#define READINDX	d3
#define INCMD		d4
#define BREAK		d5
#define KSTAT		d6
#define FLAG		d7

#define MODEMPTR	a0


_crt_getaux:
	movem.l	d1-d7/a0-a1,-(sp)
	clr.l	FLAG				; register setup


	lea	_crt_aux_buf,MODEMPTR		; register setup
	move.l	_crt_aux_wrix, COUNT		
	move.l	_crt_aux_rdix,  READINDX
	sub.l	READINDX, COUNT

	move.w	_crt_aux_incmd, INCMD		; register setup
	move.w	_crt_aux_nbytes, NBYTES
	move.w	_crt_aux_break, BREAK		; register setup

	cmp	#0, NBYTES			; do we still have data from
	bne 	.loop				; the last command?

.mwait:
	move.l	_crt_aux_wrix, COUNT		;is data in the buffer?
	move.l	_crt_aux_rdix,  READINDX
	sub.l	READINDX, COUNT
	bpl	.l0
	add.l	#CRT_AUX_BUFSIZE, COUNT
.l0:
	cmp.l	#0, COUNT
	beq	.mwait				; no data, then wait
	subq.l	#1, COUNT

.loop:

	move.b	(MODEMPTR,READINDX),DATA	; get data
	addq.w	#1, READINDX
	cmp.w	#CRT_AUX_BUFSIZE, READINDX		; wrapped?
	blt	.l1
	move.w	#0, READINDX			; reset index
.l1:
	cmp.w	#1, INCMD
	beq	.incmd
	
	move.b 	DATA, NBYTES
	sub.w	#$8f, NBYTES	  ; get number of following bytes ($90 - $1)
	move.w	#1, INCMD
	bra	.loopend
.incmd:
	subq.w	#1, NBYTES

	cmp.b	#$ff, DATA			; is it a break code?
	bne	.l2
	move.w	#1, BREAK
	bra	.loopend

	cmp.w	#1, BREAK			; error
	bne	.l2
	move.w	#$ff, DATA			; for now, return -1
	move.w	#1, FLAG
	move.w	#0, INCMD
;xxxxx
;	insert error handling
;xxxxx
	bra	.loopend
.l2:
	move.w	#1, FLAG
	bra	.loopout
.loopend:
	cmp.w	#0, NBYTES
	bne	.l4
	clr.w	INCMD
.l4:
	dbra COUNT, .loop
.loopout:
	move.l	READINDX,_crt_aux_rdix

	cmp.w	#1, FLAG			; anything real?
	bne	.mwait	

	cmp.w	#0, NBYTES
	bne	.l5
	clr.w	INCMD
.l5:
	move.w	INCMD, _crt_aux_incmd		; register write back
	move.w	NBYTES, _crt_aux_nbytes
	move.w	BREAK, _crt_aux_break

	movem.l	(a7)+,d1-d7/a0-a1
	rts


;************************************************************************
;*** _crt_putaux()
;************************************************************************

#define DATA		d0
#define COUNT		d1
#define NBYTES		d2
#define READINDX	d3

#define MODEMPTR	a0


_crt_putaux:
	move.w	4(sp), DATA
	movem.l	d1/a0-a1,-(sp)

	move.w	#$7c, _crt_aux_sendcmd
	move.w	#$07, _crt_aux_sendcmd+2
	move.l	#_crt_aux_sendcmd+4, a0
	move.w	DATA,(a0)+
	move.w	#$ffff,(a0)
	lea	_crt_aux_sendcmd, a0
	move.w	#$74, (a0)+
	move.w	#$01, (a0)+
	move.w	#$ffff, (a0)
	lea	_crt_aux_sendcmd, a0
	jsr	UART_SEND
	movem.l	(sp)+,d1/a0-a1
	rts

;**************************************************************************
; _crt_kbdstat
; Input:  -
; Output: d0: 0=No data available, -1=min. one byte available
;**************************************************************************

_crt_kbdstat:
	movem.l	d1-d2,-(sp)
	move.l	_crt_kbd_wrix,d1
	move.l	_crt_kbd_rdix,d2
	cmp.l	d2,d1
	bne	.1
	move.l	#0,d0
	bra	.2
.1:
	move.l	#$ffffffff,d0
.2:
	movem.l	(sp)+,d1-d2
	rts


;**************************************************************************
; _crt_auxstat
; Input:  -
; Output: d0: 0=No data available, -1=min. one byte available
;**************************************************************************

_crt_auxstat:
	movem.l	d1-d2,-(sp)
	move.l	_crt_aux_wrix,d1
	move.l	_crt_aux_rdix,d2
	cmp.l	d2,d1
	bne	.1
	move.l	#0,d0
	bra	.2
.1:
	move.l	#$ffffffff,d0
.2:
	movem.l	(sp)+,d1-d2
	rts

;************************************************************************
;  _crt_mouse(&mouseEvent)
;	arg1 - address of mouseEvent struct (buttEdge,x,y,buttCur)
;

_crt_mouse:
	link	a6, #-4
	movem.l	a2-a5/d2-d6,-(sp)

	;clear edges
	move.l	8(a6), a3
	clr.w	(a3)

	;check for any data (in _crt_mouse_buf)
	move.l	_crt_mouse_wrix,d1
	move.l	_crt_mouse_rdix,d2
	cmp.l	d2,d1
	beq		.done

	;get the new data - put into mouseDat
	movea.l	#mouseDat, a0
	move.w	#64, d0	;num of chars
	clr.l	d1
	move.w	mouseDatTop, d1
	sub.w	d1, d0
	add.l	d1, a0
	move.l	#1, d1	;from mouse buffer (mouseBuf == buffer#1)
;	jsr	crtGetPortData
	add.w	mouseDatTop, d0


	;update the mouseEvent
	movea.l	#mouseEvt,a1
	clr.l	d7
	move.b	(a1)+,d7	;grab packetIndex
	move.l	8(a6), a3
	movea.l	#.switchTab, a2

	movea.l	#mouseDat, a0
	tst.w	d0
	beq		.aintNoMore
	subq.w	#1,d0
	beq		.aintNoMore
	.procBuffLp:
		move.b	(a0)+,d1	;get it
		;check for start
		btst	#6, d1
		bne	.bh1	;jump back to byte 1
		move.l	(a2,d7.w), a4
		jmp	(a4)
		.bh1:
			;byte 1
			clr.l	d7
			bclr.l	#6,d1 ; make room for third button
			move.b	d1,(a1) ;butts
			move	d1,d2
			lsl.b	#6,d2
			move.b	d2,1(a1) ;x
			and.b	#12,d1
			lsl.b	#4,d1
			move.b	d1,2(a1) ;y
			bra	.endSw
		.bh3:	;yes, they're out of order!
			;byte 3
			add.b	d1,2(a1)
			tst	d0
			beq	.outEvt
			move.b	(a0),d1	;check it
			btst	#6, d1
			bne	.outEvt	;packet is done
			bra	.endSw
		.bh4:
			;byte 4
			lsl.b	#1,d1
			and.b	d1,(a1)
			clr.l	d7 ;for security reasons
			bra	.endSw
		.bh2:
			;byte 2
			add.b	d1,1(a1)
			;and write
		.endSw:
		addq	#4,d7
		dbra	d0,.procBuffLp
	.lover:
	move.b	d7,mouseEvt
.aintNoMore:
	addq.w	#1,d0
	move.w	d0, mouseDatTop

.done:
	movem.l	(sp)+,a2-a5/d2-d6
	unlk	a6
	rts
.outEvt:
	;first update coords
	move.b	1(a1),d1	;x
	ext.w	d1
	add.w	d1,2(a3)	;x
	move.b	2(a1),d1	;y
	ext.w	d1
	add.w	d1,4(a3)	;y

	;next check buttons
	move.b	(a1),d1		;butts
	and	#$70, d1
;**	eor
;**	beq

	bra	.endSw
	.long
.switchTab:
	.dc.l	.bh1,.bh2,.bh3,.bh4







;**************************************************************************
;	Preinitialized Data
;**************************************************************************

	.data	


;**************************************************************************
;	PC Keyboard Scan Codes

	.phrase
scan_code:
	; no modifiers
	.dc.b	000,000,000,000,000,000,000,000,000,000,000,000,000,009,'`',000
	.dc.b	000,000,000,000,000,'q','1',000,000,000,'z','s','a','w','2',000
	.dc.b	000,'c','x','d','e','4','3',000,000,032,'v','f','t','r','5',000
	.dc.b	000,'n','b','h','g','y','6',000,000,000,'m','j','u','7','8',000
	.dc.b	000,',','k','i','o','0','9',000,000,'.',047,'l',';','p','-',000
	.dc.b	000,000,039,000,'[','=',000,000,000,000,013,']',092,000,000,000
	.dc.b	002,004,000,001,000,000,008,000,000,'1',003,'4','7',000,000,000
	.dc.b	'0','.','2','5','6','8',000,'/',000,013,'3',000,'+','9',000,'*'

	; shifted code set
	.dc.b	000,000,000,000,000,000,000,000,000,000,000,000,000,009,'~',000
	.dc.b	000,000,000,000,000,'Q','!',000,000,000,'Z','S','A','W','@',000
	.dc.b	000,'C','X','D','E','$','#',000,000,032,'V','F','T','R','%',000
	.dc.b	000,'N','B','H','G','Y','^',000,000,000,'M','J','U','&','*',000
	.dc.b	000,'<','K','I','O',')','(',000,000,'>','?','L',':','P','_',000
	.dc.b	000,000,'"',000,'{','+',000,000,000,000,013,'}','|',000,000,000
	.dc.b	002,004,000,001,000,000,008,000,000,'1',003,'4','7',000,000,000
	.dc.b	'0','.','2','5','6','8',000,'/',000,013,'3',000,'+','9',000,'*'
	

;**************************************************************************
;	Init Cortina Command String

crt_init_str:
	.dc.w	$73,$8b,$ffff	;interface setup - enable mouse,kbd,aux, 46K


;**************************************************************************
;	Uninitialized Data
;**************************************************************************
		.bss
		
		.phrase
__crt_buf_start:

_crt_kbd_stat:
		.ds.l			1
		
_crt_gen_wrix:
		.ds.l			1
_crt_aux_wrix:
		.ds.l			1
_crt_mouse_wrix:
		.ds.l			1
_crt_prt_wrix:
		.ds.l			1
_crt_kbd_wrix:
		.ds.l			1

_crt_gen_rdix:
		.ds.l			1
_crt_aux_rdix:
		.ds.l			1
_crt_mouse_rdix:
		.ds.l			1
_crt_prt_rdix:
		.ds.l			1
_crt_kbd_rdix:
		.ds.l			1
_crt_aux_incmd:
		.ds.w			1
_crt_aux_nbytes:
		.ds.w			1
_crt_aux_break:
		.ds.w			1

		.ds.w			1
_crt_aux_sendcmd:
		.ds.w			10
		
		.long
_crt_gen_buf:
		.ds.b           	CRT_STD_BUFSIZE
_crt_aux_buf:
		.ds.b			CRT_STD_BUFSIZE
_crt_mouse_buf:
		.ds.b			CRT_STD_BUFSIZE
_crt_prt_buf:
		.ds.b			CRT_STD_BUFSIZE
_crt_kbd_buf:
		.ds.b			CRT_KBD_BUFSIZE
__crt_buf_end:
		

mouseDat:	.ds.b	64
mouseDatTop:	.ds.w	1
mouseEvt:	.ds.b	8		;packetIndex,buttEdge,x,y,buttCur


		.end


