/************************************************************* * File: pmon/mips.s * Purpose: startup code for PMON * Author: Phil Bunce (pjb@carmel.com) * Revision History: * 970304 Start of revision history * 970313 changed jal to jalr for EPI tools * 970530 Changed DCACHEI to DCACHE. Could lose data on 4010. * 971212 Always copy handler to debug exception vector * 980203 Restored 64008 ifdef to reset_exception * 980703 Replaced hostInit(0) with cpuInit() * 980703 Added code to save cpuType after cpuInit is called. * 990305 Added code to handle normal program exit w gdb. */ /* * The contents of this file are not copyrighted in any * way, and may therefore be used without restriction. */ #include /* * If you are new to MIPS assembly language programming, you will find * the following texts useful: * * "MIPS Risc Architecture", by Jerry Kane, published by Prentice Hall, * ISBN 0-13-584749-4. * * "MIPS Programmer's Handbook", by Erin Farquhar and Philip Bunce, * published by Morgan Kaufmann, ISBN 1-55860-297-6. * */ /* needed for r4000 mode */ #define eret .word 0x42000018 /* could use -mips2 sw */ #define NEWMEMSIZE .extern initial_sr,4 .text reset_exception: #ifdef LR64008 li t0,0xbff40400 li t1,0x1fc0 sh t1,(t0) .set noreorder nop nop nop nop nop .set reorder #endif la k0,_start or k0,K1BASE j k0 .align 8 #ifdef R4KEXCEPTIONS .align 9 /* bfc00200 TLB refill */ la k0,_exception li k1,K1BASE or k0,k1 j k0 .align 7 /* bfc00280 XTLB refill */ la k0,_exception li k1,K1BASE or k0,k1 j k0 .align 8 /* bfc00300 Cache error */ la k0,_exception li k1,K1BASE or k0,k1 j k0 .align 7 /* bfc00380 Others (general) */ la k0,_exception li k1,K1BASE or k0,k1 j k0 .align 10 /* bfc00400 */ addu zero,zero,zero .align 8 /* bfc00500 start of entry pt table */ #else utlb_miss_exception: la k0,_exception li k1,K1BASE or k0,k1 j k0 .align 7 general_exception: la k0,_exception li k1,K1BASE or k0,k1 j k0 .align 9 #endif /************************************************************* * util_routines: * table of entry address used by clients to access PMON's * internal routines. It's the main reason that PMON must * be built with "-G 0" (no gp addressing). * This table starts at PROM base + 0x200 */ .globl util_routines util_routines: .word read # 0 .word write # 1 .word open # 2 .word close # 3 .word ioctl # 4 .word printf # 5 .word vsprintf # 6 .word ttctl # 7 .word cliexit # 8 .word getMonEnv # 9 .word onintr # 10 .word flush_cache # 11 .word _exception # 12 #ifdef FPEM .word _fpstatesz # 13 #ifdef NEWFP .word 0 # 14 #else .word _fpinit # 14 #endif .word _fpstate # 15 .word cop1 # 16 #else .word 0 .word 0 .word 0 .word 0 #endif .word adr2symoff # 17 .word sym2adr # 18 .word getclkfreq # 19 .word _clkinit # 20 .word 0:8 # spare #define STKSIZE 8192 .comm stack,STKSIZE /* PMON's own stack */ .comm hndlrtbl,16*4 .comm flush_ptr,4 /************************************************************* * _start: * This is the entry point of the entire PROM Monitor */ .globl _start .ent _start _start: # force kSeg1 in case control is passed here from Kseg0 la t0,1f or t0,K1BASE j t0 1: # set SR and CAUSE to something sensible li v0,SR_BEV .set noreorder .set noat mtc0 v0,C0_SR mtc0 zero,C0_CAUSE #ifdef VR4300 mtc0 zero,$18 # C0_WATCHLO mtc0 zero,$19 # C0_WATCHHI #endif .set at .set reorder # Set up the CPU and enable the RAM. This routine figures out # what type of CPU this is and returns the address of the # cache flushing routine in s0. # It also returns the CPU type in s1. jal cpuInit # set up a K1seg stack la sp,stack+STKSIZE-24 or sp,K1BASE # flush the dcache li a0,DCACHEI or s0,K1BASE jal s0 li a0,FDATA jal cpdata jal clrbss #if !defined(NON_CACHED) && !defined(LR64388) # copy handler la a0,handler la a1,ehandler li a2,0x80000000 # utlb miss jal copyHandler /* always copy this. But sometimes it's pointless */ li a2,0x80000040 # debug jal copyHandler li a2,0x80000080 # general vector jal copyHandler #endif # flush the caches li a0,DCACHE # 970530 jal s0 li a0,ICACHEI jal s0 # ok to use k0seg stack now la sp,stack+STKSIZE-24 # save the flush routine ptr for later use sw s0,flush_ptr # save the CPU type for later use sw s1,cpuType /* * Provide address for use by shrc function. This feature * permits text to be placed in the PROM and to be read as a * sort of 'startup' file when PMON starts. It is normally * disabled because it can cause problems if the PROM has * junk in the end. */ #ifdef ENB_SHRC la a0,edata la t1,_fdata subu a0,t1 la t1,etext addu a0,t1 #endif la t0,pmoninit # initialize PMON jal t0 # ints might be enabled from here on ######################################################### # Set initial client conditions # # la t6,DBGREG li v0,CLIENTPC sw v0,(R_PC*12)+4(t6) jal clienttos sw v0,(R_SP*12)+4(t6) la v0,initial_a1 sw v0,(R_A1*12)+4(t6) # argv li v0,1 sw v0,(R_A0*12)+4(t6) # argc .set noreorder mfc0 v0,C0_SR nop #if !defined(NON_CACHED) && !defined(LR64388) # clear BEV # Do not clear BEV bit for 64388 because 0x80000000 does not exist. li t0,~SR_BEV and v0,t0 mtc0 v0,C0_SR #endif sw v0,initial_sr sw v0,R_STATUS*4(t6) .set reorder # # ######################################################### la t0,monmain jal t0 # transfer to main part of PMON j _start .end _start /************************************************************* * handler: * This is the handler that gets copied to the exception vector * addresses. */ .globl handler .ent handler handler: .set noat la k0,_exception j k0 ehandler: .set at .end handler /************************************************************* * _exit: * This is an exit routine, it should never be called except when PMON * is aborted while running under SABLE. */ .globl _exit .ent _exit _exit: #ifndef SABLE break 0 #endif j ra .end _exit /************************************************************* * cliexit: * This is called when a client terminates normally. */ .globl cliexit .ent cliexit cliexit: la sp,stack+STKSIZE-24 li a0,0 jal brkRemove #ifdef GDB_SUPPORT /* 990305 */ la t0,gdbmode lw t0,(t0) beq t0,zero,1f la t0,trace_mode lw t0,(t0) li a0,1 bne t0,TRACE_SS,2f li a0,2 2: j gdbstop 1: #endif j monmain .end cliexit /************************************************************* * _go: * This routine is used to transfer control to a client program. */ .globl _go .ent _go _go: li a0,2 jal swlst la k0,DBGREG # restored later /* $1 (at) */ lw v0,(R_V0*12)+4(k0) /* $2 (v0) */ lw v1,(R_V1*12)+4(k0) /* $3 (v1) */ lw a0,(R_A0*12)+4(k0) /* $4 (a0) */ lw a1,(R_A1*12)+4(k0) /* $5 (a1) */ lw a2,(R_A2*12)+4(k0) /* $6 (a2) */ lw a3,(R_A3*12)+4(k0) /* $7 (a3) */ # restored later /* $8 (t0) */ lw t1,(R_T1*12)+4(k0) /* $9 (t1) */ lw t2,(R_T2*12)+4(k0) /* $10 (t2) */ lw t3,(R_T3*12)+4(k0) /* $11 (t3) */ lw t4,(R_T4*12)+4(k0) /* $12 (t4) */ lw t5,(R_T5*12)+4(k0) /* $13 (t5) */ lw t6,(R_T6*12)+4(k0) /* $14 (t6) */ lw t7,(R_T7*12)+4(k0) /* $15 (t7) */ lw s0,(R_S0*12)+4(k0) /* $16 (s0) */ lw s1,(R_S1*12)+4(k0) /* $17 (s1) */ lw s2,(R_S2*12)+4(k0) /* $18 (s2) */ lw s3,(R_S3*12)+4(k0) /* $19 (s3) */ lw s4,(R_S4*12)+4(k0) /* $20 (s4) */ lw s5,(R_S5*12)+4(k0) /* $21 (s5) */ lw s6,(R_S6*12)+4(k0) /* $22 (s6) */ lw s7,(R_S7*12)+4(k0) /* $23 (s7) */ lw t8,(R_T8*12)+4(k0) /* $24 (t8) */ lw t9,(R_T9*12)+4(k0) /* $25 (t9) */ /* $26 (k0) */ /* $27 (k1) */ lw gp,(R_GP*12)+4(k0) /* $28 (gp) */ lw sp,(R_SP*12)+4(k0) /* $29 (sp) */ lw s8,(R_FP*12)+4(k0) /* $30 (s8) */ lw ra,(R_RA*12)+4(k0) /* $31 (ra) */ # If the mthi/mtlo are emulated k0 gets overwritten have to reload it # the .noreorder is because the assembler doesn't know about the # dependency between mtlo and la k0 and swaps them. .set noreorder lw k1,(R_HI*12)+4(k0) /* Hi */ nop mthi k1 la k0,DBGREG lw k1,(R_LO*12)+4(k0) /* Lo */ nop mtlo k1 la k0,DBGREG .set reorder .set noreorder .set noat #ifdef R4KEXCEPTIONS lw k1,(R_STATUS*12)+4(k0) # get Status nop or k1,(1<<1) # SR_EXL mtc0 k1,C0_SR # set SR nop #else # restore SR from Status but fixup the KU&IE field # to make sure that correct value is restored after the rfe mtc0 zero,C0_SR # clear IEC (and everything else) lw k1,(R_STATUS*12)+4(k0) # get Status li AT,0x3f # KU&IE mask and t0,k1,AT # get KU&IE field not AT # invert mask and k1,AT # clear KU&IE field sll t0,2 # fixup KU&IE field or k1,t0 # insert KU&IE field mtc0 k1,C0_SR # set SR #endif lw k1,(R_K1*12)+4(k0) /* $27 (k1) */ lw t0,(R_T0*12)+4(k0) /* $8 (t0) */ lw AT,(R_AT*12)+4(k0) /* $1 (AT) */ lw k0,(R_PC*12)+4(k0) /* PC */ nop #ifdef R4KEXCEPTIONS mtc0 k0,C0_EPC # I don't know exactly how many nops you need here. But is # certainly more than one. nop nop nop nop nop eret nop #else j k0 # transfer control to client rfe #endif .set at .set reorder .end _go /************************************************************* * _exception: * This routine is used to save the state of a client program after * an exception is encountered. But it first checks to see if there * is a user defined exception handler (via onintr), and then checks * to see if it's a floating-point instruction (if PMON has fp emulation * enabled.) */ .globl _exception .ent _exception _exception: .set noat la k0,DBGREG sw k1,(R_K1TMP*12)+4(k0) la k0,asm_exception_ptr lw k0,(k0) beq k0,zero,1f jalr k1,k0 # 970313 1: # if (curlst == &pmlst) branch to exc2 la k0,curlst lw k0,(k0) la k1,pmlst beq k0,k1,exc2 # skip if in PMON # see if we have a user defined handler .set noreorder mfc0 k0,C0_CAUSE nop .set reorder and k0,CAUSE_EXCMASK la k1,hndlrtbl addu k0,k1 # calc table entry addr lw k0,(k0) # get contents of table entry beq k0,zero,exc2 lw k0,4(k0) # user routine addr la k1,DBGREG lw k1,(R_K1TMP*12)+4(k1) # restore k1 j k0 # jump to user handler exc2: #ifdef FPEM /* see if it's a cp1 unusable */ .set noreorder mfc0 k0,C0_CAUSE nop .set reorder li k1,(CAUSE_CEMASK|CAUSE_EXCMASK) and k0,k1 li k1,((1<