 #*****************************************************************************
 #
 #                                  Cpu_ext
 #
 # This module contains the assemly routines for the CPU driver.
 #
 # Note that comment lines must begin with a blank so cpp will not regard 
 # them.
 #
 # History:
 #   +----------+------------+------------------------------------------------+
 #   |   Date   |     by     |     Description                                |
 #   +----------+------------+------------------------------------------------+
 #   |          | Coby       | Written                                        |
 #   +----------+------------+------------------------------------------------+
 #
 #*****************************************************************************


	.file	"cpu_e.s"

#include "global.h"
#include "reset.h"

#define NUM_OF_CPU_REGS  22


 #
 # List of global functions defined in this routine
 # Note the routine are defined in C style
 #
#ifndef public
extern void		call_bpt__(/*addr*/);
extern void		begin_bpt__(/*addr*/);
extern void		get_in__(/*addr*/);
extern void		mod_in__(/*addr*/);
extern void		get_cfg__(/*addr*/);
extern void		mod_cfg__(/*addr*/);
extern void		mod_cfg__(/*addr*/);
extern void		get_dcr__(/*addr*/);
extern void		mod_dcr__(/*addr*/);
extern void		get_dsr__(/*addr*/);
extern void		mod_dsr__(/*addr*/);
extern void		get_car__(/*addr*/);
extern void		mod_car__(/*addr*/);
extern void		get_bpc__(/*addr*/);
extern void		mod_bpc__(/*addr*/);

#endif


 #
 # Define global variables
 #

	.comm	_cmon_sp__,4
	.comm	_cmon_fp__,4
	.comm	_cmon_sb__,4
	.comm	_saved_user_cpu_regs__,NUM_OF_CPU_REGS*4
#ifdef DEBUG
	.comm	_ram_intbase__,4
	.comm	_rom_intbase__,4
#endif
	.globl  _END_BSS__
	.globl	rom_module_table__,ram_module_table__
	.globl  normal_intbase__, de_intbase__
	.globl  end_init_cpu__


 #
 # Define local variables
 #
		.udata			# bss section
ret_addr:	.blkd
sb_saved:	.blkb

		.text
 #/*^L*/
 #-----------------------------------------------------------------------------
 #
 #                                 Init_cpu
 #
 # This routine is called as part of the reset procedure. It initializes the
 # CMON and user cpu registers.
 #
 #-----------------------------------------------------------------------------

init_cpu__::
#ifdef DEBUG
	movd	$9, r0			# change to superviser mode
	movd	$0x55555555, r1
	svc				

	bicpsrw $0x200			# use is
#endif
	movd	$CMON_MOD,r7		# build the module table
	movd	$rom_module_table__, r0
	cmpd	r0, r7
	beq	1f
	movmd	0(r0), 0(r7),4	# (it has to be in first 64K of memory)
1:
	lprw	mod,r7			#
	lprd	sb,0(r7)		# load sb
#if (NON_DE_AVAILABLE)
	movd	$normal_intbase__,r7	# load intbase, non direct-exception
#else
	movd	$de_intbase__,r7	# load intbase, direct-exception
#endif
#ifndef DEBUG
	lprd	intbase,r7		#
#else
	movd	r7,_ram_intbase__	# on ram monitor don't change intbase
#endif
#if (CORE_TYPE == GX)
	lprd	cfg,$0xa00		# enable data + instruction caches
	movd	$0xa00, _save_CFG__	# update saved cfg
	movd	r0, _save_R0__		# save r0 (last pc)
	movd	r1, _save_R1__		# save r0 (last psr)
#else
#if (NON_DE_AVAILABLE)
	setcfg	[]			# default cfg
	movqd	0, _save_CFG__		# update saved cfg
#else
	setcfg	[de]			# default cfg
	movd	$0x100, _save_CFG__	# update saved cfg
#endif
#endif
	movd	$_end_cmon_stack__ ,r7
	addd    $(C_IS_SIZE-4) ,r7
	movd	r7, _cmon_sp__		# load sp
	lprd	sp,r7			#
	movqd	0,_cmon_fp__		# inizialize cmons fp
	movd	$_end_interrupt_stack__ ,r7
	addd	$(IS_SIZE-4),r7		# 
	movd	r7, _save_IS__		#
	movqd	0, _save_PC__		# update saved pc
	movqd	0, _save_PSR__		# update saved psr
	br	end_init_cpu__




 #/*^L*/
 #-----------------------------------------------------------------------------
 #
 #                           Save_user_cpu_regs
 #
 # This routine is called always before entering monitor time.
 # It saves the users cpu registers, and loads them with the values
 # needed by CMON.
 # Note that the values of the SB (and possibly CFG) registers might have 
 # already been saved by the save_sb function.
 # All the regs are saved here, even though intbase for example doesn't have
 # to be, for the convenience of the CPU driver print and change functions.
 # If needed, the msr/mcr are also saved.
 #
 #-----------------------------------------------------------------------------

save_user_cpu_regs::
        movd    0(sp),ret_addr		# save ret addr of calling routine
	movzwd	8(sp), _save_MO__	# save mod of user program
	movzwd	10(sp), _save_PSR__	# save psr
	movd    4(sp), _save_PC__	# save pc
	addr    12(sp), _save_IS__	# save is
	bispsrw $0x200			# set psr-s /* switch to user stack */
	addr    0(sp), _save_US__	# save us
	bicpsrw $0x200			# return to superviser  stack
	sprd    fp, _save_FP__		# save fp

					#
					# Save of CFG in case it can be read
					#
#if (CORE_TYPE == GX)
	sprd	cfg, _save_CFG__
#endif

					#
					# Save SB 
					#   In Non direct exception extract
					#   from mod table.
					#   In direct exception read directly 
					#   from register.
					#
#if (DE_AVAILABLE)
	tbitb	$CFG_DE, _save_CFG__	# direct_exception = cfg_bit
	bfc	nondirect		# if (direct_exception) { 
	sprd	sb, _save_SB__		#   Save sb 
	br	save_gen_regs		# }
nondirect:				# else {
#endif
	movd    _save_MO__, tos
	movd	0(0(sp)),_save_SB__	#   save sb from module table
save_gen_regs:				# }
	movd	r0,_save_R0__		# save R0
	movd	r1,_save_R1__		# save R1
	movd	r2,_save_R2__		# save R2
	movd	r3,_save_R3__		# save R3
	movd	r4,_save_R4__		# save R4
	movd	r5,_save_R5__		# save R5
	movd	r6,_save_R6__		# save R6
	movd	r7,_save_R7__		# save R7
	lprw    psr,$0			# Initialize  CMON psr
	lprd    sp,_cmon_sp__		# load CMON sp (to Interrupt stack)
	lprd    fp,_cmon_fp__		# load CMON fp
	movd    ret_addr,tos		# put return address on stack
	ret	0



 #/*^L*/

 #-----------------------------------------------------------------------------
 #
 #                           Load_user_cpu_regs
 #
 # This routine is called always just before exiting monitor time.
 # It loads the cpu registers with the values they contained at user time.
 # The CFG and INTBASE registers are not loaded since they have the same value
 # as in monitor time.
 # If needed, the msr/mcr are also loaded.
 #
 #-----------------------------------------------------------------------------

load_user_cpu_regs::
        movd    tos,ret_addr		# save ret addr of calling routine
	bispsrw $0x200			# set psr-s /* switch to user stack */
	lprd    sp,_save_US__		# load us
	lprd    fp,_save_FP__		# load fp
	lprd	sb,_save_SB__		# load SB This will be over writen in
					# Non direct exception mode
	bicpsrw $0x200			# clear psr-s
	movd	_save_R0__,r0		# load r0
	movd	_save_R1__,r1		# load r1
	movd	_save_R2__,r2		# load r2
	movd	_save_R3__,r3		# load r3
	movd	_save_R4__,r4		# load r4
	movd	_save_R5__,r5		# load r5
	movd	_save_R6__,r6		# load r6
	movd	_save_R7__,r7		# load r7
	lprd    sp,_save_IS__		# load is
	cbitb	$PSR_P,_save_PSR__	# clear psr-p /* no pending trace */
	movw	_save_PSR__,tos		# push psr    /* return parameter */
	movw	_save_MO__,tos		# push mod    /* return parameter */
	movd	_save_PC__,tos		# push pc     /* return parameter */
	movd	ret_addr,tos		# put return address on stack
	ret	0			# return 

 #----------------------------------------------------------------------------
 #
 #    Two globaly defined labels on BPT instruction.
 #    They are used to implement the BEGIN and two CALLs command.
 #    The return address pushed onto the stack are those labels.
 #
 #    NOTE this implementation of the above command differs from the old 
 #         monitor implementation and will not work in MMU environment,
 #         nevertheless it is cleaner and will work no mater which stack is
 #         chosen.
 #
 #----------------------------------------------------------------------------

_call_bpt__::
	bpt

_begin_bpt__::
	bpt



 ##----------------------------------------------------------------------------
 ## 
 ## The following functions implements some of the table driven get/mod 
 ## commands for the CPU register that dose not simply use their copy
 ##
 ## The standart format in C languege for this commands are:
 ##	    get_<reg>__(addr)   Will copy into addr reg contents
 ##	    mod_<reg>__(addr)	Will copy into reg addr contents
 ##---------------------------------------------------------------------------
 
 
 #-----------------------------------------------------------------------------
 #
 #                           _get_in__
 #
 # This routine is used to read the current value of the intbase register.
 #
 #-----------------------------------------------------------------------------

_get_in__::

#ifdef DEBUG
	movd	_ram_intbase__, 0(4(sp))
#else
	sprd	intbase, 0(4(sp))
#endif
	ret 0
 #-----------------------------------------------------------------------------
 #
 #                           _mod_in__
 #
 # This routine is used to modify the value of the intbase register.
 #
 #-----------------------------------------------------------------------------

_mod_in__::

#ifdef DEBUG
	movd	0(4(sp)), _ram_intbase__
#else
	lprd	intbase, 0(4(sp))
#endif
	ret 0

 #----------------------------------------------------------------------------
 #			    _get_cfg__
 #
 # This routine is used to read the value of the cfg register.
 # NOTE: If the sprd cfg is supported then this instruction is simply executed
 #	 other wise the cfg internal copy is read
 #
 #-----------------------------------------------------------------------------

#if (CORE_TYPE == GX)
_get_cfg__::
	sprd	cfg, 0(4(sp))
	ret	0
#endif

 #-----------------------------------------------------------------------------
 #
 #                           _mod_cfg__
 #
 # This routine is used to modify the value of the cfg register.
 # NOTE: If the lprd cfg is supported then this instruction is simply executed
 #	 other wise it is emulated
 #
 #-----------------------------------------------------------------------------

#if (CORE_TYPE == GX)
_mod_cfg__::

	lprd	cfg,0(4(sp))
	ret 0

#endif
#if (CORE_TYPE == CG )
 #-----------------------------------------------------------------------------
 #
 # NOTE: this routine is used where the lprx cfg instruction is not supported
 #       the routine uses self modified code to create setcfg  [xxx] 
 #       instruction. 
 #
 #-----------------------------------------------------------------------------

	.comm	jmpram,0x10

_mod_cfg__::
	movd	0(4(sp)), _save_CFG__
	movd	scfgl,jmpram	        #   copy setcfg instruction to ram
	movw	ret0,jmpram+4	        # copy ret 0
	movzwd  0(4(sp)), r1
   	lshw    $7,r1
   	andw	$0x787f,jmpram+1
   	orw	r1,jmpram+1
	jsr	jmpram		        # jump to ram
	ret	0
	
	
scfgl:	setcfg	[]			# (* setcfg instructin *)
	nop
ret0:	ret	0			# ret 0 instruction


#endif 



#if (CORE_TYPE == GX )
 #
 #-----------------------------------------------------------------------------
 #
 # The Following routines get and put GX CORE Hardware breakpoint registers
 #
 #-----------------------------------------------------------------------------

_get_dcr__::
	sprd	dcr, 0(4(sp))
	ret	0

_mod_dcr__::
	lprd	dcr, 0(4(sp))
	ret	0


_get_dsr__::
	sprd	dsr, 0(4(sp))
	ret	0

_mod_dsr__::
	lprd	dsr, 0(4(sp))
	ret	0


_get_car__::
	sprd	car, 0(4(sp))
	ret	0

_mod_car__::
	lprd	car, 0(4(sp))
	ret	0


_get_bpc__::
	sprd	bpc, 0(4(sp))
	ret	0

_mod_bpc__::
	lprd	bpc, 0(4(sp))
	ret	0


#endif

