/* * Copyright (c) 1995, 1996, 1998 Cygnus Support * * The authors hereby grant permission to use, copy, modify, distribute, * and license this software and its documentation for any purpose, provided * that existing copyright notices are retained in all copies and that this * notice is included verbatim in any distributions. No written agreement, * license, or royalty fee is required for any of the authorized uses. * Modifications to this software may be copyrighted by their authors * and need not follow the licensing terms described here, provided that * the new terms are clearly indicated on the first page of each file where * they apply. */ #include "asm.h" #include "slite.h" .register %g2, #scratch .register %g3, #scratch .text .align 4 /* * The trap table has to be the first code in a boot PROM. But because * the Memory Configuration comes up thinking we only have 4K of PROM, we * cannot have a full trap table and still have room left over to * reprogram the Memory Configuration register correctly. This file * uses an abbreviated trap which has every entry which might be used * before RTEMS installs its own trap table. */ .globl _trap_table _trap_table: TRAP(SYM(ercinit)); ! 00 reset trap BAD_TRAP; ! 01 instruction access exception TRAP(SYM(no_fpu)); ! 02 illegal instruction BAD_TRAP; ! 03 privileged instruction BAD_TRAP; ! 04 fp disabled TRAP(SYM(win_overflow)); ! 05 window overflow TRAP(SYM(win_underflow)); ! 06 window underflow BAD_TRAP; ! 07 memory address not aligned BAD_TRAP; ! 08 fp exception BAD_TRAP; ! 09 data access exception BAD_TRAP; ! 0A tag overflow /* Trap levels from 0B to 0x10 are not defined (used for MEC init) */ SYM(ercinit): sethi %hi(_ERC32_MEC), %g1 ! 0B sethi %hi(0x001C1000), %g2 or %g1,%lo(0x001C1000),%g1 st %g2, [%g1 + 0x10] st %g0, [%g1 + 0x18] ! 0C nop nop nop TRAP(SYM(hard_reset)); ! 0D undefined BAD_TRAP; ! 0E undefined BAD_TRAP; ! 0F undefined BAD_TRAP; ! 10 undefined /* * ERC32 defined traps */ BAD_TRAP; ! 11 masked errors BAD_TRAP; ! 12 external 1 BAD_TRAP; ! 13 external 2 BAD_TRAP; ! 14 UART A RX/TX BAD_TRAP; ! 15 UART B RX/TX BAD_TRAP; ! 16 correctable memory error BAD_TRAP; ! 17 UART error BAD_TRAP; ! 18 DMA access error BAD_TRAP; ! 19 DMA timeout BAD_TRAP; ! 1A external 3 BAD_TRAP; ! 1B external 4 BAD_TRAP; ! 1C general purpose timer BAD_TRAP; ! 1D real time clock BAD_TRAP; ! 1E external 5 BAD_TRAP; ! 1F watchdog timeout BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 20 - 23 undefined BAD_TRAP; ! 24 cp_disabled BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 25 - 27 undefined BAD_TRAP; ! 28 cp_exception BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 29 - 2B undefined BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 2C - 2F undefined BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 30 - 33 undefined BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 34 - 37 undefined BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 38 - 3B undefined BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 3C - 3F undefined BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 40 - 43 undefined BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 44 - 47 undefined BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 48 - 4B undefined BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 4C - 4F undefined BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 50 - 53 undefined BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 54 - 57 undefined BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 58 - 5B undefined BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 5C - 5F undefined BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 60 - 63 undefined BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 64 - 67 undefined BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 68 - 6B undefined BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 6C - 6F undefined BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 70 - 73 undefined BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 74 - 77 undefined BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 78 - 7B undefined BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 7C - 7F undefined /* * Software traps * * NOTE: At the risk of being redundant... this is not a full * table. The setjmp on the SPARC requires a window flush trap * handler and RTEMS will preserve the entries that were * installed before. */ SOFT_TRAP; ! 80 #if 0 SOFT_TRAP; ! 81 #else TRAP(SYM(trap_low)) ! 81 #endif SOFT_TRAP; ! 82 TRAP(SYM(win_flush)); ! 83 flush windows SW trap SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 84 - 87 SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 88 - 8B SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 8C - 8F SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 90 - 93 SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 94 - 97 SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 98 - 9B SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 9C - 9F SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! A0 - A3 SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! A4 - A7 SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! A8 - AB SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! AC - AF SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! B0 - B3 SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! B4 - B7 SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! B8 - BB SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! BC - BF SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! C0 - C3 SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! C4 - C7 SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! C8 - CB SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! CC - CF SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! D0 - D3 SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! D4 - D7 SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! D8 - DB SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! DC - DF SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! E0 - E3 SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! E4 - E7 SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! E8 - EB SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! EC - EF SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! F0 - F3 SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! F4 - F7 SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! F8 - FB SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! FC - FF /* * Startup code for standalone system. Wash IU and FPU (if present) * registers. The registers have to be written to initiate the parity * bits. */ .globl SYM(hard_reset) SYM(hard_reset): sethi %hi(0x01FE0),%o0 or %o0,%lo(0x01FE0),%o0 mov %o0, %psr ! Set valid PSR nop mov %g0, %wim ! Set window invalid mask register mov %g0, %y ! Init Y-register nop sethi %hi(SYM(hard_reset)), %g1 mov %g1, %tbr ! Set TBR sethi %hi(SP_INIT),%sp or %g0, 1, %o0 ld [%g0], %f0 ! Check if FPU is present tst %o0 bz fixiu nop ba fixfpu ! FPU disabled trap address clr %i0 jmpl %l2, %g0 rett %l2 + 4 nop ! Wash register files (fix for 90C601E & 90C602E) fixfpu: ld [%g0], %f0 ld [%g0], %f1 ld [%g0], %f2 ld [%g0], %f3 ld [%g0], %f4 ld [%g0], %f5 ld [%g0], %f6 ld [%g0], %f7 ld [%g0], %f8 ld [%g0], %f9 ld [%g0], %f10 ld [%g0], %f11 ld [%g0], %f12 ld [%g0], %f13 ld [%g0], %f14 ld [%g0], %f15 ld [%g0], %f16 ld [%g0], %f17 ld [%g0], %f18 ld [%g0], %f19 ld [%g0], %f20 ld [%g0], %f21 ld [%g0], %f22 ld [%g0], %f23 ld [%g0], %f24 ld [%g0], %f25 ld [%g0], %f26 ld [%g0], %f27 ld [%g0], %f28 ld [%g0], %f29 ld [%g0], %f30 ld [%g0], %f31 fixiu: clr %g1 clr %g2 clr %g3 clr %g4 clr %g5 clr %g6 clr %g7 set 8,%g1 wl0: clr %i0 clr %i1 clr %i2 clr %i3 clr %i4 clr %i5 clr %i6 clr %i7 clr %l0 clr %l1 clr %l2 clr %l3 clr %l4 clr %l5 clr %l6 clr %l7 save subcc %g1, 1, %g1 bne wl0 nop ! ! Start the real-time clock with a tick of 150 clocks ! rtc: set 0x1f80000, %l0 ! MEC register base set 149, %l1 st %l1, [%l0 + 0x84] ! RTC scaler = 149 set 0x0d00, %l1 st %l1, [%l0 + 0x98] ! Start RTC st %g0, [%l0 + 0x64] ! Disable watchdog for now ld [%l0], %g1 or %g1, 1, %g1 st %g1, [%l0] ! Enable power-down mode _init: set PSR_INIT, %g1 ! Initialize psr mov %g1, %psr set WIM_INIT, %g1 ! Initialize WIM mov %g1, %wim set _trap_table, %g1 ! Initialize TBR mov %g1, %tbr nop;nop;nop set PSR_INIT, %g1 wr %g1, 0x20, %psr ! enable traps nop; nop; nop; call SYM(start) nop /* * Register window overflow handler. Come here when save would move us * into the invalid window. This routine runs with traps disabled, and * must be careful not to touch the condition codes, as PSR is never * restored. * * We are called with %l0 = wim, %l1 = pc, %l2 = npc */ .globl SYM(win_overflow) SYM(win_overflow): mov %g1, %l3 ! Save g1, we use it to hold the wim srl %l0, 1, %g1 ! Rotate wim right sll %l0, NUMBER_OF_REGISTER_WINDOWS - 1, %l0 or %l0, %g1, %g1 save %g0, %g0, %g0 ! Slip into next window mov %g1, %wim ! Install the new wim nop nop nop std %l0, [%sp + 0 * 4] ! save L & I registers std %l2, [%sp + 2 * 4] std %l4, [%sp + 4 * 4] std %l6, [%sp + 6 * 4] std %i0, [%sp + 8 * 4] std %i2, [%sp + 10 * 4] std %i4, [%sp + 12 * 4] std %i6, [%sp + 14 * 4] restore ! Go back to trap window. mov %l3, %g1 ! Restore %g1 jmpl %l1, %g0 rett %l2 /* * Register window underflow handler. Come here when restore would move us * into the invalid window. This routine runs with traps disabled, and * must be careful not to touch the condition codes, as PSR is never * restored. * * We are called with %l0 = wim, %l1 = pc, %l2 = npc */ .globl SYM(win_underflow) SYM(win_underflow): sll %l0, 1, %l3 ! Rotate wim left srl %l0, NUMBER_OF_REGISTER_WINDOWS - 1, %l0 or %l0, %l3, %l0 mov %l0, %wim ! Install the new wim restore ! Users window restore ! His callers window ldd [%sp + 0 * 4], %l0 ! restore L & I registers ldd [%sp + 2 * 4], %l2 ldd [%sp + 4 * 4], %l4 ldd [%sp + 6 * 4], %l6 ldd [%sp + 8 * 4], %i0 ldd [%sp + 10 * 4], %i2 ldd [%sp + 12 * 4], %i4 ldd [%sp + 14 * 4], %i6 save %g0, %g0, %g0 ! Back to trap window save %g0, %g0, %g0 jmpl %l1, %g0 rett %l2 /* * Register window flush handler, triggered by a "ta 3" instruction. * We are called with %l0 = wim, %l1 = pc, %l2 = npc */ .globl SYM(win_flush) SYM(win_flush): mov %psr, %l0 or %l0,0xf00,%l3 ! Disable interrupts mov %l3,%psr nop nop nop mov %wim, %l3 srl %l3, %l0, %l4 ! wim >> cwp cmp %l4, 1 bne flush_window_fine ! Branch if not in the invalid window nop /* Handle window overflow. We can't trap here. */ mov %g1, %l4 ! Save g1, we use it to hold the wim srl %l3, 1, %g1 ! Rotate wim right sll %l3, NUMBER_OF_REGISTER_WINDOWS - 1, %l3 or %l3, %g1, %g1 mov %g0, %wim ! Clear wim so that subsequent save nop ! wont trap nop nop save %g0, %g0, %g0 ! Slip into next window mov %g1, %wim ! Install the new wim std %l0, [%sp + 0 * 4] ! save L & I registers std %l2, [%sp + 2 * 4] std %l4, [%sp + 4 * 4] std %l6, [%sp + 6 * 4] std %i0, [%sp + 8 * 4] std %i2, [%sp + 10 * 4] std %i4, [%sp + 12 * 4] std %i6, [%sp + 14 * 4] restore ! Go back to trap window. mov %l4, %g1 ! Restore %g1 flush_window_fine: mov %psr,%l5 ! enable traps or %l5,0x20,%l5 mov %l5, %psr nop nop nop set save_buf,%l5 st %l2,[%l5] ! The stack pointer currently contains a bogus value [when a trap ! occurs CWP is decremented and points to an unused window]. ! Give it something useful before we flush every window. ! This does what a "save %sp,-64,$sp" would, except that CWP has ! already been decremented. add %fp, -64, %sp save %sp, -64, %sp ! Flush user register window to stack save %sp, -64, %sp save %sp, -64, %sp save %sp, -64, %sp save %sp, -64, %sp save %sp, -64, %sp save %sp, -64, %sp save %sp, -64, %sp restore restore restore restore restore restore restore restore restore ! Make sure we have a valid window save %g0, %g0, %g0 set save_buf, %l2 ! Get our return address back ld [%l2],%l2 mov %psr,%l5 ! disable traps for rett andn %l5,0x20,%l5 mov %l5,%psr nop nop nop jmpl %l2, %g0 rett %l2+4 /* * Read the TBR. */ .globl SYM(rdtbr) SYM(rdtbr): mov %tbr, %o0 nop retl nop /* * Read the psr */ .globl SYM(read_psr) SYM(read_psr): mov %psr, %o0 nop retl nop /* * Write the PSR. */ .globl SYM(write_psr) SYM(write_psr): mov %i0, %psr nop nop nop retl nop /* * Come here when no fpu exists. This just skips the offending * instruction. */ .globl SYM(no_fpu) SYM(no_fpu): jmpl %l2, %g0 rett %l2+4 .globl SYM(fltr_proto) .align 4 SYM(fltr_proto): ! First level trap routine prototype sethi 0, %l0 jmpl 0+%l0, %g0 nop nop /* * Trap handler for memory errors. This just sets mem_err to be * non-zero. It assumes that l1 is non-zero. This should be safe, * as it is doubtful that 0 would ever contain code that could mem * fault. This routine will skip past the faulting instruction after * setting mem_err. */ .globl SYM(fltr_set_mem_err) SYM(fltr_set_mem_err): sethi %hi(SYM(mem_err)), %l0 st %l1, [%l0 + %lo(SYM(mem_err))] jmpl %l2, %g0 rett %l2+4 .data .align 4 .ascii "DaTa" .long SYM(sdata) in_trap_handler: .word 0 save_buf: .word 0 /* place to save %g1 */ .word 0 /* place to save %g2 */ .text .align 4 /* * This function is called when any SPARC trap (except window overflow * or underflow) occurs. It makes sure that the invalid register * window is still available before jumping into C code. It will also * restore the world if you return from handle_exception. */ .globl SYM(trap_low) SYM(trap_low): mov %psr, %l0 mov %wim, %l3 srl %l3, %l0, %l4 ! wim >> cwp cmp %l4, 1 bne window_fine ! Branch if not in the invalid window nop mov %g1, %l4 ! Save g1, we use it to hold the wim srl %l3, 1, %g1 ! Rotate wim right sll %l3, 8-1, %l5 or %l5, %g1, %g1 save %g0, %g0, %g0 ! Slip into next window mov %g1, %wim ! Install the new wim std %l0, [%sp + 0 * 4] ! save L & I registers std %l2, [%sp + 2 * 4] std %l4, [%sp + 4 * 4] std %l6, [%sp + 6 * 4] std %i0, [%sp + 8 * 4] std %i2, [%sp + 10 * 4] std %i4, [%sp + 12 * 4] std %i6, [%sp + 14 * 4] restore ! Go back to trap window. mov %l4, %g1 ! Restore g1 window_fine: sethi %hi(in_trap_handler), %l4 ld [%lo(in_trap_handler) + %l4], %l5 tst %l5 bg recursive_trap inc %l5 /* use the stack we set in the linker script */ sethi %hi(__trap_stack), %l6 or %l6,%lo(__trap_stack),%l6 mov %l6, %sp ! set the stack pointer recursive_trap: st %l5, [%lo(in_trap_handler) + %l4] sub %sp,(16+1+6+1+72)*4,%sp ! Make room for input & locals ! + hidden arg + arg spill ! + doubleword alignment ! + registers[72] local var std %g0, [%sp + (24 + 0) * 4] ! registers[Gx] std %g2, [%sp + (24 + 2) * 4] std %g4, [%sp + (24 + 4) * 4] std %g6, [%sp + (24 + 6) * 4] std %i0, [%sp + (24 + 8) * 4] ! registers[Ox] std %i2, [%sp + (24 + 10) * 4] std %i4, [%sp + (24 + 12) * 4] std %i6, [%sp + (24 + 14) * 4] ! F0->F31 not implemented mov %y, %l4 mov %tbr, %l5 st %l4, [%sp + (24 + 64) * 4] ! Y st %l0, [%sp + (24 + 65) * 4] ! PSR st %l3, [%sp + (24 + 66) * 4] ! WIM st %l5, [%sp + (24 + 67) * 4] ! TBR st %l1, [%sp + (24 + 68) * 4] ! PC st %l2, [%sp + (24 + 69) * 4] ! NPC ! CPSR and FPSR not implemented or %l0, 0xf20, %l4 mov %l4, %psr ! Turn on traps, disable interrupts call SYM(handle_exception) add %sp, 24 * 4, %o0 ! Pass address of registers /* Reload all of the registers that aren't on the stack */ ld [%sp + (24 + 1) * 4], %g1 ! registers[Gx] ldd [%sp + (24 + 2) * 4], %g2 ldd [%sp + (24 + 4) * 4], %g4 ldd [%sp + (24 + 6) * 4], %g6 ldd [%sp + (24 + 8) * 4], %i0 ! registers[Ox] ldd [%sp + (24 + 10) * 4], %i2 ldd [%sp + (24 + 12) * 4], %i4 ldd [%sp + (24 + 14) * 4], %i6 ldd [%sp + (24 + 64) * 4], %l0 ! Y & PSR ldd [%sp + (24 + 68) * 4], %l2 ! PC & NPC restore ! Ensure that previous window is valid save %g0, %g0, %g0 ! by causing a window_underflow trap mov %l0, %y mov %l1, %psr ! Make sure that traps are disabled ! for rett sethi %hi(in_trap_handler), %l4 ld [%lo(in_trap_handler) + %l4], %l5 dec %l5 st %l5, [%lo(in_trap_handler) + %l4] jmpl %l2, %g0 ! Restore old PC rett %l3 ! Restore old nPC