;******************************************************************************
;            (C) Copyright 1992-1995, Radius, Inc. and Atari Corp.
; Secret and confidential                                   All rights reserved
;******************************************************************************
; This source code and any compilation or derivative thereof is the joint
; property of Radius, Inc. and Atari Corp.  This code is provided pursuant
; to a Software License Agreement and/or Software Development Contract.  This
; code is the proprietary information of Radius, Inc. and Atari Corp. and is
; confidential in nature.  Its use and dissemination by any party other than
; Atari Corp. are strictly limited by the confidential information provisions
; of the Agreement or Contract referenced above.
;******************************************************************************
; Revision 1.1  04/27/94  16:04:45  jpe
; CD-BIOS changes incorporated.
;
; Revision 1.0  04/08/94  13:59:30  jpe
; Initial revision.
;******************************************************************************
; 200 17 May 95 JPE     Resurrected code to initialize and update snapshot
;                       area in ROMulator memory. Added playPhase to list
;                       of things which are dumped to memory.
; 201 30 May 95 JPE     Modified SetNextGroup to accept pointer to buffer
;                       control block, and to save register a0.
; 202 07 Jun 95 JPE     CBUF_END no longer hard-wired in ReadCDData and
;                       SetNextGroup (renamed SnoopBuffer). Register a2 added
;                       to snapshot history. SnoopBuffer predetermines EOF
;                       address for early release of CD-ROM.
; 203 09 Jun 95 JPE     Use symbolic, not hard-wired, offsets from buffer
;                       control block.
; 204 07 Aug 95 JPE     Debug code moved to debug.s. Sync search now chases
;                       write pointer.
; 205 17 Aug 95 JPE     Film segments concatenated on single CD track.
; 206 05 Oct 95 JPE     Moved blitter code to separate module. Added LToA
;                       subroutine.
; 207 08 Nov 95 JPE     Official legal banner added (no other changes).
; 208 07 Dec 95 JPE     Incorporated Print() and Printf() functions.
; 209 10 Jan 96 JPE     Added 'params.inc' include file.
;******************************************************************************

        .nlist
        .include    'memory.inc'
        .include    'jaguar.inc'
        .include    'cd.inc'
        .include    'player.inc'
        .include    'params.inc'
        .include    'offset.inc'
        .list

;==============================================================================
;                               FindSync
;==============================================================================
;   Subroutine to locate sync pattern in buffer.
;
;       Input:  d0 = sync pattern
;               a0 = starting address
;
;       Output: a0 = data address (immediately following sync)
;
;   If sync is not found within a prescribed length, zero is returned in a0.
;   If CD write pointer is too close to search region, $ffffffff is returned
;   in a0.
;==============================================================================

FindSync:
        movem.l a1-a2/d7,-(a7)          ; Save registers
        movea.l a0,a1                   ; Make a copy of starting address
       adda.l  #SRCH_WIN,a1            ; Add length of search window
;//      adda.l  #(42*BLK_SIZE),a1            ; Add length of search window	
CoarseSearch:
        move.l  a0,d7                   ; Current pointer
        addi.l  #$80,d7                 ; Add 128-byte safety margin
  
        bsr     GetCDWritePtr           ; See where CD write pointer is
        cmp.l   CDWritePtr,d7           ; Are we too far ahead?
        blt.s   HuntSync                ; No, hunt for sync pattern

        movea.l #$ffffffff,a0           ; Yes, return flag
        bra.s   SyncExit                ; Exit

HuntSync:
        cmp.l   (a0),d0                 ; Sync pattern?
        beq.s   FineSearch              ; Yes, begin fine search

ResumeCoarse:
        lea     SYNC_SIZE(a0),a0        ; Move over to next group
        cmpa.l  a0,a1                   ; Reached end of window?
        bgt.s   CoarseSearch            ; No, continue

        movea.l #0,a0                   ; Yes, return 0 (search failed)
        bra.s   SyncExit                ; Report the bad news

FineSearch:
        clr     d7                      ; Clear sync counter
        lea     0(a0),a2                ; Start from current location

FindStart:
        cmp.l   -(a2),d0                ; Found upstream sync pattern?
        bne.s   FoundStart              ; No, continue counting at (a0)

        addq    #1,d7                   ; Yes, increment counter
        bra.s   FindStart               ; Back up and look again

FoundStart:
        lea     0(a0),a2                ; Continue at coarse search point

CountSync:
        cmp.l   (a2)+,d0                ; Sync pattern?
        bne.s   ResumeCoarse            ; No, break out and try again

        addq    #1,d7                   ; Yes, incrememnt counter
        cmpi    #SYNC_SIZE/4,d7         ; Found the right number?
        bne.s   CountSync               ; Not yet, keep counting

        movea.l a2,a0                   ; Yep, we're done

SyncExit:
        movem.l (a7)+,a1-a2/d7          ; Restore registers
        rts

;==============================================================================
;                            GetCDWritePtr
;==============================================================================
;   Subroutine to find current DRAM write address for CD-ROM data.
;
;       Input:  None
;
;       Output: None
;==============================================================================

GetCDWritePtr:
        movem.l a0-a1,-(a7)             ; Save used registers

        jsr     CD_ptr                  ; Get pointer location
        move.l  a0,CDWritePtr           ; Store it for later reference

        movem.l (a7)+,a0-a1             ; Restore used registers
        rts

;==============================================================================
;                             GetTimeCode
;==============================================================================
;   Subroutine to compute time code.
;
;       Input:  d0 = data offset in bytes
;
;       Output: d0 = time code (00:mm:ss:bb)
;============================================================================

GetTimeCode:
        move.l  d1,-(a7)                ; Save register

        move.l  filmOffset,d1           ; Film offset (bytes)
        add.l   mediaOffset,d1          ; Add media offset (bytes)
        add.l   d0,d1                   ; Add data offset (bytes)
        move    #BLK_SIZE,d0            ; Bytes per block
        bsr     LongDivide              ; Convert byte to block offset
        add.l   trackOffset,d1          ; Track offset in blocks

        divu    #BLK_RATE,d1            ; d1 = 00:bb:00:ss
        clr.l   d0                      ; d0 = 00:00:00:00
        swap    d1                      ; d1 = 00:ss:00:bb
        move    d1,d0                   ; d0 = 00:00:00:bb
        clr     d1                      ; Nuke the remainder
        swap    d1                      ; d1 = 00:00:00:ss
        divu    #60,d1                  ; d1 = 00:ss:00:mm
        swap    d1                      ; d1 = 00:mm:00:ss
        lsl     #8,d1                   ; d1 = 00:mm:ss:00
        or.l    d1,d0                   ; d0 = 00:mm:ss:bb

        move.l  (a7)+,d1                ; Restore register
        rts

;==============================================================================
;                               LoadDSP
;==============================================================================
;   Subroutine to copy over the DSP program.
;
;       Input:  None
;
;       Output: None
;==============================================================================

LoadDSP:

        lea     DSP_STOP,a0
        move.l  #1,(a0)                 ; Tell the DSP to stop

WaitDSP:
        move.l  D_CTRL,d0               ; Read DSP control register
        btst    #0,d0                   ; Is it still running?
        bne.s   WaitDSP                 ; Yes, wait for it to stop

        clr.l   (a0)                    ; Now clear the stop flag

        movea.l #DSP_LOAD,a1            ; Destination in DSP memory
        movea.l #DSP_S,a0               ; Source in CPU memory

.Loop0:
        move.l  (a0)+,(a1)+
        cmpa.l  #DSP_E,a0               ; Reached EOF in CPU memory?
        bne.s   .Loop0                  ; No, continue

; Make sure the DACs are silent!

        move.l  #0,R_DAC
        move.l  #0,L_DAC

; Set up the I2S mode and clock.

        move.l  #18,SCLK                ; 21.793 kHz (Default)
        move.l  #$15,SMODE              ; FALLING, WSEN, INTERNAL

; Enable sound (mute bit).

        move.w  #$100,JOYSTICK
    
        rts

;==============================================================================
;                               LoadGPU
;==============================================================================
; Procedure: LoadGPU
;            Load and start GPU processes.
;
; In this demo, the GPU is a rather busy processor. The following needs to
; be loaded:
;
; 1. Stub (contains OP/PIT handlers) which has several purposes:
;    a) Initialize Interrupt Stack
;    b) Switch to register bank #1 (second bank)
;    c) Enable (atomically) CPU/OP/PIT Interrupts
;    d) Jump to Cinepak Code
; 2. Cinepak Decompression Code (primary, i.e. always running GPU process)
; 3. CD-BIOS (is a Jerry Interrupt Handler)
;
; Memory Map:
; F03000-F0304F   Interrupt Stubs
; F03050-F031FF   Startup Stub
; F03200-F03B0F   Cinepak Code
; F03B10-F03BFF   CD-BIOS
;
; The stub is not started until all three components are loaded into the
; system.
;==============================================================================

LoadGPU:
        movem.l d0/a0-a1,-(sp)          ; Save used registers

;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Startup Stub Code
;;;;;;;;;;;;;;;;;;;;;;;;;

        movea.l #gpustartup,a0          ; Source address in DRAM
        movea.l #G_RAM,a1               ; Where to load stub
        move.l  #gpustartupx,d0         ; End of Code in DRAM
        sub.l   a0,d0                   ; Byte count
        bsr     BlockMove               ; Copy stub code
    
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Cinepak Code (primary process)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        move.l  #GPU_OFFSET,GPUOffset   ; Initialize offset value

        movea.l #DECOMP_S,a0            ; Source address in DRAM
        movea.l #G_RAM+GPU_OFFSET,a1    ; Where to load decompressor
        move.l  #DECOMP_E,d0            ; End of Code in DRAM
        sub.l   a0,d0                   ; Byte count
        bsr     BlockMove               ; Copy decompressor code
    
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; CD-BIOS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        move.l  #$F03B10,a0
        jsr     CD_initf                ; Load support code

        movem.l (sp)+,d0/a0-a1          ; Restore used registers
        rts

;==============================================================================
;                              LongDivide
;==============================================================================
;   Subroutine to perform long division. Correctly handles overflow in cases
;   where the quotient exceeds 16-bit range. Remainder is discarded.
;
;       Input:  d0 = unsigned 16-bit divisor
;               d1 = unsigned 32-bit dividend: [Dhi,Dlo]
;
;       Output: d1 = unsigned 32-bit quotient: [Qhi,Qlo]
;==============================================================================

LongDivide:
        divu    d0,d1                   ; d1 = Rlo, Qlo
        bvs.s   FixOverflow             ; We overflowed, fix it

        swap    d1                      ; d1 = Qlo, Rlo
        clr     d1                      ; d1 = Qlo, 000
        swap    d1                      ; d1 = 000, Qlo
        rts

FixOverflow:
        move.l  d2,-(a7)                ; Save register

        move    d1,d2                   ; d2 = xxx, Dlo
        clr     d1                      ; d1 = Dhi, 000
        swap    d1                      ; d1 = 000, Dhi
        divu    d0,d1                   ; d1 = Rhi, Qhi
        swap    d1                      ; d1 = Qhi, Rhi
        swap    d2                      ; d2 = Dlo, xxx
        move    d1,d2                   ; d2 = Dlo, Rhi
        swap    d2                      ; d2 = Rhi, Dlo
        divu    d0,d2                   ; d2 = Rlo, Qlo
        move    d2,d1                   ; d1 = Qhi, Qlo

        move.l  (a7)+,d2                ; Restore register
        rts

;==============================================================================
;                                 LToA
;==============================================================================
;   Subroutine to convert unsigned long integer to null-terminated ASCII
;   string.
;
;       Input:  d0 = unsigned 32-bit number
;               a0 = pointer to start of output string
;
;       Output: None
;==============================================================================

LToA:
        movem.l d0-d2/a0-a1,-(sp)       ; Save registers

        lea     powersOfTen,a1          ; Powers of 10
        tst.l   d0                      ; Do we have a zero?
        bne.s   FindPlace               ; No, get started

        move.b  #'0',(a0)+              ; Yes, special case
        bra.s   LToADone                ; That's all

FindPlace:
        cmp.l   (a1),d0                 ; Compare with power of 10
        bcc.s   NextDigit               ; Start if number >= table
        lea     4(a1),a1                ; Advance to next power of 10
        bra.s   FindPlace               ; Try again

NextDigit:
        move.l  (a1)+,d2                ; Get power of 10
        beq.s   LToADone                ; If zero, we're done
        move.b  #'0',d1                 ; ASCII 0

ComputeDigit:
        cmp.l   d2,d0                   ; Compare with power of 10
        bcs.s   GotDigit                ; Branch if negative

        sub.l   d2,d0                   ; Otherwise, subtract
        addq.b  #1,d1                   ; Increment ASCII value
        bra.s   ComputeDigit            ; Keep going

GotDigit:
        move.b  d1,(a0)+                ; Store ASCII digit to string
        bra.s   NextDigit               ; Move to next digit

LToADone:
        move.b  #0,(a0)+                ; Terminate string with NULL

        movem.l (sp)+,d0-d2/a0-a1       ; Restore registers
        rts

powersOfTen:
        dc.l    1000000000              ; 10**9
        dc.l    100000000               ; 10**8
        dc.l    10000000                ; 10**7
        dc.l    1000000                 ; 10**6
        dc.l    100000                  ; 10**5
        dc.l    10000                   ; 10**4
        dc.l    1000                    ; 10**3
        dc.l    100                     ; 10**2
        dc.l    10                      ; 10**1
        dc.l    1                       ; 10**0
        dc.l    0                       ; End of table marker

;==============================================================================
;                                Print
;==============================================================================
;   Subroutine to print a string with a specified color at a specified x,y
;   location. If x = -1, the string is centered in the display.
;
;   Input:  a2 = pointer to text string
;           d0 = (x,y) location
;           d1 = color
;
;   Output: None
;==============================================================================

Print:
        movem.l a0-a1/d0-d1,-(a7)       ; Save gcc registers
        move.l  d2,-(sp)                ; Save register

        movea.l #SCREEN_BASE,a0         ; Base of triple buffer
        move    blitIndex,d2            ; Index of active buffer
        lsl     #3,d2                   ; Convert to phrase offset
        lea     $8(a0,d2),a0            ; Base of target buffer

        move    #$0,-(sp)               ; bgcolor
        move    d1,-(sp)                ; fgcolor
        pea     font                    ; FNThead

        move.l  #PIXEL16|PITCH3|WID320,-(sp)     ; blitflags

        move.l  a0,-(sp)                ; void *dest
        move.l  a2,-(sp)                ; char *str
        move    d0,-(sp)                ; int y
        swap    d0                      ; Get x in low word
        tst     d0                      ; Positive?
        bge.s   PushX                   ; Yes, push value to stack

        bsr.s   GetCenter               ; No, compute centered value

PushX:
        move    d0,-(sp)                ; int x
        jsr     _FNTstr                 ; do it
        lea     $18(a7),a7              ; Balance stack

        move.l  (sp)+,d2                ; Restore register
        movem.l (sp)+,a0-a1/d0-d1       ; Restore gcc registers
        rts

;------------------------------------------------------------------------------

GetCenter:
        movem.l d1/a0-a1,-(sp)          ; Save gcc registers (use d0)

        pea     font                    ; FNThead
        move.l  a2,-(a7)                ; char *str
        jsr     _FNTbox                 ; Get bounding rectangle in d0
        lea     $8(a7),a7               ; Balance stack

        subi    #NPIXELS,d0             ; Subtract pixels per line
        neg     d0                      ; Make positive
        lsr     #1,d0                   ; Divide by 2

        movem.l (sp)+,d1/a0-a1          ; Restore gcc registers (use d0)
        rts

;==============================================================================
;                                Printf
;==============================================================================
;   Subroutine to print a string formatted with newline characters. Vertical
;   centering is based on the computed line count. After every line, the
;   vertical position is incremented by 24.
;
;   Input:  a2 = pointer to text string
;           d1 = color
;
;   Output: None
;==============================================================================

Printf:
        movem.l d0/d2/a0/a2,-(sp)       : Save regsiters

        movea.l a2,a0                   ; Copy string pointer
        clr     d2                      ; Initialize line counter

CountLines:
        cmpi.b  #$a,(a0)+               ; Newline character?
        beq.s   IncCount                ; Yes, increment count

        tst.b   -1(a0)                  ; Null?
        bne.s   CountLines              ; No, continue counting

IncCount:
        addq    #1,d2                   ; Increment line counter
        tst.b   -1(a0)                  ; Null?
        bne.s   CountLines              ; No, continue counting

        subi    #9,d2                   ; #lines - 9
        neg     d2                      ; 9 - #lines
        lsr     #1,d2                   ; (9 - #lines) / 2
        mulu    #24,d2                  ; 24 display lines per text line
        moveq   #-1,d0                  ; (x,y) = (-1,-1)
        move    d2,d0                   ; (x,y) = (-1,y)
        movea.l a2,a0                   ; Copy string pointer

TestChar:
        cmpi.b  #$a,(a0)+               ; New line?
        beq.s   PrintLine               ; Yes, print it

        tst.b   -1(a0)                  ; End of formatted string?
        bne.s   TestChar                ; No, continue search

        bra.s   PrintLast               ; Yes, print final line

PrintLine:
        clr.b   -1(a0)                  ; Poke in a NULL
        bsr     Print                   ; Print one line
        move.b  #$a,-1(a0)              ; Restore newline character
        addi    #24,d0                  ; Move down 24 lines
        movea.l a0,a2                   ; Reset string pointer
        bra.s   TestChar                ; Continue with input string

PrintLast:
        bsr     Print                   ; Print final line

        movem.l (sp)+,d0/d2/a0/a2       ; Restore registers
        rts

;==============================================================================
;                              ReadCDData
;==============================================================================
;   Subroutine to set up controls and play data from CD-ROM.
;
;       Input:  a0 = starting destination address
;               a1 = ending destination address
;               d0 = data offset on CD-ROM
;
;       Output: None
;==============================================================================

ReadCDData:
        movem.l a1-a2/d1,-(a7)          ; Save registers (CD_read uses a2/d1)

        bsr     GetTimeCode             ; Get start time code in d0
        jsr     CD_read                 ; Read from specified time code

        movem.l (a7)+,a1-a2/d1          ; Restore registers
        rts

;==============================================================================
;                             SnoopBuffer
;==============================================================================
;   Subroutine to determine number of chunks and ending address of last
;   complete chunk in a buffer. Decrements the filmChunks variable and
;   updates a pointer to the next chunk which must be read from the CD.
;
;       Input:  a0 = Address of first chunk in circular buffer
;               a1 = Base of buffer control block
;
;       Output: None
;==============================================================================

SnoopBuffer:
        movem.l a0/a2,-(a7)             ; Save registers

        movea.l pNextGroup,a2           ; Pointer to next group of chunks
        clr.l   buffChunks(a1)          ; Clear buffer chunk count

AddChunkSize:
        adda.l  $4(a2),a0               ; Add chunk size
        cmpa.l  bufEnd(a1),a0           ; Did chunk fit in buffer?
        bgt.s   SetPointer              ; No, set chunk pointer

        move.l  a0,dataEnd(a1)          ; Pending EOF address
        lea     $10(a2),a2              ; Advance chunk table pointer
        addq.l  #1,buffChunks(a1)       ; Increment buffer chunk count
        subq.l  #1,filmChunks           ; Decrement film chunk count
        bne.s   AddChunkSize            ; Alternate exit if no more left

SetPointer:
        move.l  a2,pNextGroup           ; Update pointer

        movem.l (a7)+,a0/a2             ; Restore registers
        rts

;------------------------------------------------------------------------------
;   Declare externals and globals.
;------------------------------------------------------------------------------

        .extern     DSP_LOAD
        .extern     DSP_STOP            ; Flag tells DSP to stop
        .extern     DSP_S
        .extern     DSP_E

        .extern     DECOMP_S
        .extern     DECOMP_E

        .extern     gpustartup
        .extern     gpustartupx

        .extern     BlockMove

        .extern     CDWritePtr
        .extern     filmChunks
        .extern     GPUOffset
        .extern     mediaOffset
        .extern     trackOffset
        .extern     filmOffset
        .extern     pNextGroup
        .extern     blitIndex
        .extern     font
        .extern     _FNTstr
        .extern     _FNTbox

        .globl      FindSync            ; Find sync pattern in data stream
        .globl      GetCDWritePtr       ; Get location of CD-ROM write
        .globl      LoadDSP             ; Load DSP code
        .globl      LoadGPU             ; Load GPU code
        .globl      LongDivide          ; Long division routine
        .globl      LToA                ; Long-to-ASCII conversion 
        .globl      ReadCDData          ; Play CD and fill circular buffer
        .globl      SnoopBuffer         ; Set next chunk group's parameters
        .globl      Print
        .globl      Printf

        .end
