/*
 * Copyright (c) 2003-2004 The Regents of The University of Michigan
 * Copyright (c) 1993 The Hewlett-Packard Development Company
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * Debug Monitor Entry code
 */
#include "fromHudsonOsf.h"

        .extern myAlphaAccess
        .text

/* return address and padding to octaword align */
#define STARTFRM 16

        .globl  _start
        .ent    _start, 0
_start:
_entry:
        br      t0, 2f			# get the current PC
2:	ldgp    gp, 0(t0)               # init gp

/* Processor 0 start stack frame is begining of physical memory (0)
   Other processors spin here waiting to get their stacks from
   Processor 0, then they can progress as normal.
*/
        call_pal PAL_WHAMI_ENTRY
        beq v0, cpuz
        ldq  t3, m5AlphaAccess
        addq t3,0x70,t3 # *** If offset in console alpha access struct changes
                        # This must be changed as well!
        bis  zero,8,t4
        mulq t4,v0,t4
        addq t3,t4,t3
        ldah a0, 3(zero)  # load arg0 with 65536*3
cpuwait: .long 0x6000002  # jsr quiesceNs
        ldq  t4, 0(t3)
        beq  t4, cpuwait
        bis  t4,t4,sp


cpuz:	bis	sp,sp,s0 /* save sp */

slave:	lda	v0,(8*1024)(sp) /* end of page  */

        subq	zero, 1, t0
        sll	t0, 42, t0
        bis	t0, v0, sp

        lda     sp, -STARTFRM(sp)	# Create a stack frame
        stq     ra, 0(sp)		# Place return address on the stack

        .mask   0x84000000, -8
        .frame  sp, STARTFRM, ra

/*
 *	Enable the Floating Point Unit
 */
        lda	a0, 1(zero)
        call_pal PAL_WRFEN_ENTRY

/*
 *	Every good C program has a main()
 */

/* If stack pointer was 0, then this is CPU0*/
        beq	s0,master

        call_pal PAL_WHAMI_ENTRY
        bis	v0,v0,a0
        jsr	ra, SlaveLoop
master:
        jsr	ra, main



/*
 *	The Debug Monitor should never return.
 *	However, just incase...
 */
        ldgp	gp, 0(ra)
        bsr	zero, _exit

.end	_start



        .globl  _exit
        .ent    _exit, 0
_exit:

        ldq     ra, 0(sp)		# restore return address
        lda	sp, STARTFRM(sp)	# prune back the stack
        ret	zero, (ra)		# Back from whence we came
.end	_exit

                .globl	cServe
        .ent	cServe 2
cServe:
        .option	O1
        .frame	sp, 0, ra
        call_pal PAL_CSERVE_ENTRY
        ret	zero, (ra)
        .end	cServe

        .globl	wrfen
        .ent	wrfen 2
wrfen:
        .option	O1
        .frame	sp, 0, ra
        call_pal PAL_WRFEN_ENTRY
        ret	zero, (ra)
        .end	wrfen
        .globl	consoleCallback
        .ent	consoleCallback 2
consoleCallback:
        br      t0, 2f			# get the current PC
2:	ldgp    gp, 0(t0)               # init gp
        lda     sp,-64(sp)
        stq     ra,0(sp)
        jsr     CallBackDispatcher
        ldq     ra,0(sp)
        lda     sp,64(sp)
        ret     zero,(ra)
        .end    consoleCallback


        .globl	consoleFixup
        .ent	consoleFixup 2
consoleFixup:
        br      t0, 2f			# get the current PC
2:	ldgp    gp, 0(t0)               # init gp
        lda     sp,-64(sp)
        stq     ra,0(sp)
        jsr     CallBackFixup
        ldq     ra,0(sp)
        lda     sp,64(sp)
        ret     zero,(ra)
        .end    consoleFixup



        .globl	SpinLock
        .ent	SpinLock 2
SpinLock:
1:
        ldq_l	a1,0(a0)		# interlock complete lock state
        subl	ra,3,v0			# get calling addr[31:0] + 1
        blbs	a1,2f			# branch if lock is busy
        stq_c	v0,0(a0)		# attempt to acquire lock
        beq	v0,2f			# branch if lost atomicity
        mb				# ensure memory coherence
        ret	zero,(ra)		# return to caller (v0 is 1)
2:
        br	zero,1b
        .end	SpinLock

        .globl	loadContext
        .ent	loadContext 2
loadContext:
        .option	O1
        .frame	sp, 0, ra
        call_pal PAL_SWPCTX_ENTRY
        ret	zero, (ra)
        .end	loadContext


        .globl	SlaveSpin          # Very carefully spin wait
        .ent	SlaveSpin 2        # and swap context without
SlaveSpin:                         # using any stack space
        .option	O1
        .frame	sp, 0, ra
        mov a0, t0                 # cpu number
        mov a1, t1                 # cpu rpb pointer (virtual)
        mov a2, t2                 # what to spin on
        ldah a0, 3(zero)  # load arg0 with 65536
test:   .long 0x6000002  # jsr quiesceNs     # wait 65us*3
        ldl  t3, 0(t2)
        beq  t3, test
        zapnot t1,0x1f,a0          # make rpb physical
        call_pal PAL_SWPCTX_ENTRY  # switch to pcb
        mov t0, a0                 # setup args for SlaveCmd
        mov t1, a1
        jsr SlaveCmd               # call SlaveCmd
        ret	zero, (ra)         # Should never be reached
        .end	SlaveSpin