/*
 * <vectors.S>
 *
 * Sparc V9 Trap Table(s) with SpitFire/Cheetah extensions.
 *
 *   Copyright (C) 1996, 2001 David S. Miller (davem@caip.rutgers.edu)
 *
 *   This program is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU General Public License
 *   version 2 as published by the Free Software Foundation.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *   MA  02110-1301, USA.
 *   This program is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU General Public License V2
 *   as published by the Free Software Foundation
 */

#define __ASSEMBLY
#include "psr.h"
#include "asm/asi.h"
#define SER_ADDR5  0x71100004
#define SER_ADDR10 0xf1100004

        .section ".text.vectors", "ax"
        .align 4 /* Should be 16384, but alignment is handled by the ldscript */
/* Sparc32 trap table */
        .globl trap_table, t_zero, t_wovf, t_wunf, __divide_error
trap_table:

#define WINDOW_SPILL \
        rd %psr, %l0; rd %wim, %l3; b spill_window_entry; nop;

#define WINDOW_FILL \
        rd %psr, %l0; rd %wim, %l3; b fill_window_entry; nop;

#define TRAP_DFAULT(lvl) \
        rd %psr, %l0; rd %wim, %l3; b handle_dfault; mov lvl, %l7;

#define BTRAP(lvl) ba bug; mov lvl, %g1; nop; nop;
#define BTRAPS(x) BTRAP(x) BTRAP(x+1) BTRAP(x+2) BTRAP(x+3) BTRAP(x+4) BTRAP(x+5) BTRAP(x+6) BTRAP(x+7)
#define TRAP_ENTRY_INTERRUPT(int_level) \
        sethi %hi(irq_entry ## int_level), %l7; \
        or %l7, %lo(irq_entry ## int_level), %l7; \
        jmp %l7; \
         nop

t_zero:         b entry; nop; nop; nop;
                BTRAP(0x1) BTRAP(0x2) BTRAP(0x3) BTRAP(0x4)
t_wovf:         WINDOW_SPILL                        /* Window Overflow               */
t_wunf:         WINDOW_FILL                         /* Window Underflow              */
                BTRAP(0x7)
                BTRAP(0x8)
                TRAP_DFAULT(0x9)
                BTRAP(0xa) BTRAP(0xb) BTRAP(0xc) BTRAP(0xd) BTRAP(0xe) BTRAP(0xf)
#if 0
                BAD_TRAP(0x10)
t_irq1:         TRAP_ENTRY_INTERRUPT(1)             /* IRQ Software/SBUS Level 1     */
t_irq2:         TRAP_ENTRY_INTERRUPT(2)             /* IRQ SBUS Level 2              */
t_irq3:         TRAP_ENTRY_INTERRUPT(3)             /* IRQ SCSI/DMA/SBUS Level 3     */
t_irq4:         TRAP_ENTRY_INTERRUPT(4)             /* IRQ Software Level 4          */
t_irq5:         TRAP_ENTRY_INTERRUPT(5)             /* IRQ SBUS/Ethernet Level 5     */
t_irq6:         TRAP_ENTRY_INTERRUPT(6)             /* IRQ Software Level 6          */
t_irq7:         TRAP_ENTRY_INTERRUPT(7)             /* IRQ Video/SBUS Level 5        */
t_irq8:         TRAP_ENTRY_INTERRUPT(8)             /* IRQ SBUS Level 6              */
t_irq9:         TRAP_ENTRY_INTERRUPT(9)             /* IRQ SBUS Level 7              */
t_irq10:        TRAP_ENTRY_INTERRUPT(10)            /* IRQ Timer #1 (one we use)     */
t_irq11:        TRAP_ENTRY_INTERRUPT(11)            /* IRQ Floppy Intr.              */
t_irq12:        TRAP_ENTRY_INTERRUPT(12)            /* IRQ Zilog serial chip         */
t_irq13:        TRAP_ENTRY_INTERRUPT(13)            /* IRQ Audio Intr.               */
t_irq14:        TRAP_ENTRY_INTERRUPT(14)            /* IRQ Timer #2                  */
t_nmi:          BAD_TRAP(0x1f)                      /* Level 15 (NMI)                */
#else
                BTRAPS(0x10)
                BTRAP(0x18) BTRAP(0x19)
t_irq10:        TRAP_ENTRY_INTERRUPT(10)            /* IRQ Timer #1 (one we use)     */
                BTRAP(0x1b) BTRAP(0x1c) BTRAP(0x1d)
t_irq14:        TRAP_ENTRY_INTERRUPT(14)            /* IRQ Timer #2                  */
                BTRAP(0x1f)
#endif
                BTRAPS(0x20)
                BTRAP(0x28)
                TRAP_DFAULT(0x29)
                BTRAP(0x2a) BTRAP(0x2b) BTRAP(0x2c) BTRAP(0x2d) BTRAP(0x2e) BTRAP(0x2f)
                BTRAPS(0x30) BTRAPS(0x38)
                BTRAPS(0x40) BTRAPS(0x48)
                BTRAPS(0x50) BTRAPS(0x58)
                BTRAPS(0x60) BTRAPS(0x68)
                BTRAPS(0x70) BTRAPS(0x78)
                BTRAPS(0x80) BTRAPS(0x88)
                BTRAPS(0x90) BTRAPS(0x98)
                BTRAPS(0xa0) BTRAPS(0xa8)
                BTRAPS(0xb0) BTRAPS(0xb8)
                BTRAPS(0xc0) BTRAPS(0xc8)
                BTRAPS(0xd0) BTRAPS(0xd8)
                BTRAPS(0xe0) BTRAPS(0xe8)
                BTRAPS(0xf0) BTRAPS(0xf8)

        .section ".text", "ax"
        .align 4
__divide_error:
bug:
        /* Dump the exception and its context */
        ! Set up CPU state
        rd      %psr, %g2
        andn    %g2, PSR_ET, %g2
        wr      %g2, %psr
        ! Disable mmu, re-enable boot mode
        set     _start, %g3
        set     dump_exception, %g2
        sub     %g2, %g3, %g3
        set     3 << 13, %g2
        jmp    %g3
         sta    %g2, [%g0] ASI_M_MMUREGS

outstr:
        /* void outstr (unsigned long port5, unsigned long port10,
         * const unsigned char *str);
         * Writes a string on an IO port.
         */
1:      lduba    [%o2] ASI_M_KERNELTXT, %o3
        cmp     %o3, 0
        be      2f
         nop
        stba    %o3, [%o0] ASI_M_BYPASS
        stba    %o3, [%o1] ASI_M_CTL
        b       1b
         inc    %o2
2:      retl
         nop

outhex:
        /* void outhex (unsigned long port5, unsigned long port10,
         * uint32_t value);
         * Dumps a 32 bits hex number on serial port
         */
        mov     %o2, %o4
        set     28, %o3
        srl     %o4, %o3, %o2
1:      and     %o2, 0xf, %o2
        cmp     %o2, 9
        bgt     2f
         nop
        b       3f
         add    %o2, '0', %o2
2:      add     %o2, 'a' - 10, %o2
3:      stba    %o2, [%o0] ASI_M_BYPASS
        stba    %o2, [%o1] ASI_M_CTL
        subcc   %o3, 4, %o3
        bge     1b
         srl    %o4, %o3, %o2
        retl
         nop

        /* void dump_exception ();
         *
         * Dump a message when catching an exception
         */
dump_exception:
        set     SER_ADDR5 + 2, %o0
        set     SER_ADDR10 + 2, %o1
        set     (_BUG_message_0), %o2
        call    outstr
         nop

        call    outhex
         mov    %g1, %o2

        set     (_BUG_message_1), %o2
        call    outstr
         nop

        call    outhex
         mov    %l1, %o2

        set     (_BUG_message_2), %o2
        call    outstr
         nop

        call    outhex
         mov    %l2, %o2

        set     (_BUG_message_3), %o2
        call    outstr
         nop
_forever:
        /* Loop forever */
        b       _forever                                  ;
         nop

irq_entry10:
        sethi   %hi(counter_regs), %l7
        ld      [%l7 + %lo(counter_regs)], %l7
        sethi   0x10000, %l6
        ld      [%l7 + %l6], %g0
        jmp     %l1
         rett   %l2

irq_entry14:
        sethi   %hi(counter_regs), %l7
        ld      [%l7 + %lo(counter_regs)], %l7
        ld      [%l7], %g0
        sethi   %hi(obp_ticks), %l7
        ld      [%l7 + %lo(obp_ticks)], %l7
        ld      [%l7], %l6
        add     %l6, 10, %l6
        st      %l6, [%l7]
        jmp     %l1
         rett  %l2

/* Register window handlers */
#include "wof.S"
#include "wuf.S"

/* Data fault handler */
        .data
        .align  4
        .global ignore_dfault

ignore_dfault:
        .word   0

        .text
        .align  4

handle_dfault:
        /* If ignore_dfault is 0, fall through to normal exception handler */
        sethi   %hi(ignore_dfault), %l4
        ld      [%l4 + %lo(ignore_dfault)], %l4
        tst     %l4
        bz,a    bug
         mov    %l7, %g1

        /* Otherwise skip the faulting instruction and return */
        jmp     %l2
         rett   %l2 + 4


        .section .rodata
_BUG_message_0:
        .string "Unhandled Exception 0x"
_BUG_message_1:
        .string "\r\nPC = 0x"
_BUG_message_2:
        .string " NPC = 0x"
_BUG_message_3:
        .string "\r\nStopping execution\r\n"