;******************************************************************************
;* (C)1993 ATARI CORP.       SECRET & CONFIDENTIAL       ALL RIGHTS RESERVED
;*
;*
;*				CDROM.S
;*
;* This MC68K program demonstrates the retrieval of extended R-W subcodes from
;* the CD, by using some of the subroutines presently available to drive the
;* Jaguar CD Module in standard CD audio playback mode.  
;* All calls to the CD Module are made as "jsrs".
;*
;* This program requires assembly and linking of the DSP program  'echo.gas'.
;*
;* The hardware assumptions here are a CDROM interface card Rev 2.0 mounted in
;* the 2 MB Sylvester Development System.
;*
;*				REVISION HISTORY
;*
;* REV.	DATE	   BY	DESCRIPTION OF EDIT
;* """"	""""	   ""	"""""""""""""""""""
;* 1.00  12 Nov 93  DMS   Based on CD_audio.s
;* 1.02  15 Dec 93  DMS   Update to test new Philips drive CD+G mode R-W codes
;* 2.01  10 Jan 94  DMS   Only store TW longwords.  Works fine.
;* 3.00  11 Jan 94  DMS   Interleave the subcode bits into low 6 of a longword
;*
;* 4.00	18 Feb 94  PKF	 Added the CDROM driver routines along with the
;*			 routines to control subcode flow for CD+G
;*			 All variables are relocatable
;******************************************************************************

;*============================================================================*
;* HEADER FILES								      *
;*============================================================================*

	.include 'jaguar.inc'		; cast in concrete for console
	.include 'cd_inits.inc'		; CD-related equates

;*============================================================================*
;* EXTERNAL DATA							      *
;*============================================================================*

	.extern	end			; needed for GPU program load by DB

;*============================================================================*
;* EXTERNAL ROUTINE							      *
;*============================================================================*

;*============================================================================*
;* PUBLIC DATA								      *
;*============================================================================*

	.globl	_CDGword

;*============================================================================*
;* PUBLIC ROUTINE							      *
;*============================================================================*

	.globl	HandleCD
	.globl	Subcode

;*============================================================================*
;* LOCAL EQUATES							      *
;*============================================================================*

DSP_stop	equ	$F1C310		; Stop-DSP semaphore from M68K

;******************************************************************************
;*	SUBROUTINES AREA						      *
;******************************************************************************

	.text

;*============================================================================*
;*============================================================================*

CDDATLEN	equ	1454400

aaHandleCD:
	jsr	Init_CD			; initialise CD variables

;	move.l	#0,BUTCH		; Butch enable 
;	move.l	#$10000,DSCNTRL		; turn on DSA Bus
;;	move.l	#$1e4,SBCNTRL		; preload PRN for subcode clock (0F2)
;;	move.l	#$3e4,SBCNTRL		; turn on the subcode counter (2F2)
;	move.l	#$7,I2CNTRL		; 5 = code, f = audio, b = from given start time
;
;	move.l	#$14,SMODE		; external clk, interrupt on every sample pair

;;	move.l	SBCNTRL,d0		; clear any pending frame ints
	rts

;*============================================================================*
;*============================================================================*

aaSubcode:
	movem.l	a0-a1/d0-d1,-(sp)

.inicode:
	move.l	Subcount,d0
	cmp.l	#CDDATLEN,d0
	bne.s	.cpycode
	move.l	#0,d0
.cpycode:
;	move.l	#$200000-CDDATLEN,a0
	move.l	#$804000,a0
	add.l	d0,a0

	move.l	#_CDGword,a1
	move.l	#0,d1
.cpyloop:
	move.b	#0,(a1)+
	move.b	(a0)+,(a1)+
	add.l	#1,d1
	cmp.l	#96,d1
	bne.s	.cpyloop
.endloop:
	add.l	#96,d0
	move.l	d0,Subcount
.retcode:
	movem.l	(sp)+,d0-d1/a0-a1
	rts

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

	.globl	_savesub
_savesub:
	move.l	#$200000-CDDATLEN,a0
	move.l	Subcount,d0
	add.l	d0,a0

	move.l	#_CDGword,a1
	move.l	#95,d1
.cpyloop:
	move.w	(a1)+,d2
	move.b	d2,(a0)+
	dbra	d1,.cpyloop

	add.l	#96,d0
	move.l	d0,Subcount
	cmp.l	#CDDATLEN,d0
	bne.s	.retsave
	move.l	#$0,SBCNTRL		; turn on the subcode counter (2F2)
	illegal
.retsave:
	rts

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

;*============================================================================*
;* HandleCD :	Handle CD+G type discs					      *
;*============================================================================*

HandleCD:
	movem.l	a0-a6/d0-d7,-(sp)

;****************************************
;* Clear our own memory range		*
;****************************************

.Clearmem:
	move.l	#CD_TOC,a0		; our lowest DRAM address in this file
	move.l	#DRAM_end,d1		; our highest DRAM address
.clermem1:				; clear CD variables and data buffer area
	move.l	#0,(a0)+
	move.l	a0,d0
	cmp.l	d0,d1
	bne	.clermem1

;****************************************
;* Initialize CD-variables		*
;****************************************

	jsr	Init_CD			; initialise CD variables

;****************************************
;* Play audio from CD			*
;****************************************

.Do_CDG:				; CD+G audio track playback demo
	jsr	CDmode_g		; setup Jerry's i2s port and clocks

;****************************************
;* Load DSP program			*
;****************************************

.Run_DSP:				; leonard's thing
	move.l	#end,a0
	move.l	(a0)+,d0		; final location of DSP code
	move.l	d0,a1
	move.l	d0,d5
	move.l	(a0)+,d0		; size in bytes
	asr.l	#2,d0
.xferloop:
	move.l	(a0)+,(a1)+
	dbra	d0,.xferloop

;****************************************
;* Initialize & run DSP program		*
;****************************************

.DSP_init:
	move.l	d5,D_PC			; set DSP PC to start of code in SRAM
	move.l	#0,DSP_stop		; semaphore to tell DSP to stop itself
	move.l	#1,D_CTRL		; set DSP GO bit to start running

;****************************************
;* Play a track on the CD		*
;****************************************

.Play_it:				; DSP's running.  Now start disc
	jsr	Pause_CD
	move.l	#1,d1			; play track #n
	jsr	Play_CD
	jsr	UnpausCD

	move.l	#$0F2,SBCNTRL		; preload PRN for subcode clock (0F2)
	move.l	#$2F2,SBCNTRL		; turn on the subcode counter (2F2)
	move.l	#$7,I2CNTRL		; 5 = code, f = audio, b = from given start time

;****************************************
;* Clear any frame intr, if pending	*
;****************************************

;.FrmIntr:
;	move.l	#$1000,d0
;.wtlup:
;	move.l	SBCNTRL,d1		; clear any pending frame ints
;	dbra	d0,.wtlup

;****************************************
;* Stop CD and DSP, then exit		*
;****************************************

Fini:
;	jsr	Stop_CD			; stop drive
;	move.l	#1,DSP_stop		; semaphore to tell DSP to stop itself
	movem.l	(sp)+,d0-d7/a0-a6
	rts

;______________________________________________________________________________
;______________________________________________________________________________

;****************************************
;* Fill up a DRAM block with CD subcode	*
;****************************************

Subcode:
	move.l	#_CDGword,a0		; pointer to symbol list
	move.l	#SUBDATA,a1		; address of subcode low data reg in Butch
	move.l	#SUBDATB,a2		; address of subcode hi data reg in Butch
	move.l	#$10,d7			; first expected subcode type

.Sub_int:				; see if subcode chunk is ready
	move.l	BUTCH,d0		; get contents of int control reg
	btst.l	#10,d0			; see if subdata bit is set
	beq.s	.Sub_int		; wait till it is

.Sub_cod:
	move.l	(a1),d0			; d0 = SRxQ
	move.l	(a2),d2			; d1 = WVUT
	move.l	SBCNTRL,d1		; read to clear int flag

.Sub_cmp:
	cmp.b	d0,d7			; check if the subcode is as expected
	beq.s	.Sub_dne		; accept the subcode, if so

.Sub_can:
	sub.l	#$10,d7			; get the number of subcode reads so far
	mulu	#$10,d7			; 16 bytes for 8 symbols/each subcode read
	sub.l	d7,a0			; restore the pointer to symbol list
	move.l	#$10,d7			; next expected subcode
	bra.s	.Sub_int		; check for next subcode

.Sub_dne:
	move.l	d7,-(sp)		; save d7

	move.l	d0,d1			; d0 = Srxx	- Used for S
	swap	d1			; d1 = xxsR	- Used for R
	move.l	d2,d3			; d2 = Wvut	- Used for W
	swap	d3			; d3 = utwV	- Used for V
	move.l	d2,d4			; d4 = wvUt	- Used for U
	move.l	d2,d5			; d5 = wvuT	- Used for T

	move.w	#7,d7			; 8 symbols per subcode read
.Sub_smb:
	clr.w	d6			; make symbol in d6
	roxl.b	#1,d1			; get the R bit
	roxl.b	#1,d6			; result = 0000000r
	roxl.l	#1,d0			; get the S bit
	roxl.b	#1,d6			; result = 000000rs
	roxl.b	#1,d5			; get the T bit
	roxl.b	#1,d6			; result = 00000rst
	roxl.w	#1,d4			; get the U bit
	roxl.b	#1,d6			; result = 0000rstu
	roxl.b	#1,d3			; get the V bit
	roxl.b	#1,d6			; result = 000rstuv
	roxl.l	#1,d2			; get the W bit
	roxl.b	#1,d6			; result = 00rstuvw
	move.w	d6,(a0)+		; save it in buffer
	dbra	d7,.Sub_smb		; get next symbol

.Sub_nxt:
	move.l	(sp)+,d7		; restore d7
	addi.l	#$1,d7			; next subcode type expected
	cmp.l	#$1C,d7			; if all subcodes for the current
	blt	.Sub_int		; wait for next subcode
.Sub_ret:
	rts				; end of Subcode routine

;______________________________________________________________________________
;||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
;				SUBROUTINES

;****************************************
;* Initialize CD-variables		*
;****************************************

Init_CD:
	clr.l	d0

	; initialise CD_TOC area too

	move.l	d0,CD_base

	move.l	d0,CD_found
	move.l	d0,CD_stat	
	move.l	d0,CD_error
	move.l	d0,CDcutlnL
	move.l	d0,CDcutlnH
	move.l	d0,CD_track
	move.l	d0,CD_index
	move.l	d0,CD_Rmins
	move.l	d0,CD_Rsecs
	move.l	d0,CD_Amins
	move.l	d0,CD_Asecs
	move.l	d0,CD_Afrms
	move.l	d0,CD_setup
	move.l	d0,CDTOCbeg
	move.l	d0,CDTOCend
	move.l	d0,CDTOCmin
	move.l	d0,CDTOCsec
	move.l	d0,CDTOCfrm
	move.l	d0,CDseshns
	move.l	d0,CDcutnum
	move.l	d0,CDcutCAB
	move.l	d0,CDcutstm
	move.l	d0,CDcutsts
	move.l	d0,CDcutstf
	move.l	d0,CD_DAC

	move.l	d0,CD_wrd0	

	move.l	d0,CDfatals
	move.l	d0,CDmaybes

	move.l	d0,CD_retry
	move.l	d0,PS_flag	

	move.l	d0,Init_cut
	move.l	d0,CD_mode	
	move.l	d0,DAC_mode

	move.w	d0,Strt_min
	move.w	d0,Strt_sec
	move.w	d0,strt_frm
	move.w	d0,Stop_min
	move.w	d0,Stop_sec
	move.w	d0,Stop_frm

	move.w	d0,Waittime
	move.w	d0,Session

	move.l	#0,CD_count

	move.l	#0,Subcount
	rts

;****************************************
;* Setup CD Module for Mode G, Audio+G	*
;****************************************

CDmode_g:				; init for CD+G mode
.setibit:				; can't write to CD Module before setting the I/O bit
;	move.w	#$1865,MEMCON1		; in Tom's base register value to read ROM1 space
;.set_moto:
;	move.l	#$00070007,D_END	; make damn sure we're Motorola-way
;	move.l	#$00070007,G_END	; make damn sure we're Motorola-way
.do_butch:				; initialise jerry/butch stuff
	move.l	#0,BUTCH		; Butch enable 
	move.l	#$10000,DSCNTRL		; turn on DSA Bus

;	move.l	#$1000610,SB_TIME	; start at min:sec:frm
.setmode:
	move.l	#$14,SMODE		; external clk, interrupt on every sample pair
.interpol:				; interpolate audio data errors
	move.w	#$1501,DS_DATA		; DSA command
	jsr	DSA_rx
.setDAC:
	move.w	#$7002,DS_DATA		; output audio data at 2X oversampled
	jsr	DSA_rx
	rts

;****************************************
;* Setup CD Module for Mode 1, CD ROM	*
;****************************************

CDmode_1:
.setibit:				; can't write to CD Module before setting the I/O bit
	move.w	#$1865,MEMCON1		; in Tom's base register value to read ROM1 space
.setmotor:				; make damn sure we're Motorola-way
	move.l	#$00070007,D_END
	move.l	#$00070007,G_END	; make damn sure we're Motorola-way
.do_butch:				; initialise jerry/butch stuff
	move.l	#$0,BUTCH		; Butch enable 
	move.l	#$10000,DSCNTRL		; turn on DSA Bus
	move.l	#5,I2CNTRL		; 5 = code, f = audio 

.init_CDR:				; no interpolation, double-speed spindle
	move.w	#$150A,DS_DATA		; send to Butch
	jsr	DSA_rx			; get response
.Chekmode:				; verify CD is in mode 0A
	move.l	CD_wrd0,d0
	cmp.l	#$0000170A,d0
	bne	.init_CDR		; hang forever if CD won't get it right
	rts

;****************************************
;* Setup CD Module Mode 2,CD ROM-Jerry	*
;****************************************

CDmode_2:
.setibit:				; can't write to CD Module before setting the I/O bit
	move.w	#$1865,MEMCON1		; in Tom's base register value to read ROM1 space
.setmotor:				; make damn sure we're Motorola-way
	move.l	#$00070007,D_END
	move.l	#$00070007,G_END	; make damn sure we're Motorola-way
.do_butch:				; initialise jerry/butch stuff
	move.l	#$0,BUTCH		; Butch enable 
	move.l	#$10000,DSCNTRL		; turn on DSA Bus
	move.l	#$7,I2CNTRL		; i2s on, copy to jerry, forced, 16-bit master

.setmode:
	move.l	#$14,SMODE		; external clk, interrupt on every sample pair

.DSAoff2X:				; DSA in 'shut-up' mode, 2 x spindle speed
	move.w	#$150A,DS_DATA		; DSA command
	jsr	DSA_rx
.Chekmode:				; verify CD is in mode 0A
	move.l	CD_wrd0,d0
	cmp.l	#$0000170A,d0
	bne	.DSAoff2X		; hang forever if CD won't get it right
	rts

;****************************************
;* Setup CD Module for Mode 4, Audio	*
;****************************************

CDmode_4:				; init for audio (mode 2)
.setibit:				; can't write to CD Module before setting the I/O bit
	move.w	#$1865,MEMCON1		; in Tom's base register value to read ROM1 space
.setmotor:				; make damn sure we're Motorola-way
	move.l	#$00070007,D_END
	move.l	#$00070007,G_END	; make damn sure we're Motorola-way
.do_butch:				; initialise jerry/butch stuff
	move.l	#$0,BUTCH		; Butch enable
	move.l	#$10000,DSCNTRL		; turn on DSA Bus
	move.l	#$f,I2CNTRL		; 5 = code, f = audio

.make_clk:				; Init serial clk frequency to...
	move.l	#2,SCLK			; 2(N+1) = 6	26/6 =~ 4.3 MHz
.setmode:
	move.l	#$14,SMODE		; external clk, interrupt on every sample pair

.interpol:				; interpolate audio data errors
	move.w	#$1501,DS_DATA		; DSA command
	jsr	DSA_rx
.setDAC:				; output audio data at 2x oversampled
	move.w	#$7002,DS_DATA		; DSA command
	jsr	DSA_rx
	rts

;****************************************
;* i2s data copy to Jerry on/off	*
;* Input : d1				*
;****************************************

Jeridata:				; d1 must have a 1 or a 0 in it
.setibit:				; can't write to CD Module before setting the I/O bit
	move.w	#$1865,MEMCON1		; in Tom's base register value to read ROM1 space
.setmotor:				; make damn sure we're Motorola-way
	move.l	#$00070007,D_END
	move.l	#$00070007,G_END	; make damn sure we're Motorola-way
.test_d1:
	cmp.l	#1,d1
	beq	.Jcp_on

.Jcp_off:
	move.l	#$0,BUTCH		; Butch enable
	move.l	I2CNTRL,d0		; get contents of i2s control reg
	and.l	#$FFFFFFFC,d0		; clear bit-0 and bit-1
	move.l	d0,I2CNTRL		; do it
	rts				; end of i2s data off subroutine

.Jcp_on:
	move.l	#$0,BUTCH		; Butch enable
	move.l	I2CNTRL,d0		; get contents of i2s control reg
	or.l	#$00000003,d0		; set bit-0 and bit-1 (Jerry copy-on bits)
	move.l	d0,I2CNTRL		; do it
	rts				; end of i2s data on subroutine

;****************************************
;* Use service mode to debug drive	*
;****************************************

Service:				; some code to test service modes
	move.w	#$F001,DS_DATA		; kick into service mode
	jsr	DSA_rx
	move.w	#$F301,DS_DATA		; turn on laser, try to focus it, run motor
	jsr	DSA_rx
	move.w	#$F000,DS_DATA		; turn off service mode
	rts

;****************************************
;* Command CD to spin-up		*
;* Input : d1				*
;****************************************

Spin_CD:				; spin-up command
	cmp.l	#0,d1			; check for user-selection of mode
	bne	.sessions		; not 0, jump to multi-session mode

.single:				; start-up normal disc
	move.w	#$1800,d1
	move.w	d1,DS_DATA		; Spins up on first TOC
	jsr	DSA_rx
	rts				; end of spin-up-normal command

.sessions:				; start-up multi-session on specified session
	or.w	#$1800,d1		; session number must be in d1
	move.w	d1,DS_DATA
	jsr	DSA_rx
	rts				; end of spin-up-multi-session command

;****************************************
;* Command CD to play in 1 of 3 forms	*
;* Input : d1/d2/d3			*
;****************************************

					; 3-way switch for Play, Play @, & Play A-B
Play_CD:				; call play command with track number in d1
	cmp.l	#0,d1			; see if user has cleared d1
	bne	.playtrak		; not 0, ie. has track number, so go play it

.maybe_AB:
	cmp.l	#0,d3			; if d3 has target value, user wants A-B play
	bne	.AB_play		; branch to A-B play mode

.gotimeCD:				; d3 was 0 so play from user's time-code setup
	move.l	d2,d4			; safe copy of d2
	and.l	#$00FF0000,d2		; mask for minutes
	ror.l	#8,d2			; shift the byte over
	ror.l	#8,d2
	or.w	#$1000,d2		; format it for goto
	move.w	d2,DS_DATA		; DSA tx
	jsr	DSA_tx			; wait till sent before sending next 1

	move.l	d4,d2			; restore d2
	and.l	#$0000FF00,d2		; mask for seconds
	ror.l	#8,d2
	or.w	#$1100,d2		; format it for goto
	move.w	d2,DS_DATA		; DSA tx
	jsr	DSA_tx			; wait till sent before sending next 1

	move.l	d4,d2			; restore d2
	and.l	#$000000FF,d2		; mask for frames
	or.w	#$1200,d2		; format it for goto
	move.w	d2,DS_DATA		; DSA tx
	jsr	DSA_rx			; verify receipt 
	rts				; end of goto time and play command

.playtrak:				; play a track 
	or.w	#$0100,d1		; no pause, format for DSA play-track command
	move.w	d1,DS_DATA		; DSA TX command to play track specified
	jsr	DSA_rx			; get response
	rts				; end of play-track

.AB_play:
	move.l	d2,d4			; safe copy of whole start time in d4
	and.l	#$00FF0000,d2		; mask for minutes
	ror.l	#8,d2			; shift the byte over
	ror.l	#8,d2
	or.w	#$2000,d2		; format it for play A-B
	move.w	d2,DS_DATA		; DSA tx
	jsr	DSA_tx			; wait till sent before sending next 1

	move.l	d4,d2			; bring in copy of original user value of d2
	and.l	#$0000FF00,d2		; mask for seconds
	ror.l	#8,d2
	or.w	#$2100,d2		; format it for play A-B
	move.w	d2,DS_DATA		; DSA tx
	jsr	DSA_tx			; wait till sent before sending next 1

	move.l	d4,d2			; bring in copy of original user value of d2
	and.l	#$000000FF,d2		; mask for frames
	or.l	#$2200,d2		; format it for play A-B
	move.w	d2,DS_DATA		; DSA tx
	jsr	DSA_tx			; wait till sent before sending next 1

	move.l	d3,d4			; safe copy of whole stop time in d4
	and.l	#$00FF0000,d3		; mask for minutes
	ror.l	#8,d3			; shift the byte over
	ror.l	#8,d3
	or.w	#$2300,d3		; format it for play A-B
	move.w	d3,DS_DATA		; DSA tx
	jsr	DSA_tx			; wait till sent before sending next 1

	move.l	d4,d3			; bring in copy of original user value of d3
	and.l	#$0000FF00,d3		; mask for seconds
	ror.l	#8,d3
	or.w	#$2400,d3		; format it for play A-B
	move.w	d3,DS_DATA		; DSA tx
	jsr	DSA_tx			; wait till sent before sending next 1

	move.l	d4,d3			; bring in copy of original user value of d3
	and.l	#$000000FF,d3		; mask for frames
	or.l	#$2500,d3		; format it for play A-B
	move.w	d3,DS_DATA		; DSA tx
	jsr	DSA_rx			; verify receipt 
	rts				; end of Play A_B command

;****************************************
;* Command CD to stop			*
;****************************************

Stop_CD:			
	move.w	#$0200,DS_DATA		; DSA TX command to stop
	jsr	DSA_rx
	rts				; end of stop command

;****************************************
;* Command CD to mute the decoder	*
;****************************************

Mute_CD:			
	move.w	#$5100,DS_DATA		; DSA TX command to mute
	jsr	DSA_rx
	rts				; end of mute command

;****************************************
;* Command CD to un-mute the decoder	*
;****************************************

UnmuteCD:
	move.w	#$51FF,DS_DATA		; DSA TX command to un-mute
	jsr	DSA_rx
	rts				; end of un-mute command

;****************************************
;* Command CD to pause			*
;****************************************

Pause_CD:
	move.w	#$0400,DS_DATA		; DSA TX command to pause
	jsr	DSA_rx
	rts				; end of pause command

;****************************************
;* Command CD to un-pause		*
;****************************************

UnpausCD:
	move.w	#$0500,DS_DATA		; DSA TX command to un-pause
	jsr	DSA_rx
	rts				; end of un-pause command

;****************************************
;* Command CD to send ABS timecode	*
;****************************************

Get_time:				; send-absolute-timecode command
	move.w	#$0D00,DS_DATA
	jsr	DSA_rx			; receive 3 times to get min:sec:frm
	jsr	DSA_rx
	jsr	DSA_rx
	rts				; end of get-time command

;****************************************
;* Command CD to send no. of sessions	*
;****************************************

Seshn_CD:				; send the number of sessions on disc
	move.w	#$5400,DS_DATA
	jsr	DSA_rx
	rts				; end of get-sessions command


;****************************************
;* Command CD to kill its A-B flags	*
;****************************************

KillCDAB:
	move.w	#$2600,DS_DATA
	jsr	DSA_rx
	rts				; end of kill A-B flags command

;****************************************
;* Command CD to search forward		*
;****************************************

ForwrdCD:				; low byte of d4 sets search mode
	or.l	#$0600,d4		; gets user's search mode byte
	move.w	d4,DS_DATA		; DSA TX command to search
	jsr	DSA_rx
	rts				; end of search command

;****************************************
;* Command CD to search backward	*
;****************************************

BckwrdCD:				; low byte of d4 sets search mode
	or.l	#$0700,d4		; gets user's search mode byte
	move.w	d4,DS_DATA		; DSA TX command to search
	jsr	DSA_rx
	rts				; end of search command

;****************************************
;* Command CD to stop searching		*
;****************************************

NosrchCD:			
	move.w	#$0800,DS_DATA		; DSA TX command to stop searching
	jsr	DSA_rx
	rts				; end of stop-search command

;****************************************
;* Command CD to send TOC min-max	*
;****************************************

CDminmax:				; returns first, last cut nums & endtime
	or.l	#$0300,d4		; get user's session number
	move.w	d4,DS_DATA
	jsr	DSA_rx			; gets min cut number
	jsr	DSA_rx			; gets max cut number
	jsr	DSA_rx			; gets end min
	jsr	DSA_rx			; gets end sec
	jsr	DSA_rx			; gets end frame
	rts				; end of CDminmax command

;****************************************
;* Command CD to send whole TOC		*
;****************************************

CDbigTOC:				; gets the entire table of contents
	move.l	#CD_TOC,a0		; setup address of start of TOC storage area
	or.l	#$1400,d4		; get user's session number
	move.w	d4,DS_DATA		; note that CDminmax must be called first

.GetItem:				; receive a TOC entry
	jsr	DSA_rx			; gets cut number
	jsr	DSA_rx			; gets control and address byte
	jsr	DSA_rx			; gets start min of cut
	jsr	DSA_rx			; gets start sec
	jsr	DSA_rx			; gets start frame

	move.l	CDcutnum,(a0)+		; Save another valid TOC entry to memory
	move.l	CDcutCAB,(a0)+
	move.l	CDcutstm,(a0)+
	move.l	CDcutsts,(a0)+
	move.l	CDcutstf,(a0)+

	move.l	CDcutnum,d1		; the current cut number
	and.l	#$FF,d1			; mask for low byte
	move.l	CDTOCend,d2		; get highest cut number known to be on CD
	and.l	#$FF,d2			; mask for low byte
	cmp.l	d1,d2			; compare 'em
	bne	.GetItem		; go get the next TOC entry
	rts				; end of CDbigTOC command

;****************************************
;* Command CD to send status of disc	*
;****************************************

Stat_CD:			
	move.w	#$5000,DS_DATA
	jsr	DSA_rx
	rts				; end of send-disc-status command

;****************************************
;* Command CD to send cut length	*
;****************************************

CtlnthCD:				; low byte of d4 must have cut $number
	or.l	#$0900,d4		; gets user's cut number byte
	move.w	d4,DS_DATA		; DSA TX command to search
	jsr	DSA_rx			; do rx twice to get low byte, high byte
	jsr	DSA_rx			; the value of the word is $seconds
	rts				; end of get-cut-length command

;****************************************
;* DSA error handler			*
;****************************************

GetCDerr:				; gets & classifies most recent error
	move.w	#$1600,DS_DATA		; request error code
	jsr	DSA_rx			; receive it
	move.l	CD_error,d1		; analyze it
	and.l	#$FF,d1			; low byte only, please
	cmp.l	#0,d1			; if it's 0 there's no error...
	beq	.Clearerr		; so blow out of here, otherwise...
	cmp.l	#$1F,d1			; see if its fatal or not
	bge	.Retry_OK		; not fatal

.Fatals:
	move.l	CDfatals,d0		; get current number of fatal errors
	add.l	#1,d0			; increment
	move.l	d0,CDfatals		; store it
	bra	.Clearerr		; done
	
.Retry_OK:
	move.l	CDmaybes,d0		; get current number of retry-able errors
	add.l	#1,d0			; increment
	move.l	d0,CDmaybes		; store it

.Clearerr:
	move.w	#$1700,DS_DATA		; ask CD to clear error its register
	jsr	DSA_rx
	rts				; end of DSA error handler

;****************************************
;* Transmit a DSA Bus command		*
;****************************************

DSA_tx:					; set up as a polling loop
	move.l	BUTCH,d1		; get Butch's ICR into d1
	and.l	#$1000,d1		; mask for bit-12, DSA TX Intr. pending
	beq	DSA_tx			; nothing here yet, so wait for bit to set 
	bra	sort_CD			; parse the DSA response

;****************************************
;* Receive DSA Bus response & parse it	*
;****************************************

DSA_rx:					; set up as a polling loop
	move.l	BUTCH,d1		; get Butch's ICR into d1
	and.l	#$2000,d1		; mask for bit-13, DSA RX Intr. pending
	beq	DSA_rx			; nothing here yet, so wait for bit to set 

;****************************************
;* Sets different variables depending	*
;* upon the command received from drive	*
;* Commands are decoded per DSA spec.	*
;****************************************

sort_CD:
	move.w	DS_DATA,d1		; flag set, so get the word from Butch
	move.l	d1,CD_wrd0		; store it where we can see it for debugging
	move.l	DSCNTRL,d5		; read here to clear interrupt flag

	move.l	d1,d2			; save d1 in d2
	andi.l	#$FF00,d1		; mask to see hi byte only

.cmnd_01:				; parse it
	cmp.l	#$0100,d1		; test
	bne	.Found			; found "found" message

.cmnd_03:				; parse it
	cmp.l	#$0300,d1		; test
	beq	.Discstat		; found "disc status" message

.cmnd_04:				; parse it
	cmp.l	#$0400,d1		; test
	beq	.Error			; found "error" message

.cmnd_09:				; parse it
	cmp.l	#$0900,d1		; test
	beq	.CutlenL		; found "cut-length low byte of seconds" 

.cmnd_0A:				; parse it
	cmp.l	#$0A00,d1		; test
	beq	.CutlenH		; found "cut-length high byte of seconds"

.cmnd_10:				; parse it
	cmp.l	#$1000,d1		; test
	beq	.Track			; found "track number"

.cmnd_11:
	cmp.l	#$1100,d1		; test
	beq	.Index			; found "index"

.cmnd_12:
	cmp.l	#$1200,d1		; test
	beq	.Rel_mins		; found "rel. minutes"

.cmnd_13:
	cmp.l	#$1300,d1		; test
	beq	.Rel_secs		; found "rel. seconds"

.cmnd_14:
	cmp.l	#$1400,d1		; test
	beq	.Abs_mins		; found "abs. minutes"

.cmnd_15:
	cmp.l	#$1500,d1		; test
	beq	.Abs_secs		; found "abs. seconds"

.cmnd_16:
	cmp.l	#$1600,d1		; test
	beq	.Frames			; found "frames"

.cmnd_17:
	cmp.l	#$1700,d1		; test
	beq	.Mode			; found "mode"

.cmnd_20:
	cmp.l	#$2000,d1		; test
	beq	.Firs_trk		; found "first track number in TOC"

.cmnd_21:
	cmp.l	#$2100,d1		; test
	beq	.Last_trk		; found "last track number in TOC"

.cmnd_22:
	cmp.l	#$2200,d1		; test
	beq	.End_mins		; found "last minute of last track in this TOC"

.cmnd_23:
	cmp.l	#$2300,d1		; test
	beq	.End_secs		; found "last second of last track in this TOC"

.cmnd_24:
	cmp.l	#$2400,d1		; test
	beq	.Endframe		; found "last frame of last track in this TOC"

.cmnd_54:
	cmp.l	#$5400,d1		; test
	beq	.Sessions		; found "Number of Sessions on disc message"

.cmnd_60:
	cmp.l	#$6000,d1		; test
	beq	.Cutnum			; found "TOC cut number"

.cmnd_61:
	cmp.l	#$6100,d1		; test
	beq	.CutCAB			; found "TOC cut control and address byte"

.cmnd_62:
	cmp.l	#$6200,d1		; test
	beq	.Cutstm			; found "TOC cut start minute"

.cmnd_63:
	cmp.l	#$6300,d1		; test
	beq	.Cutsts			; found "TOC cut start sec"

.cmnd_64:
	cmp.l	#$6400,d1		; test
	beq	.Cutstf			; found "TOC cut start frame"

.cmnd_70:
	cmp.l	#$7000,d1		; test
	beq	.DAC			; found "DAC setting"
	bra	.Endsort		; no command number match - fell thru to here

.Found:
	move.l	d2,CD_found
	bra	.Endsort

.Discstat:
	move.l	d2,CD_stat
	bra	.Endsort

.Error:
	move.l	d2,CD_error
	bra	.Endsort

.CutlenL:
	move.l	d2,CDcutlnL
	bra	.Endsort

.CutlenH:
	move.l	d2,CDcutlnH
	bra	.Endsort

.Track:				
	move.l	d2,CD_track
	bra	.Endsort	

.Index:
	move.l	d2,CD_index
	bra	.Endsort

.Rel_mins:			
	move.l	d2,CD_Rmins
	bra	.Endsort

.Rel_secs:			
	move.l	d2,CD_Rsecs
	bra	.Endsort

.Abs_mins:
	move.l	d2,CD_Amins	
	bra	.Endsort

.Abs_secs:
	move.l	d2,CD_Asecs
	bra	.Endsort

.Frames:
	move.l	d2,CD_Afrms
	bra	.Endsort

.Mode:
	move.l	d2,CD_setup
	bra	.Endsort

.Firs_trk:
	move.l	d2,CDTOCbeg
	bra	.Endsort

.Last_trk:
	move.l	d2,CDTOCend
	bra	.Endsort

.End_mins:
	move.l	d2,CDTOCmin
	bra	.Endsort

.End_secs:
	move.l	d2,CDTOCsec
	bra	.Endsort

.Endframe:
	move.l	d2,CDTOCfrm
	bra	.Endsort

.Sessions:
	move.l	d2,CDseshns
	bra	.Endsort

.Cutnum:
	move.l	d2,CDcutnum
	bra	.Endsort

.CutCAB:
	move.l	d2,CDcutCAB
	bra	.Endsort

.Cutstm:
	move.l	d2,CDcutstm
	bra	.Endsort

.Cutsts:
	move.l	d2,CDcutsts
	bra	.Endsort

.Cutstf:
	move.l	d2,CDcutstf

.DAC:
	move.l	d2,CD_DAC
	bra	.Endsort

.Endsort:
	rts				; end of sorting routine

;******************************************************************************
;*	VARIABLE DATA AREA						      *
;******************************************************************************

	.bss

;*============================================================================*
;*============================================================================*

		.phrase

; Butch's registers shadow in DRAM

S_BUTCH :	.ds.l	1		; base of Butch=interrupt control register, R/W
SDSCNTRL:	.ds.w	3		; DSA control register, R/W
SDS_DATA:	.ds.w	3		; DSA TX/RX data, R/W
SI2CNTRL:	.ds.l	1		; i2s bus control register, R/W
SSBCNTRL:	.ds.l	1		; CD subcode control register, R/W
SSUBDATA:	.ds.l	1		; Subcode data register A
SSUBDATB:	.ds.l	1		; Subcode data register B
SSB_TIME:	.ds.l	1		; Subcode time and compare enable (D24)
SI2SDAT1:	.ds.l	1		; i2s FIFO data
SI2SDAT2:	.ds.l	1		; i2s FIFO data

; CD TOC area (set to arbitrary big size)

CD_TOC:		.ds.l	3000

; Different variable storage area for CD handling routines

CD_base:	.ds.l	1

CD_found:	.ds.l	1
CD_stat:	.ds.l	1
CD_error:	.ds.l	1
CDcutlnL:	.ds.l	1
CDcutlnH:	.ds.l	1
CD_track:	.ds.l	1
CD_index:	.ds.l	1
CD_Rmins:	.ds.l	1
CD_Rsecs:	.ds.l	1
CD_Amins:	.ds.l	1
CD_Asecs:	.ds.l	1
CD_Afrms:	.ds.l	1
CD_setup:	.ds.l	1
CDTOCbeg:	.ds.l	1
CDTOCend:	.ds.l	1
CDTOCmin:	.ds.l	1
CDTOCsec:	.ds.l	1
CDTOCfrm:	.ds.l	1
CDseshns:	.ds.l	1
CDcutnum:	.ds.l	1
CDcutCAB:	.ds.l	1
CDcutstm:	.ds.l	1
CDcutsts:	.ds.l	1
CDcutstf:	.ds.l	1
CD_DAC:		.ds.l	1

CD_wrd0:	.ds.l	1

CDfatals:	.ds.l	1
CDmaybes:	.ds.l	1

; These variables are written to in normal

CD_retry:	.ds.l	1
PS_flag	:	.ds.l	1

; This group of variables must be initialized.

Init_cut:	.ds.l	1
CD_mode	:	.ds.l	1
DAC_mode:	.ds.l	1

Strt_min:	.ds.w	1		; format is $20nn, where nn is $minute value
Strt_sec:	.ds.w	1		; format is $21nn, where nn is $second value
strt_frm:	.ds.w	1		; format is $22nn, where nn is $frame value
Stop_min:	.ds.w	1		; format is $23nn, where nn is $minute value
Stop_sec:	.ds.w	1		; format is $24nn, where nn is $second value
Stop_frm:	.ds.w	1		; format is $25nn, where nn is $frame value

; More CD inits that are required for DSA

Waittime:	.ds.w	1		; hex value to use in wait loop
Session :	.ds.w	1		; Session number to spin-up on

; DRAM memory area where the incoming CD data is kept
; These define the main DRAM CD data buf area
; edit the values both here & in the .GAS files

Blok_ptr:	.ds.l	1		; pointer into CD data block stored here
Blok_beg:	.ds.l	1		; start of CD raw data buf
Blok_end:	.ds.l	1		; end of CD test buf

CD_count:	.ds.l	1		; counter for total number of pictures
					; shown before crash

; DRAM memory area where the incoming subcodes are kept

Subcount:	.ds.l	1		; number of subcodes

RS_words:	.ds.l	12		; arrays of subcodes in longwords before 
TW_words:	.ds.l	12		; splitting into bytes in longwords

_CDGword:	.ds.w	96		; interleaved R-W subcode bits in longwords
					; hi word = 0, lo word = 0000000000rstuvw

DRAM_end:	.ds.l	1		; highest address to clear

		.phrase

;******************************************************************************
;*	END OF FILE							      *
;******************************************************************************

	.end

