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