Files
BaS_gcc/BaS_gcc/sys/exceptions.S
2015-01-09 15:08:44 +00:00

551 lines
23 KiB
ArmAsm

/*
* initialize exception vectors
*
* This file is part of BaS_gcc.
*
* BaS_gcc is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* BaS_gcc 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 BaS_gcc. If not, see <http://www.gnu.org/licenses/>.
*
* Created on: 26.02.2013
* Author: Markus Fröschle
*/
#include "startcf.h"
#if MACHINE_FIREBEE
#include "firebee.h"
#elif MACHINE_M5484LITE
#include "m5484l.h"
#endif /* MACHINE_FIREBEE */
.extern __SUP_SP
.extern _rom_entry
.extern __RAMBAR0
.extern _rt_mod
.extern _rt_ssp
.extern _rt_usp
.extern _rt_vbr
.extern _mmutr_miss
.extern __MBAR
.extern __MMUBAR
.extern _video_tlb
.extern _video_sbt
.extern _flush_and_invalidate_caches
.extern _get_bas_drivers
/* PCI interrupt handlers */
.extern _irq5_handler
.extern _irq6_handler
.extern _irq7_handler
.global _vec_init
.global _std_exc_vec /* needed by driver_vec.c */
/* Register read/write equates */
/* MMU */
.equ MCF_MMU_MMUCR, __MMUBAR
.equ MCF_MMU_MMUOR, __MMUBAR+0x04
.equ MCF_MMU_MMUSR, __MMUBAR+0x08
.equ MCF_MMU_MMUAR, __MMUBAR+0x10
.equ MCF_MMU_MMUTR, __MMUBAR+0x14
.equ MCF_MMU_MMUDR, __MMUBAR+0x18
/* EPORT flag register */
.equ MCF_EPORT_EPFR, __MBAR+0xf0c
/* FEC1 port output data direction register */
.equ MCF_GPIO_PODR_FEC1L, __MBAR+0xa07
/* PSC0 transmit buffer register */
.equ MCF_PSC0_PSCTB_8BIT, __MBAR+0x860c
/* GPT mode select register */
.equ MCF_GPT0_GMS, __MBAR+0x800
/* Slice timer 0 count register */
.equ MCF_SLT0_SCNT, __MBAR+0x908
// interrupt sources
.equ INT_SOURCE_EPORT_EPF1,1 // edge port flag 1
.equ INT_SOURCE_EPORT_EPF2,2 // edge port flag 2
.equ INT_SOURCE_EPORT_EPF3,3 // edge port flag 3
.equ INT_SOURCE_EPORT_EPF4,4 // edge port flag 4
.equ INT_SOURCE_EPORT_EPF5,5 // edge port flag 5
.equ INT_SOURCE_EPORT_EPF6,6 // edge port flag 6
.equ INT_SOURCE_EPORT_EPF7,7 // edge port flag 7
.equ INT_SOURCE_USB_EP0ISR,15 // USB endpoint 0 interrupt
.equ INT_SOURCE_USB_EP1ISR,16 // USB endpoint 1 interrupt
.equ INT_SOURCE_USB_EP2ISR,17 // USB endpoint 2 interrupt
.equ INT_SOURCE_USB_EP3ISR,18 // USB endpoint 3 interrupt
.equ INT_SOURCE_USB_EP4ISR,19 // USB endpoint 4 interrupt
.equ INT_SOURCE_USB_EP5ISR,20 // USB endpoint 5 interrupt
.equ INT_SOURCE_USB_EP6ISR,21 // USB endpoint 6 interrupt
.equ INT_SOURCE_USB_USBISR,22 // USB general interrupt
.equ INT_SOURCE_USB_USBAISR,23 // USB core interrupt
.equ INT_SOURCE_USB_ANY,24 // OR of all USB interrupts
.equ INT_SOURCE_USB_DSPI_OVF,25 // DSPI overflow or underflow
.equ INT_SOURCE_USB_DSPI_RFOF,26 // receive FIFO overflow interrupt
.equ INT_SOURCE_USB_DSPI_RFDF,27 // receive FIFO drain interrupt
.equ INT_SOURCE_USB_DSPI_TFUF,28 // transmit FIFO underflow interrupt
.equ INT_SOURCE_USB_DSPI_TCF,29 // transfer complete interrupt
.equ INT_SOURCE_USB_DSPI_TFFF,30 // transfer FIFO fill interrupt
.equ INT_SOURCE_USB_DSPI_EOQF,31 // end of queue interrupt
.equ INT_SOURCE_PSC3,32 // PSC3 interrupt
.equ INT_SOURCE_PSC2,33 // PSC2 interrupt
.equ INT_SOURCE_PSC1,34 // PSC1 interrupt
.equ INT_SOURCE_PSC0,35 // PSC0 interrupt
.equ INT_SOURCE_CTIMERS,36 // combined source for comm timers
.equ INT_SOURCE_SEC,37 // SEC interrupt
.equ INT_SOURCE_FEC1,38 // FEC1 interrupt
.equ INT_SOURCE_FEC0,39 // FEC0 interrupt
.equ INT_SOURCE_I2C,40 // I2C interrupt
.equ INT_SOURCE_PCIARB,41 // PCI arbiter interrupt
.equ INT_SOURCE_CBPCI,42 // COMM bus PCI interrupt
.equ INT_SOURCE_XLBPCI,43 // XLB PCI interrupt
.equ INT_SOURCE_XLBARB,47 // XLBARB to PCI interrupt
.equ INT_SOURCE_DMA,48 // multichannel DMA interrupt
.equ INT_SOURCE_CAN0_ERROR,49 // FlexCAN error interrupt
.equ INT_SOURCE_CAN0_BUSOFF,50 // FlexCAN bus off interrupt
.equ INT_SOURCE_CAN0_MBOR,51 // message buffer ORed interrupt
.equ INT_SOURCE_SLT1,53 // slice timer 1 interrupt
.equ INT_SOURCE_SLT0,54 // slice timer 0 interrupt
.equ INT_SOURCE_CAN1_ERROR,55 // FlexCAN error interrupt
.equ INT_SOURCE_CAN1_BUSOFF,56 // FlexCAN bus off interrupt
.equ INT_SOURCE_CAN1_MBOR,57 // message buffer ORed interrupt
.equ INT_SOURCE_GPT3,59 // GPT3 timer interrupt
.equ INT_SOURCE_GPT2,60 // GPT2 timer interrupt
.equ INT_SOURCE_GPT1,61 // GPT1 timer interrupt
.equ INT_SOURCE_GPT0,62 // GPT0 timer interrupt
// Atari register equates (provided by FPGA)
.equ vbasehi, 0xffff8201
/*
* macros
*/
.altmacro
.macro irq vector,int_mask,clr_int
move.w #0x2700,sr // disable interrupt
subq.l #8,sp
movem.l d0/a5,(sp) // save registers
lea MCF_EPORT_EPFR,a5
move.b #\clr_int,(a5) // clear int pending
movem.l (sp),d0/a5 // restore registers
addq.l #8,sp
move.l \vector,-(sp)
move #0x2\int_mask\()00,sr
rts
.endm
.text
_vec_init:
move.l a2,-(sp) // Backup registers
mov3q.l #-1,_rt_mod // rt_mod auf super
clr.l _rt_ssp
clr.l _rt_usp
clr.l _rt_vbr
move.l #__RAMBAR0,d0 // exception vectors reside in rambar0
movec d0,VBR
move.l d0,a0
move.l a0,a2
/*
* first, set standard vector for all exceptions
*/
init_vec:
move.l #256,d0
lea std_exc_vec(pc),a1 // standard vector
init_vec_loop:
move.l a1,(a2)+ // set standard vector for all exceptions
subq.l #1,d0
bne init_vec_loop
move.l #__SUP_SP,(a0) // set initial stack pointer at start of exception vector table
lea reset_vector(pc),a1 // set reset vector
move.l a1,0x04(a0)
lea access(pc),a1 // set illegal access exception handler
move.l a1,0x08(a0)
// trap #0 (without any parameters for now) is used to provide BaS' driver addresses to the OS
lea _get_bas_drivers(pc),a1
move.l a1,0x80(a0) // trap #0 exception vector
#ifdef MACHINE_FIREBEE
// timer vectors (triggers when vbashi gets changed, used for video page copy)
lea handler_gpt0(pc),a1
// GPT0 interrupt source = 62
move.l a1,(INT_SOURCE_GPT0 + 64) * 4(a0)
#endif /* MACHINE_FIREBEE */
// install lowlevel_isr_handler for the three GPT timers
lea _lowlevel_isr_handler(pc),a1
move.l a1,(INT_SOURCE_GPT1 + 64) * 4(a0)
move.l a1,(INT_SOURCE_GPT2 + 64) * 4(a0)
move.l a1,(INT_SOURCE_GPT3 + 64) * 4(a0)
// install lowlevel_isr_handler for the FEC0 interrupt
move.l a1,(INT_SOURCE_FEC0 + 64) * 4(a0)
// install lowlevel_isr_handler for the PSC3 interrupt
move.l a1,(INT_SOURCE_PSC3 + 64) * 4(a0)
// install lowlevel_isr_handler for the XLBPCI interrupt
move.l a1,(INT_SOURCE_XLBPCI + 64) * 4(a0)
#ifndef MACHINE_FIREBEE
// FEC1 not wired on the FireBee (used for FPGA as GPIO), but used on other machines
move.l a1,(INT_SOURCE_FEC1 + 64) * 4(a0)
#endif
// install lowlevel_isr_handler for Coldfire DMA interrupts
move.l a1,(INT_SOURCE_DMA + 64) * 4(a0)
move.l (sp)+,a2 // Restore registers
rts
/*
* exception vector routines
*/
vector_table_start:
std_exc_vec:
_std_exc_vec:
//move.w #0x2700,sr // disable interrupt
subq.l #8,sp
movem.l d0/a5,(sp) // save registers
move.w 8(sp),d0 // fetch vector
and.l #0x3fc,d0 // mask out vector number
#ifdef DBG_EXC
// printout vector number of exception
lea -4 * 4(sp),sp // reserve stack space
movem.l d0-d1/a0-a1,(sp) // save gcc scratch registers
lsr.l #2,d0 // shift vector number in place
cmp.l #33,d0
beq noprint
cmp.l #34,d0
beq n oprint
cmp.l #45,d0
beq noprint
cmp.l #46,d0
beq noprint
move.l 4 * 4 + 8 + 4(sp),-(sp) // pc at exception
move.l d0,-(sp) // provide it to xprintf()
pea exception_text
jsr _xprintf // call xprintf()
add.l #3*4,sp // adjust stack
noprint:
movem.l (sp),d0-d1/a0-a1 // restore registers
lea 4 * 4(sp),sp
#endif /* DBG_EXC */
add.l _rt_vbr,d0 // + VBR
move.l d0,a5
move.l (a5),d0 // fetch exception routine address
move.l 4(sp),a5 // restore a5
move.l d0,4(sp) // store exception routine address
// FIXME: not clear why we would need the following?
//move.w 10(sp),d0 // restore original SR
//bset #13,d0 // set supervisor bit
//move.w d0,sr //
move.l (sp)+,d0 // restore d0
rts // jump to exception handler
exception_text:
.ascii "DEBUG: EXCEPTION %d caught at %p"
.byte 13, 10, 0
.align 4
reset_vector:
move.w #0x2700,sr // disable interrupt
move.l #0x31415926,d0
cmp.l 0x426,d0 // _resvalid: reset vector valid?
beq std_exc_vec // yes->
jmp _rom_entry // no, cold start machine
access:
move.w #0x2700,sr // disable interrupts
link a6,#-4 * 4 // make room for gcc scratch registers
movem.l d0-d1/a0-a1,(sp) // save them
move.l 4(a6),-(sp) // push format_status
move.l 8(a6),-(sp) // pc at exception
move.l MCF_MMU_MMUAR,-(sp) // MMU fault address
move.l MCF_MMU_MMUSR,-(sp) // MMU status regisrter
move.w #0x2300,sr // can lower interrupt mask now that MMU status is safe
jsr _mmutr_miss // call C routine
lea 4 * 4(sp),sp // adjust stack
tst.l d0 // exception handler signals bus error
bne bus_error
movem.l (sp),d0-d1/a0-a1 // restore registers
unlk a6
rte
bus_error:
movem.l (sp),d0-d1/a0-a1 // restore registers
unlk a6
bra std_exc_vec
zero_divide:
move.w #0x2700,sr // disable interrupt
move.l a0,-(sp)
move.l d0,-(sp)
move.l 12(sp),a0 // pc
move.w (a0)+,d0 // command word
btst #7,d0 // long?
beq zd_word // nein->
addq.l #2,a0
zd_word:
and.l 0x3f,d0 // mask out ea field
cmp.w #0x08,d0 // -(ax) or less?
ble zd_end
addq.l #2,a0
cmp.w #0x39,d0 // xxx.L
bne zd_nal
addq.l #2,a0
bra zd_end
zd_nal: cmp.w #0x3c,d0 // immediate?
bne zd_end // no->
btst #7,d0 // long?
beq zd_end // no
addq.l #2,a0
zd_end:
move.l a0,12(sp)
move.l (sp)+,d0
move.l (sp)+,a0
rte
#ifdef _NOT_USED_
linea:
move.w #0x2700,sr // disable interrupt
halt
nop
nop
linef:
move.w #0x2700,sr // disable interrupt
halt
nop
nop
format:
move.w #0x2700,sr // disable interrupt
halt
nop
nop
//floating point
flpoow:
move.w #0x2700,sr // disable interrupt
halt
nop
nop
#endif /* _NOT_USED */
#if MACHINE_M5484LITE // handlers for M5484LITE
irq5: // irq5 is tied to PCI INTC# and PCI INTD# on the M5484LITE
move.w #0x2700,sr // disable interrupts
lea -4*4(sp),sp // save gcc scratch registers
movem.l d0-d1/a0-a1,(sp)
jsr _irq5_handler // call C handler routine
movem.l (sp),d0-d1/a0-a1 // restore registers
lea 4*4(sp),sp
rte // return from exception
irq5text:
.ascii "IRQ5!"
.dc.b 13,10,0
irq6:
irq 0x74,5,0x20
irq7: // irq7 is tied to PCI INTA# and PCI INTB# on the M5484LITE
move.w #0x2700,sr // disable interrupts
lea -4*4(sp),sp // save gcc scratch registers
movem.l d0-d1/a0-a1,(sp)
jsr _irq7_handler // call C handler routine
movem.l (sp),d0-d1/a0-a1 // restore registers
lea 4*4(sp),sp
rte // return from exception
irq7text:
.data
.ascii "IRQ7!"
.dc.b 13,10,0
.text
#elif MACHINE_FIREBEE /* these handlers are only meaningful for the Firebee */
irq5: move.w #0x2700,sr // disable interrupts
subq.l #4,sp // extra space
link a6,#-4 * 4 // save gcc scratch registers
movem.l d0-d1/a0-a1,(sp)
jsr _irq5_handler // call C handler routine
tst.l d0 // handled?
bne irq5_forward
movem.l (sp),d0-d1/a0-a1 // restore registers
unlk a6
addq.l #4,sp
rte // return from exception
irq5_forward: move.l 0x74,a0 // fetch OS irq5 vector
add.l _rt_vbr,a0 // add runtime vbr
move.l a0,4(a6) // put on stack
movem.l (sp),d0-d1/a0-a1 // restore registers
unlk a6 //
move.w #0x2500,sr // set interrupt level
rts // jump through vector
irq6: move.w #0x2700,sr // disable interrupt
subq.l #4,sp // extra space
link a6,#-4 * 4 // save gcc scratch registers
movem.l d0-d1/a0-a1,(sp)
move.l 4(a6),-(sp) // format status word
move.l 8(a6),-(sp) // pc at exception
jsr _irq6_handler // call C handler
lea 8(sp),sp // fix stack
tst.l d0 // interrupt handled?
bne irq6_forward // no, forward to TOS
movem.l (sp),d0-d1/a0-a1 // restore registers
unlk a6
addq.l #4,sp // "extra space" not needed in this case
rte
irq6_forward:
move.l 0xf0020000,a0 // fetch "MFP interrupt vector from FPGA"
add.l _rt_vbr,a0 // add runtime VBR
move.l (a0),8(a6) // fetch handler address and put it on "extra space"
movem.l (sp),d0-d1/a0-a1
unlk a6
move.w #0x2600,sr // set interrupt level
rts // jump through vector
/*
* irq 7 = pseudo bus error
*/
irq7:
lea -12(sp),sp
movem.l d0/a0,(sp)
move.l __RAMBAR0+0x008,a0 // real access error handler
move.l a0,8(sp) // this will be the return address for rts
move.w 12(sp),d0 // format/vector word
andi.l #0xf000,d0 // keep only the format
ori.l #2*4,d0 // simulate vector #2, no fault
move.w d0,12(sp)
// TODO: Inside an interrupt handler, 16(sp) is the return address.
// For an Access Error, it should be the address of the fault instruction instead
lea MCF_EPORT_EPFR,a0
bset #7,(a0) // clear int 7
move.l (sp)+,d0 // restore registers
move.l (sp)+,a0
rts // Forward to the Access Error handler
/*
* general purpose timer 0 (GPT0): video change, later also others.
*
* GPT0 is used as input trigger. It is connected to the TIN0 signal of
* the FPGA and triggers everytime vbasehi is written to, i.e.
* when the video base address gets changed
*/
/*
* TODO: remove. This interrupt still fires, but doesn't do anything anymore.
* BaS_gcc handles FPGA RAM as STRAM, so there is no page copy necessary as
* it was with previous versions.
*/
handler_gpt0:
.extern _gpt0_interrupt_handler
move.w #0x2700,sr // disable interrupts
link a6,#-4 * 4 // make room for
movem.l d0-d1/a0-a1,(sp) // gcc scratch registers and save them,
// other registers will be handled by gcc itself
move.w 4(a6),d0 // fetch vector number from stack
move.l d0,-(sp) // push it
jsr _gpt0_interrupt_handler // call C handler
addq.l #4,sp // adjust stack
movem.l (sp),d0-d1/a0-a1 // restore registers
unlk a6
rte
#endif /* MACHINE_FIREBEE */
/*
* low-level interrupt service routine for routines registered with
* isr_register_handler()
*/
.global _lowlevel_isr_handler
.extern _isr_execute_handler
_lowlevel_isr_handler:
move.w #0x2700,sr // do not disturb
link a6,#-4 * 4 // make room for
movem.l d0-d1/a0-a1,(sp) // gcc scratch registers and save them,
// other registers will be handled by gcc itself
move.w 4(a6),d0 // fetch vector number from stack
lsr.l #2,d0 // move it in place
andi.l #0xff,d0 // mask it out
move.l d0,-(sp) // push it
jsr _isr_execute_handler // call the C handler
addq.l #4,sp // adjust stack
movem.l (sp),d0-d1/a0-a1 // restore registers
unlk a6
rte