.text

*-------------------------------------------------------
*
*       Sega startup code for the GNU Assembler
*       Translated from:
*       Sega startup code for the Sozobon C compiler
*       Written by Paul W. Lee
*       Modified from Charles Coty's code
*
*-------------------------------------------------------

        .org    0x0000

        dc.l    0x0,0x200
        dc.l    INT,INT,INT,INT,INT,INT,INT
        dc.l    INT,INT,INT,INT,INT,INT,INT,INT
        dc.l    INT,INT,INT,INT,INT,INT,INT,INT
        dc.l    INT,INT,INT,HBL,INT,VBL,INT,INT
        dc.l    INT,INT,INT,INT,INT,INT,INT,INT
        dc.l    INT,INT,INT,INT,INT,INT,INT,INT
        dc.l    INT,INT,INT,INT,INT,INT,INT,INT
        dc.l    INT,INT,INT,INT,INT,INT,INT

        .ascii  "SEGA MEGA DRIVE "                                  /* Console Name (16) */
        .ascii  "(C)SEGA 2006.JAN"                                  /* Copyright Information (16) */
        .ascii  "SAMPLE PROGRAM                                  "  /* Domestic Name (48) */
        .ascii  "SAMPLE PROGRAM                                  "  /* Overseas Name (48) */
        .ascii  "GM 00000000-00"                                    /* Serial Number (2, 14) */
        dc.w    0x0000                                              /* Checksum (2) */
        .ascii  "JD              "                                  /* I/O Support (16) */
        dc.l    0x00000000                                          /* ROM Start Address (4) */
        dc.l    0x20000                                             /* ROM End Address (4) */
        dc.l    0x00FF0000                                          /* Start of Backup RAM (4) */
        dc.l    0x00FFFFFF                                          /* End of Backup RAM (4) */
        .ascii  "                        "                          /* Modem Support (12) */
        .ascii  "DEMONSTRATION PROGRAM                   "          /* Memo (40) */
        .ascii  "JUE             "                                  /* Country Support (16) */

        tst.l   0xa10008
        bne     SkipJoyDetect
        tst.w   0xa1000c
SkipJoyDetect:
        bne     SkipSetup
        lea     Table,%a5
        movem.w (%a5)+,%d5-%d7
        movem.l (%a5)+,%a0-%a4
* Check Version Number
        move.b  -0x10ff(%a1),%d0
        andi.b  #0x0f,%d0
        beq     WrongVersion
* Sega Security Code (SEGA)
        move.l  #0x53454741,0x2f00(%a1)
WrongVersion:
        move.w  (%a4),%d0
        moveq   #0x00,%d0
        movea.l %d0,%a6
        move    %a6,%usp
* Set VDP registers
        moveq   #0x17,%d1
FillLoop:
        move.b  (%a5)+,%d5
        move.w  %d5,(%a4)
        add.w   %d7,%d5
        dbra    %d1,FillLoop
        move.l  (%a5)+,(%a4)
        move.w  %d0,(%a3)
        move.w  %d7,(%a1)
        move.w  %d7,(%a2)
L0250:
        btst    %d0,(%a1)
        bne     L0250
* Put initial values into a00000
        moveq   #0x25,%d2
Filla:
        move.b  (%a5)+,(%a0)+
        dbra    %d2,Filla
        move.w  %d0,(%a2)
        move.w  %d0,(%a1)
        move.w  %d7,(%a2)
L0262:
        move.l  %d0,-(%a6)
        dbra    %d6,L0262
        move.l  (%a5)+,(%a4)
        move.l  (%a5)+,(%a4)
* Put initial values into c00000
        moveq   #0x1f,%d3
Filc0:
        move.l  %d0,(%a3)
        dbra    %d3,Filc0
        move.l  (%a5)+,(%a4)
* Put initial values into c00000
        moveq   #0x13,%d4
Fillc1:
        move.l  %d0,(%a3)
        dbra    %d4,Fillc1
* Put initial values into c00011
        moveq   #0x03,%d5
Fillc2:
        move.b  (%a5)+,0x0011(%a3)
        dbra    %d5,Fillc2
        move.w  %d0,(%a2)
        movem.l (%a6),%d0-%d7/%a0-%a6
        move    #0x2700,%sr
SkipSetup:
        bra     Continue
Table:
        dc.w    0x8000, 0x3fff, 0x0100, 0x00a0, 0x0000, 0x00a1, 0x1100, 0x00a1
        dc.w    0x1200, 0x00c0, 0x0000, 0x00c0, 0x0004, 0x0414, 0x302c, 0x0754
        dc.w    0x0000, 0x0000, 0x0000, 0x812b, 0x0001, 0x0100, 0x00ff, 0xff00
        dc.w    0x0080, 0x4000, 0x0080, 0xaf01, 0xd91f, 0x1127, 0x0021, 0x2600
        dc.w    0xf977, 0xedb0, 0xdde1, 0xfde1, 0xed47, 0xed4f, 0xd1e1, 0xf108
        dc.w    0xd9c1, 0xd1e1, 0xf1f9, 0xf3ed, 0x5636, 0xe9e9, 0x8104, 0x8f01
        dc.w    0xc000, 0x0000, 0x4000, 0x0010, 0x9fbf, 0xdfff

Continue:
        tst.w    0x00C00004

* set stack pointer
        move.w   #0,%a7

* user mode
        move.w  #0x2300,%sr

* clear Genesis RAM
        lea     0xff0000,%a0
        moveq   #0,%d0
clrram: move.w  #0,(%a0)+
        subq.w  #2,%d0
        bne     clrram

        jmp     start


*------------------------------------------------
*
*       interrupt functions
*
*------------------------------------------------

.bss

        .extern vtimer

.text

INT:
        rte

HBL:
        movem.l %d0-%d1/%a0-%a1,-(%sp)
        bsr    _hblankcallback
        movem.l (%sp)+,%d0-%d1/%a0-%a1
        rte

VBL:
        addq.l   #1,vtimer
        movem.l %d0-%d1/%a0-%a1,-(%sp)
        bsr    _vblankcallback
        movem.l (%sp)+,%d0-%d1/%a0-%a1
        rte


*------------------------------------------------
*
* Copyright (c) 1988 by Sozobon, Limited.  Author: Johann Ruegg
*
* Permission is granted to anyone to use this software for any purpose
* on any computer system, and to redistribute it freely, with the
* following restrictions:
* 1) No charge may be made other than reasonable charges for reproduction.
* 2) Modified versions must be clearly marked as such.
* 3) The authors are not responsible for any harmful consequences
*    of using this software, even if they result from defects in it.
*
*------------------------------------------------

ldiv:
        move.l  4(%a7),%d0
        bpl     ld1
        neg.l   %d0
ld1:
        move.l  8(%a7),%d1
        bpl     ld2
        neg.l   %d1
        eor.b   #0x80,4(%a7)
ld2:
        bsr     i_ldiv          /* d0 = d0/d1 */
        tst.b   4(%a7)
        bpl     ld3
        neg.l   %d0
ld3:
        rts

lmul:
        move.l  4(%a7),%d0
        bpl     lm1
        neg.l   %d0
lm1:
        move.l  8(%a7),%d1
        bpl     lm2
        neg.l   %d1
        eor.b   #0x80,4(%a7)
lm2:
        bsr     i_lmul          /* d0 = d0*d1 */
        tst.b   4(%a7)
        bpl     lm3
        neg.l   %d0
lm3:
        rts

lrem:
        move.l  4(%a7),%d0
        bpl     lr1
        neg.l   %d0
lr1:
        move.l  8(%a7),%d1
        bpl     lr2
        neg.l   %d1
lr2:
        bsr     i_ldiv          /* d1 = d0%d1 */
        move.l  %d1,%d0
        tst.b   4(%a7)
        bpl     lr3
        neg.l   %d0
lr3:
        rts

ldivu:
        move.l  4(%a7),%d0
        move.l  8(%a7),%d1
        bsr     i_ldiv
        rts

lmulu:
        move.l  4(%a7),%d0
        move.l  8(%a7),%d1
        bsr     i_lmul
        rts

lremu:
        move.l  4(%a7),%d0
        move.l  8(%a7),%d1
        bsr     i_ldiv
        move.l  %d1,%d0
        rts
*
* A in d0, B in d1, return A*B in d0
*
i_lmul:
        move.l  %d3,%a2           /* save d3 */
        move.w  %d1,%d2
        mulu    %d0,%d2           /* d2 = Al * Bl */

        move.l  %d1,%d3
        swap    %d3
        mulu    %d0,%d3           /* d3 = Al * Bh */

        swap    %d0
        mulu    %d1,%d0           /* d0 = Ah * Bl */

        add.l   %d3,%d0           /* d0 = (Ah*Bl + Al*Bh) */
        swap    %d0
        clr.w   %d0              /* d0 = (Ah*Bl + Al*Bh) << 16 */

        add.l   %d2,%d0           /* d0 = A*B */
        move.l  %a2,%d3           /* restore d3 */
        rts
*
*A in d0, B in d1, return A/B in d0, A%B in d1
*
i_ldiv:
        tst.l   %d1
        bne     nz1

*       divide by zero
*       divu    #0,%d0           /* cause trap */
        move.l  #0x80000000,%d0
        move.l  %d0,%d1
        rts
nz1:
        move.l  %d3,%a2           /* save d3 */
        cmp.l   %d1,%d0
        bhi     norm
        beq     is1
*       A<B, so ret 0, rem A
        move.l  %d0,%d1
        clr.l   %d0
        move.l  %a2,%d3           /* restore d3 */
        rts
*       A==B, so ret 1, rem 0
is1:
        moveq.l #1,%d0
        clr.l   %d1
        move.l  %a2,%d3           /* restore d3 */
        rts
*       A>B and B is not 0
norm:
        cmp.l   #1,%d1
        bne     not1
*       B==1, so ret A, rem 0
        clr.l   %d1
        move.l  %a2,%d3           /* restore d3 */
        rts
*  check for A short (implies B short also)
not1:
        cmp.l   #0xffff,%d0
        bhi     slow
*  A short and B short -- use 'divu'
        divu    %d1,%d0           /* d0 = REM:ANS */
        swap    %d0              /* d0 = ANS:REM */
        clr.l   %d1
        move.w  %d0,%d1           /* d1 = REM */
        clr.w   %d0
        swap    %d0
        move.l  %a2,%d3           /* restore d3 */
        rts
* check for B short
slow:
        cmp.l   #0xffff,%d1
        bhi     slower
* A long and B short -- use special stuff from gnu
        move.l  %d0,%d2
        clr.w   %d2
        swap    %d2
        divu    %d1,%d2           /* d2 = REM:ANS of Ahi/B */
        clr.l   %d3
        move.w  %d2,%d3           /* d3 = Ahi/B */
        swap    %d3

        move.w  %d0,%d2           /* d2 = REM << 16 + Alo */
        divu    %d1,%d2           /* d2 = REM:ANS of stuff/B */

        move.l  %d2,%d1
        clr.w   %d1
        swap    %d1              /* d1 = REM */

        clr.l   %d0
        move.w  %d2,%d0
        add.l   %d3,%d0           /* d0 = ANS */
        move.l  %a2,%d3           /* restore d3 */
        rts
*       A>B, B > 1
slower:
        move.l  #1,%d2
        clr.l   %d3
moreadj:
        cmp.l   %d0,%d1
        bhs     adj
        add.l   %d2,%d2
        add.l   %d1,%d1
        bpl     moreadj
* we shifted B until its >A or sign bit set
* we shifted #1 (d2) along with it
adj:
        cmp.l   %d0,%d1
        bhi     ltuns
        or.l    %d2,%d3
        sub.l   %d1,%d0
ltuns:
        lsr.l   #1,%d1
        lsr.l   #1,%d2
        bne     adj
* d3=answer, d0=rem
        move.l  %d0,%d1
        move.l  %d3,%d0
        move.l  %a2,%d3           /* restore d3 */
        rts
