File: STARTUP.S - Tab length: 1 2 4 8 - Lines: on off - No wrap: on off

;-----------------------------------------------------------------------------
; Warning!!! Warning!!! Warning!!! Warning!!! Warning!!! Warning!!! Warning!!!
; Warning!!! Warning!!! Warning!!! Warning!!! Warning!!! Warning!!! Warning!!!
;-----------------------------------------------------------------------------
; Do not change any of the code in this file except where explicitly noted.
; Making other changes can cause your program's startup code to be incorrect.
;-----------------------------------------------------------------------------


;----------------------------------------------------------------------------
; Jaguar Development System Source Code
; Copyright (c)1995 Atari Corp.
; ALL RIGHTS RESERVED
;
; Module: startup.s - Hardware initialization/License screen display
;
; Revision History:
;  1/12/95 - SDS: Modified from MOU.COF sources.
;  2/28/95 - SDS: Optimized some code from MOU.COF.
;  3/14/95 - SDS: Old code preserved old value from INT1 and OR'ed the
;                 video interrupt enable bit. Trouble is that could cause
;                 pending interrupts to persist. Now it just stuffs the value.
;  4/17/95 - MF:  Moved definitions relating to startup picture's size and
;                 filename to top of file, separate from everything else (so
;                 it's easier to swap in different pictures).
;----------------------------------------------------------------------------
; Program Description:
; Jaguar Startup Code
;
; Steps are as follows:
; 1. Set GPU/DSP to Big-Endian mode
; 2. Set VI to $FFFF to disable video-refresh.
; 3. Initialize a stack pointer to high ram.
; 4. Initialize video registers.
; 5. Create an object list as follows:
;            BRANCH Object (Branches to stop object if past display area)
;            BRANCH Object (Branches to stop object if prior to display area)
;            BITMAP Object (Jaguar License Acknowledgement - see below)
;            STOP Object
; 6. Install interrupt handler, configure VI, enable video interrupts,
;    lower 68k IPL to allow interrupts.
; 7. Use GPU routine to stuff OLP with pointer to object list.
; 8. Turn on video.
; 9. Jump to _start.
;
; Notes:
; All video variables are exposed for program use. 'ticks' is exposed to allow
; a flicker-free transition from license screen to next. gSetOLP and olp2set
; are exposed so they don't need to be included by exterior code again.
;-----------------------------------------------------------------------------

        .include        "jaguar.inc"

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Begin STARTUP PICTURE CONFIGURATION -- Edit this to change startup picture
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

PPP             .equ    4                       ; Pixels per Phrase (1-bit)
BMP_WIDTH       .equ    192                     ; Width in Pixels
BMP_HEIGHT      .equ    48                      ; Height in Pixels

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Change this macro as necessary. Games published by Atari but created by a
; third-party should use "LICENSED TO" screen. Games published and
; created by a third-party company should use "LICENSED BY" screen.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        .macro license_logo
        .incbin "/jaguar/source/sample.rgb"     ; "Jaguar Developer Kit Sample"
;       .incbin "/jaguar/startup/lt_box.rgb"    ; "Licensed To Atari Corp."
;       .incbin "/jaguar/startup/lb_box.rgb"    ; "Licensed By Atari Corp."
        .endm

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; End of STARTUP PICTURE CONFIGURATION
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; Globals
                .globl  gSetOLP
                .globl  olp2set
                .globl  ticks

                .globl  a_vdb
                .globl  a_vde
                .globl  a_hdb
                .globl  a_hde
                .globl  width
                .globl  height
; Externals
                .extern _start

BMP_PHRASES     .equ    (BMP_WIDTH/PPP)         ; Width in Phrases
BMP_LINES       .equ    (BMP_HEIGHT*2)          ; Height in Half Scanlines
BITMAP_OFF      .equ    (2*8)                   ; Two Phrases
LISTSIZE        .equ    5                       ; List length (in phrases)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Program Entry Point Follows...

                .text

                move.l  #$70007,G_END           ; big-endian mode
                move.l  #$70007,D_END
                move.w  #$FFFF,VI               ; disable video interrupts

                move.l  #INITSTACK,a7           ; Setup a stack

;               jsr             Interlace                       ; modify video regs for interlace mode                  

                jsr     InitVideo               ; Setup our video registers.
                jsr     InitLister              ; Initialize Object Display List
                jsr     InitVBint               ; Initialize our VBLANK routine

;;; Sneaky trick to cause display to popup at first VB

                move.l  #$0,listbuf+BITMAP_OFF
                move.l  #$C,listbuf+BITMAP_OFF+4

                move.l  d0,olp2set              ; D0 is swapped OLP from InitLister
                move.l  #gSetOLP,G_PC           ; Set GPU PC
                move.l  #RISCGO,G_CTRL          ; Go!
waitforset:
                move.l  G_CTRL,d0               ; Wait for write.
                andi.l  #$1,d0
                bne     waitforset

                move.w  #$2C7,VMODE             ; Configure Video
               
;boucle:        
;               bra.s   boucle
        jmp     _start                  ; Jump to main code

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Procedure: gSetOLP
;            Use the GPU to set the OLP and quit.
;
;    Inputs: olp2set - Variable contains pre-swapped value to stuff OLP with.
;
; NOTE!!!: This code can run in DRAM only because it contains no JUMP's or
;          JR's. It will generate a warning with current versions of MADMAC
;          because it doesn't '.ORG'.
;
                .long
                .gpu
gSetOLP:
                movei   #olp2set,r0             ; Read value to write
                load    (r0),r1

                movei   #OLP,r0                 ; Store it
                store   r1,(r0)

                moveq   #0,r0                   ; Stop GPU
                movei   #G_CTRL,r1
                store   r0,(r1)
                nop                             ; Two "feet" on the brake pedal
                nop

                .68000
                .bss
                .long

olp2set:        .ds.l   1                       ; GPU Code Parameter

                .text

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Procedure: InitVBint
; Install our vertical blank handler and enable interrupts
;

InitVBint:
                move.l  d0,-(sp)

                move.l  #UpdateList,LEVEL0      ; Install 68K LEVEL0 handler

                move.w  a_vde,d0                ; Must be ODD
                ori.w   #1,d0
                move.w  d0,VI
                move.w  d0,vi_line              ; save it for later, VI is write-only

                move.w  #C_VIDENA,INT1          ; Enable video interrupts

                move.w  sr,d0
                and.w   #$F8FF,d0               ; Lower 68k IPL to allow
                move.w  d0,sr                   ; interrupts

                move.l  (sp)+,d0
                rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Procedure: Interlace
;            Sets up video signals correctly to enable interlaced video
;            Modifies registers we were told never to touch.
;            Code by Zerosquare of Jagware
;
Interlace:
                move.w  CONFIG, d0
                andi.w  #16, d0
                bne.s   Init60HzI
                                                 
                Init50HzI:
                move.w  #0,     HC  
                move.w  #1,     VC    
                move.w  #624,   VP    
                move.w  #614,   VEB  
                move.w  #619,   VS    
                move.w  #4,     VEE  
                move.w  #40,    VBE  
                move.w  #614,   VBB  
                move.w  #850,   HP  
                move.w  #1749,  HS  
                move.w  #787,   HEQ  
                move.w  #600,   HVS  
                move.w  #1709,  HBB
                move.w  #153,   HBE  
                bra.s   done

                Init60HzI:
                move.w  #0,     HC  
                move.w  #1,     VC  
                move.w  #524,   VP  
                move.w  #512,   VEB  
                move.w  #518,   VS  
                move.w  #5,VEE  
                move.w  #30,VBE  
                move.w  #512,VBB  
                move.w  #844,HP    
                move.w  #1743,HS  
                move.w  #780,HEQ  
                move.w  #595,HVS  
                move.w  #1697,HBB  
                move.w  #118,HBE  

done:           rts
               
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Procedure: InitVideo (same as in vidinit.s)
;            Build values for hdb, hde, vdb, and vde and store them.
;
                                               
InitVideo:
                movem.l d0-d6,-(sp)
                       
                move.w  CONFIG,d0                ; Also is joystick register
                andi.w  #VIDTYPE,d0              ; 0 = PAL, 1 = NTSC
                beq     palvals

                move.w  #NTSC_HMID,d2
                move.w  #NTSC_WIDTH,d0

                move.w  #NTSC_VMID,d6
                move.w  #NTSC_HEIGHT,d4

                bra     calc_vals
palvals:
                move.w  #PAL_HMID,d2
                move.w  #PAL_WIDTH,d0

                move.w  #PAL_VMID,d6
                move.w  #PAL_HEIGHT,d4

calc_vals:
                move.w  d0,width
                move.w  d4,height

                move.w  d0,d1
                asr     #1,d1                   ; Width/2

                sub.w   d1,d2                   ; Mid - Width/2
                add.w   #4,d2                   ; (Mid - Width/2)+4

                sub.w   #1,d1                   ; Width/2 - 1
                ori.w   #$400,d1                ; (Width/2 - 1)|$400
               
                move.w  d1,a_hde
                move.w  d1,HDE

                move.w  d2,a_hdb
                move.w  d2,HDB1
                move.w  d2,HDB2

                move.w  d6,d5
                sub.w   d4,d5
                move.w  d5,a_vdb

                add.w   d4,d6
                move.w  d6,a_vde

                move.w  a_vdb,VDB
                move.w  #$FFFF,VDE
                       
                move.l  #0,BORD1                ; Black border
                move.w  #0,BG                   ; Init line buffer to black
               
;               move.w  #0,HC
;               move.w  #1,VC

                move.w  #524,VP
               
                movem.l (sp)+,d0-d6
                rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; InitLister: Initialize Object List Processor List
;
;    Returns: Pre-word-swapped address of current object list in d0.l
;
;  Registers: d0.l/d1.l - Phrase being built
;             d2.l/d3.l - Link address overlays
;             d4.l      - Work register
;             a0.l      - Roving object list pointer
               
InitLister:
                movem.l d1-d4/a0,-(sp)          ; Save registers
                       
                lea     listbuf,a0
                move.l  a0,d2                   ; Copy

                add.l   #(LISTSIZE-1)*8,d2      ; Address of STOP object
                move.l  d2,d3                   ; Copy for low half

                lsr.l   #8,d2                   ; Shift high half into place
                lsr.l   #3,d2
               
                swap    d3                      ; Place low half correctly
                clr.w   d3
                lsl.l   #5,d3

; Write first BRANCH object (branch if YPOS > a_vde )

                clr.l   d0
                move.l  #(BRANCHOBJ|O_BRLT),d1  ; $4000 = VC < YPOS
                or.l    d2,d0                   ; Do LINK overlay
                or.l    d3,d1
                                                               
                move.w  a_vde,d4                ; for YPOS
                lsl.w   #3,d4                   ; Make it bits 13-3
                or.w    d4,d1

                move.l  d0,(a0)+
                move.l  d1,(a0)+

; Write second branch object (branch if YPOS < a_vdb)
; Note: LINK address is the same so preserve it

                andi.l  #$FF000007,d1           ; Mask off CC and YPOS
                ori.l   #O_BRGT,d1              ; $8000 = VC > YPOS
                move.w  a_vdb,d4                ; for YPOS
                lsl.w   #3,d4                   ; Make it bits 13-3
                or.w    d4,d1

                move.l  d0,(a0)+
                move.l  d1,(a0)+

; Write a standard BITMAP object

                move.l  d2,d0
                move.l  d3,d1

                ori.l  #BMP_HEIGHT/2<<14,d1       ; Height of image

                move.w  height,d4               ; Center bitmap vertically
                sub.w   #BMP_HEIGHT/2,d4
                add.w   a_vdb,d4
                andi.w  #$FFFE,d4               ; Must be even
                lsl.w   #3,d4
                or.w    d4,d1                   ; Stuff YPOS in low phrase

                move.l  #license,d4
               
                lsl.l   #8,d4
                or.l    d4,d0
       
                move.l  d0,(a0)+
                move.l  d1,(a0)+
                movem.l d0-d1,bmpupdate

; Second Phrase of Bitmap

                move.l  #BMP_PHRASES>>4,d0      ; Only part of top LONG is IWIDTH
                move.l  #O_DEPTH16|O_NOGAP,d1   ; Bit Depth = 16-bit, Contiguous data

                move.w  width,d4                ; Get width in clocks
                lsr.w   #1,d4                   ; /4 Pixel Divisor
                sub.w   #BMP_WIDTH,d4
                lsr.w   #1,d4
                or.w    d4,d1

                ori.l   #((BMP_PHRASES*2)<<18)|(BMP_PHRASES<<28),d1     ; DWIDTH|IWIDTH

                move.l  d0,(a0)+
                move.l  d1,(a0)+

; Write a STOP object at end of list
                clr.l   (a0)+
                move.l  #(STOPOBJ|O_STOPINTS),(a0)+

; Now return swapped list pointer in D0

                move.l  #listbuf,d0
                swap    d0

                movem.l (sp)+,d1-d4/a0
                rts

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Procedure: UpdateList
;        Handle Video Interrupt and update object list fields
;        destroyed by the object processor.

UpdateList:
                movem.l  d0/a0,-(sp)

                move.l  #listbuf+BITMAP_OFF,a0

                move.l  bmpupdate,(a0)          ; Phrase = d1.l/d0.l
                move.l  bmpupdate+4,4(a0)

                add.l   #1,ticks                ; Increment ticks semaphore

                move.w  #$101,INT1              ; Signal we're done
                move.w  #$0,INT2
               
                btst.b  #(11-8),VC              ; we're testing bit 11 (the 12th bit) of VC but...
                bne     .bottom                 ; btst only works on bytes when operating on memory

                ; top field
                ori.w   #1,vi_line              ; set line next VI will occur on
                move.w  vi_line,VI              ; and set it (VI is write-only)

                bra     .done

.bottom:        ; bottom field
                andi.w  #$fffe,vi_line          ; set line next VI will occur on
                move.w  vi_line,VI              ; and set it (VI is write-only)

                add.l   #((BMP_PHRASES)<<11),(a0) ; add IWIDTH to DATA to start one line lower

.done:  

; test de scrolling
;               move.w  bmpupdate+6,d0
;               add.w   #16,d0
;               and.w   #$CFFF,d0
;               move.w  d0,bmpupdate+6
               
                movem.l  (sp)+,d0/a0
                rte

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

                .data
                .phrase
license:
                license_logo

                .bss
                .dphrase

listbuf:        .ds.l   LISTSIZE*2              ; Object List
bmpupdate:      .ds.l   2                       ; One Phrase of Bitmap for Refresh
ticks:          .ds.l   1                       ; Incrementing # of ticks
vi_line:        .ds.w   1                       ; VI is write only, so cache it
a_hdb:          .ds.w   1
a_hde:          .ds.w   1
a_vdb:          .ds.w   1
a_vde:          .ds.w   1
width:          .ds.w   1
height:         .ds.w   1

                .end