679 lines
20 KiB
C
679 lines
20 KiB
C
/*
|
|
* Interrupts
|
|
*
|
|
* Handle interrupts, the levels.
|
|
*
|
|
*
|
|
* 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 <bas_types.h>
|
|
#include "MCF5475.h"
|
|
#include "bas_utils.h"
|
|
#include "bas_printf.h"
|
|
#include "bas_string.h"
|
|
#include "exceptions.h"
|
|
#include "interrupts.h"
|
|
#include "bas_printf.h"
|
|
#include "startcf.h"
|
|
#include "cache.h"
|
|
#include "util.h"
|
|
#include "dma.h"
|
|
#include "pci.h"
|
|
|
|
// #define DEBUG
|
|
#include "debug.h"
|
|
|
|
#ifndef MAX_ISR_ENTRY
|
|
#define MAX_ISR_ENTRY (20)
|
|
#endif
|
|
|
|
|
|
struct isrentry
|
|
{
|
|
int vector;
|
|
bool (*handler)(void *, void *);
|
|
void *hdev;
|
|
void *harg;
|
|
};
|
|
|
|
static struct isrentry isrtab[MAX_ISR_ENTRY]; /* list of interrupt service routines */
|
|
|
|
|
|
/*
|
|
* clear the table of interrupt service handlers
|
|
*/
|
|
void isr_init(void)
|
|
{
|
|
memset(isrtab, 0, sizeof(isrtab));
|
|
}
|
|
|
|
bool isr_set_prio_and_level(int int_source, int priority, int level)
|
|
{
|
|
if (int_source > 8 && int_source <= 62)
|
|
{
|
|
/*
|
|
* preset interrupt control registers with level and priority
|
|
*/
|
|
dbg("set MCF_INTC_ICR(%d) to priority %d, level %d\r\n",
|
|
int_source, priority, level);
|
|
MCF_INTC_ICR(int_source) = MCF_INTC_ICR_IP(priority) |
|
|
MCF_INTC_ICR_IL(level);
|
|
}
|
|
else if (int_source >= 1 && int_source <= 8)
|
|
{
|
|
dbg("interrrupt control register for vector %d is read only!\r\n");
|
|
}
|
|
else
|
|
{
|
|
err("invalid vector - interrupt control register not set.\r\n");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* enable internal int source in interrupt controller
|
|
*/
|
|
bool isr_enable_int_source(int int_source)
|
|
{
|
|
dbg("anding int_source %d, MCF_INTC_IMR%c = 0x%08x, now 0x%08x\r\n",
|
|
int_source,
|
|
int_source < 32 && int_source > 0 ? 'L' :
|
|
int_source >= 32 && int_source <= 62 ? 'H' : 'U',
|
|
int_source < 32 && int_source > 0 ? ~(1 << int_source) :
|
|
int_source >= 32 && int_source <= 62 ? ~(1 << (int_source - 32)) : 0,
|
|
MCF_INTC_IMRH);
|
|
|
|
if (int_source < 32 && int_source > 0)
|
|
{
|
|
MCF_INTC_IMRL &= ~(1 << int_source);
|
|
}
|
|
else if (int_source >= 32 && int_source <= 62)
|
|
{
|
|
MCF_INTC_IMRH &= ~(1 << (int_source - 32));
|
|
}
|
|
else
|
|
{
|
|
dbg("vector %d does not correspond to an internal interrupt source\r\n");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* This function places an interrupt handler in the ISR table,
|
|
* thereby registering it so that the low-level handler may call it.
|
|
*
|
|
* The two parameters are intended for the first arg to be a
|
|
* pointer to the device itself, and the second a pointer to a data
|
|
* structure used by the device driver for that particular device.
|
|
*/
|
|
bool isr_register_handler(int vector, int level, int priority, bool (*handler)(void *, void *), void *hdev, void *harg)
|
|
{
|
|
int index;
|
|
int int_source;
|
|
|
|
if ((vector <= 0) || (handler == NULL))
|
|
{
|
|
dbg("illegal vector or handler (vector=%x, handler=%p)!\r\n", vector, handler);
|
|
|
|
return false;
|
|
}
|
|
|
|
for (index = 0; index < MAX_ISR_ENTRY; index++)
|
|
{
|
|
if (isrtab[index].vector == vector)
|
|
{
|
|
/* one cross each, only! */
|
|
dbg("already set handler with this vector (%d, %d)\r\n", vector);
|
|
|
|
return false;
|
|
}
|
|
|
|
if (isrtab[index].vector == 0)
|
|
{
|
|
isrtab[index].vector = vector;
|
|
isrtab[index].handler = handler;
|
|
isrtab[index].hdev = hdev;
|
|
isrtab[index].harg = harg;
|
|
|
|
int_source = vector - 64;
|
|
|
|
if (int_source >= 0)
|
|
{
|
|
if (!isr_enable_int_source(int_source))
|
|
{
|
|
dbg("failed to enable internal interrupt souce %d in IMRL/IMRH\r\n", int_source);
|
|
return false;
|
|
}
|
|
|
|
if (!isr_set_prio_and_level(int_source, priority, level))
|
|
{
|
|
dbg("failed to set priority and level for interrupt source %d\r\n", int_source);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
dbg("no available slots to register handler for vector %d\n\r", vector);
|
|
|
|
return false; /* no available slots */
|
|
}
|
|
|
|
void isr_remove_handler(bool (*handler)(void *, void *))
|
|
{
|
|
/*
|
|
* This routine removes from the ISR table all
|
|
* entries that matches 'handler'.
|
|
*/
|
|
int index;
|
|
|
|
for (index = 0; index < MAX_ISR_ENTRY; index++)
|
|
{
|
|
if (isrtab[index].handler == handler)
|
|
{
|
|
memset(&isrtab[index], 0, sizeof(struct isrentry));
|
|
|
|
return;
|
|
}
|
|
}
|
|
dbg("no such handler registered (handler=%p\r\n", handler);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
static char *vector_to_str[] =
|
|
{
|
|
"initial stack pointer", /* 0 */
|
|
"initial program counter", /* 1 */
|
|
"access error", /* 2 */
|
|
"address error", /* 3 */
|
|
"illegal instruction", /* 4 */
|
|
"divide by zero", /* 5 */
|
|
"reserved6", /* 6 */
|
|
"reserved7", /* 7 */
|
|
"privilege violation", /* 8 */
|
|
"trace", /* 9 */
|
|
"unimplemented line-a opcode", /* 10 */
|
|
"unimplemented line-f opcode", /* 11 */
|
|
"non-PC breakpoint debug interrupt", /* 12 */
|
|
"PC breakpoint debug interrupt", /* 13 */
|
|
"format error", /* 14 */
|
|
"uninitialized interrupt", /* 15 */
|
|
"reserved16",
|
|
"reserved17",
|
|
"reserved18",
|
|
"reserved19",
|
|
"reserved20",
|
|
"reserved21",
|
|
"reserved22",
|
|
"reserved23",
|
|
"spurious interrupt", /* 24 */
|
|
"level 1 autovector", /* 25 */
|
|
"level 2 autovector", /* 26 */
|
|
"level 3 autovector", /* 27 */
|
|
"level 4 autovector", /* 28 */
|
|
"level 5 autovector", /* 29 */
|
|
"level 6 autovector", /* 30 */
|
|
"level 7 autovector", /* 31 */
|
|
"trap #0", /* 32 */
|
|
"trap #1", /* 33 */
|
|
"trap #2", /* 34 */
|
|
"trap #3", /* 35 */
|
|
"trap #4", /* 36 */
|
|
"trap #5", /* 37 */
|
|
"trap #6", /* 38 */
|
|
"trap #7", /* 39 */
|
|
"trap #8", /* 40 */
|
|
"trap #9", /* 41 */
|
|
"trap #10" /* 42 */
|
|
"trap #11", /* 43 */
|
|
"trap #12", /* 44 */
|
|
"trap #13", /* 45 */
|
|
"trap #14", /* 46 */
|
|
"trap #15", /* 47 */
|
|
"floating point branch on unordered condition", /* 48 */
|
|
"floting point inexact result", /* 49 */
|
|
"floating point divide by zero", /* 50 */
|
|
"floating point underflow", /* 51 */
|
|
"floating point operand error", /* 52 */
|
|
"floating point overflow", /* 53 */
|
|
"floating point NaN", /* 54 */
|
|
"floating point denormalized number", /* 55 */
|
|
"reserved56", /* 56 */
|
|
"reserved57",
|
|
"reserved58",
|
|
"reserved59",
|
|
"reserved60",
|
|
"unsupported instruction", /* 61 */
|
|
"reserved62", /* 62 */
|
|
"reserved63", /* 63 */
|
|
"", "",
|
|
"edge port 1", /* 1 */
|
|
"edge port 2", /* 2 */
|
|
"edge port 3", /* 3 */
|
|
"edge port 4", /* 4 */
|
|
"edge port 5", /* 5 */
|
|
"edge port 6", /* 6 */
|
|
"edge port 7", /* 7 */
|
|
"unused8",
|
|
"unused9",
|
|
"unused10",
|
|
"unused11",
|
|
"unused12",
|
|
"unused13",
|
|
"unused14",
|
|
"USB endpoint 0", /* 15 */
|
|
"USB endpoint 1", /* 16 */
|
|
"USB endpoint 2", /* 17 */
|
|
"USB endpoint 3", /* 18 */
|
|
"USB endpoint 4", /* 19 */
|
|
"USB endpoint 5", /* 20 */
|
|
"USB endpoint 6", /* 21 */
|
|
"USB general interrupt", /* 22 */
|
|
"USB core interrupt", /* 23 */
|
|
"USB OR interrupt", /* 24 */
|
|
"DSPI over/underflow", /* 25 */
|
|
"DSPI receive FIFO overflow", /* 26 */
|
|
"DSPI receive FIFO drain", /* 27 */
|
|
"DSPI transmit FIFO underflow", /* 28 */
|
|
"DSPI transfer complete", /* 29 */
|
|
"DSPI trasmit FIFO full", /* 30 */
|
|
"DSPI end of queue", /* 31 */
|
|
"PSC3", /* 32 */
|
|
"PSC2", /* 33 */
|
|
"PSC1", /* 34 */
|
|
"PSC0", /* 35 */
|
|
"Comm timer", /* 36 */
|
|
"SEC", /* 37 */
|
|
"FEC1", /* 38 */
|
|
"FEC0", /* 39 */
|
|
"I2C", /* 40 */
|
|
"PCI arbiter", /* 41 */
|
|
"comm bus PCI", /* 42 */
|
|
"XLB PCI", /* 43 */
|
|
"not used44",
|
|
"not used45",
|
|
"not used46",
|
|
"XLB arbiter to CPU", /* 47 */
|
|
"multichannel DMA", /* 48 */
|
|
"FlexCAN 0 error", /* 49 */
|
|
"FlexCAN 0 bus off", /* 50 */
|
|
"FlexCAN 0 message buffer", /* 51 */
|
|
"not used52"
|
|
"slice timer 1", /* 53 */
|
|
"slice timer 0", /* 54 */
|
|
"FlexCAN 1 error", /* 55 */
|
|
"FlexCAN 1 bus off", /* 56 */
|
|
"FlexCAN 1 message buffer", /* 57 */
|
|
"not used58",
|
|
"GPT3", /* 59 */
|
|
"GPT2", /* 60 */
|
|
"GPT1", /* 61 */
|
|
"GPT0", /* 62 */
|
|
"not used63"
|
|
};
|
|
#endif /* DEBUG */
|
|
|
|
/*
|
|
* This routine searches the ISR table for an entry that matches
|
|
* 'vector'. If one is found, then 'handler' is executed.
|
|
*
|
|
* This routine returns either true or false where
|
|
* true = interrupt has been handled, return to caller
|
|
* false= interrupt has been handled or hasn't, but needs to be forwarded to TOS
|
|
*/
|
|
bool isr_execute_handler(int vector)
|
|
{
|
|
int index;
|
|
|
|
dbg("vector = %d (%s)\r\n", vector, vector_to_str[vector]);
|
|
|
|
/*
|
|
* locate an interrupt service routine handler.
|
|
*/
|
|
for (index = 0; index < MAX_ISR_ENTRY; index++)
|
|
{
|
|
if (isrtab[index].vector == vector)
|
|
{
|
|
isrtab[index].handler(isrtab[index].hdev, isrtab[index].harg);
|
|
return true;
|
|
}
|
|
}
|
|
err("no isr handler for vector %d found. Spurious?\r\n", vector);
|
|
|
|
return true;
|
|
}
|
|
|
|
#if defined(MACHINE_FIREBEE)
|
|
/*
|
|
* PIC interrupt handler for Firebee
|
|
*
|
|
* Handles PIC requests that come in from PSC3 serial interface. Currently, that
|
|
* is RTC/NVRAM requests only
|
|
*/
|
|
bool pic_interrupt_handler(void *arg1, void *arg2)
|
|
{
|
|
uint8_t rcv_byte;
|
|
|
|
dbg("PIC interrupt\r\n");
|
|
|
|
rcv_byte = read_pic_byte();
|
|
if (rcv_byte == 2) /* PIC requests RTC data */
|
|
{
|
|
volatile uint8_t *rtc_reg = (uint8_t *) 0xffff8961;
|
|
volatile uint8_t *rtc_data = (uint8_t *) 0xffff8963;
|
|
int index = 0;
|
|
|
|
err("PIC interrupt: requesting RTC data\r\n");
|
|
|
|
write_pic_byte(0x82); // header byte to PIC
|
|
do
|
|
{
|
|
*rtc_reg = index;
|
|
write_pic_byte(*rtc_data);
|
|
} while (++index < 64);
|
|
}
|
|
return true;
|
|
}
|
|
#endif /* MACHINE_FIREBEE */
|
|
|
|
bool xlbpci_interrupt_handler(void *arg1, void *arg2)
|
|
{
|
|
uint32_t reason;
|
|
|
|
dbg("XLB PCI interrupt\r\n");
|
|
|
|
reason = MCF_PCI_PCIISR;
|
|
|
|
if (reason & MCF_PCI_PCIISR_RE)
|
|
{
|
|
dbg("Retry error. Retry terminated or max retries reached. Cleared\r\n");
|
|
MCF_PCI_PCIISR |= MCF_PCI_PCIISR_RE;
|
|
}
|
|
|
|
if (reason & MCF_PCI_PCIISR_IA)
|
|
{
|
|
dbg("Initiator abort. No target answered in time. Cleared.\r\n");
|
|
MCF_PCI_PCIISR |= MCF_PCI_PCIISR_IA;
|
|
}
|
|
|
|
if (reason & MCF_PCI_PCIISR_TA)
|
|
{
|
|
dbg("Target abort. Cleared.\r\n");
|
|
MCF_PCI_PCIISR |= MCF_PCI_PCIISR_TA;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool pciarb_interrupt_handler(void *arg1, void *arg2)
|
|
{
|
|
dbg("PCI ARB interrupt\r\n");
|
|
|
|
MCF_PCIARB_PASR |= MCF_PCIARB_PASR_EXTMBK(0x1f) | MCF_PCIARB_PASR_ITLMBK;
|
|
return true;
|
|
}
|
|
|
|
bool xlbarb_interrupt_handler(void *arg1, void *arg2)
|
|
{
|
|
uint32_t status = MCF_XLB_XARB_SR;
|
|
|
|
/*
|
|
* TODO: we should probably issue a bus error when this occors
|
|
*/
|
|
dbg("XLB arbiter interrupt. XARB_ADRCAP=0x%08lx\r\n", MCF_XLB_XARB_ADRCAP);
|
|
|
|
if (status & MCF_XLB_XARB_SR_AT)
|
|
dbg("address tenure timeout\r\n");
|
|
if (status & MCF_XLB_XARB_SR_DT)
|
|
dbg("data tenure timeout\r\n");
|
|
if (status & MCF_XLB_XARB_SR_BA)
|
|
dbg("bus activity tenure timeout\r\n");
|
|
if (status & MCF_XLB_XARB_SR_TTM)
|
|
dbg("TBST/TSIZ mismatch\r\n");
|
|
if (status & MCF_XLB_XARB_SR_ECW)
|
|
dbg("external control word read/write\r\n");
|
|
if (status & MCF_XLB_XARB_SR_TTR)
|
|
dbg("TT reserved\r\n");
|
|
if (status & MCF_XLB_XARB_SR_TTA)
|
|
dbg("TT address only\r\n");
|
|
if (status & MCF_XLB_XARB_SR_MM)
|
|
dbg("multiple masters at priority 0\r\n");
|
|
if (status & MCF_XLB_XARB_SR_SEA)
|
|
dbg("slave error acknowledge\r\n");
|
|
|
|
/*
|
|
* acknowledge interrupt
|
|
*/
|
|
MCF_XLB_XARB_SR = status; /* rwc bits */
|
|
|
|
return true;
|
|
}
|
|
|
|
#if defined(MACHINE_FIREBEE)
|
|
/*
|
|
* This gets called from irq5 in exceptions.S
|
|
*
|
|
* IRQ5 are the "FBEE" (PIC, ETH PHY, PCI, DVI monitor sense and DSP) interrupts multiplexed by the FPGA interrupt handler
|
|
*/
|
|
bool irq5_handler(void *arg1, void *arg2)
|
|
{
|
|
uint32_t pending_interrupts = FBEE_INTR_PENDING;
|
|
|
|
dbg("IRQ5!\r\n");
|
|
if (pending_interrupts & FBEE_INTR_PIC)
|
|
{
|
|
dbg("PIC interrupt\r\n");
|
|
FBEE_INTR_CLEAR = FBEE_INTR_PIC;
|
|
}
|
|
|
|
if (pending_interrupts & FBEE_INTR_ETHERNET)
|
|
{
|
|
dbg("ethernet 0 PHY interrupt\r\n");
|
|
FBEE_INTR_CLEAR = FBEE_INTR_ETHERNET;
|
|
}
|
|
|
|
if (pending_interrupts & FBEE_INTR_DVI)
|
|
{
|
|
dbg("DVI monitor sense interrupt\r\n");
|
|
FBEE_INTR_CLEAR = FBEE_INTR_DVI;
|
|
}
|
|
|
|
if (pending_interrupts & FBEE_INTR_PCI_INTA ||
|
|
pending_interrupts & FBEE_INTR_PCI_INTB ||
|
|
pending_interrupts & FBEE_INTR_PCI_INTC ||
|
|
pending_interrupts & FBEE_INTR_PCI_INTD)
|
|
{
|
|
int handle;
|
|
|
|
if ((handle = pci_get_interrupt_cause() != -1))
|
|
{
|
|
pci_call_interrupt_chain(handle, 0L);
|
|
}
|
|
dbg("PCI interrupt IRQ5\r\n");
|
|
FBEE_INTR_CLEAR = FBEE_INTR_PCI_INTA |
|
|
FBEE_INTR_PCI_INTB |
|
|
FBEE_INTR_PCI_INTC |
|
|
FBEE_INTR_PCI_INTD;
|
|
}
|
|
|
|
if (pending_interrupts & FBEE_INTR_DSP)
|
|
{
|
|
dbg("DSP interrupt\r\n");
|
|
FBEE_INTR_CLEAR = FBEE_INTR_DSP;
|
|
}
|
|
|
|
MCF_EPORT_EPFR |= (1 << 5); /* clear interrupt from edge port */
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* blink the Firebee's LED to show we are still alive
|
|
*/
|
|
void blink_led(void)
|
|
{
|
|
static uint16_t blinker = 0;
|
|
|
|
if ((blinker++ & 0x80) > 0)
|
|
{
|
|
MCF_GPIO_PODR_FEC1L |= (1 << 4); /* LED off */
|
|
}
|
|
else
|
|
{
|
|
MCF_GPIO_PODR_FEC1L &= ~(1 << 4); /* LED on */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Atari MFP interrupt registers.
|
|
*
|
|
* TODO: should go into a header file
|
|
*/
|
|
|
|
#define FALCON_MFP_IERA *((volatile uint8_t *) 0xfffffa07)
|
|
#define FALCON_MFP_IERB *((volatile uint8_t *) 0xfffffa09)
|
|
#define FALCON_MFP_IPRA *((volatile uint8_t *) 0xfffffa0b)
|
|
#define FALCON_MFP_IPRB *((volatile uint8_t *) 0xfffffa0d)
|
|
#define FALCON_MFP_IMRA *((volatile uint8_t *) 0xfffffa13)
|
|
#define FALCON_MFP_IMRB *((volatile uint8_t *) 0xfffffa15)
|
|
|
|
bool irq6_acsi_dma_interrupt(void)
|
|
{
|
|
dbg("ACSI DMA interrupt\r\n");
|
|
|
|
/*
|
|
* TODO: implement handler
|
|
*/
|
|
|
|
return false;
|
|
}
|
|
|
|
bool irq6_handler(uint32_t sf1, uint32_t sf2)
|
|
{
|
|
//err("IRQ6!\r\n");
|
|
|
|
if (FALCON_MFP_IPRA || FALCON_MFP_IPRB)
|
|
{
|
|
blink_led();
|
|
}
|
|
|
|
MCF_EPORT_EPFR |= (1 << 6); /* clear int6 from edge port */
|
|
|
|
return false; /* always forward IRQ6 to TOS */
|
|
}
|
|
|
|
#else /* MACHINE_FIREBEE */
|
|
|
|
bool irq5_handler(void *arg1, void *arg2)
|
|
{
|
|
MCF_EPORT_EPFR |= (1 << 5); /* clear int5 from edge port */
|
|
|
|
return true;
|
|
}
|
|
|
|
bool irq6_handler(void *arg1, void *arg2)
|
|
{
|
|
err("IRQ6!\r\n");
|
|
|
|
MCF_EPORT_EPFR |= (1 << 6); /* clear int6 from edge port */
|
|
|
|
return false; /* always forward IRQ6 to TOS */
|
|
}
|
|
|
|
/*
|
|
* This gets called from irq7 in exceptions.S
|
|
* Once we arrive here, the SR has been set to disable interrupts and the gcc scratch registers have been saved
|
|
*/
|
|
bool irq7_handler(void)
|
|
{
|
|
int32_t handle;
|
|
int32_t value = 0;
|
|
int32_t newvalue;
|
|
|
|
MCF_EPORT_EPFR |= (1 << 7);
|
|
dbg("IRQ7!\r\n");
|
|
if ((handle = pci_get_interrupt_cause()) > 0)
|
|
{
|
|
newvalue = pci_call_interrupt_chain(handle, value);
|
|
if (newvalue == value)
|
|
{
|
|
dbg("interrupt not handled!\r\n");
|
|
}
|
|
}
|
|
MCF_EPORT_EPFR |= (1 << 7); /* clear int7 from edge port */
|
|
|
|
return true;
|
|
}
|
|
#endif /* MACHINE_M548X */
|
|
|
|
#if defined(MACHINE_FIREBEE)
|
|
/*
|
|
* this is the higlevel interrupt service routine for gpt0 timer interrupts.
|
|
*
|
|
* It is called from handler_gpt0 in exceptions.S
|
|
*
|
|
* The gpt0 timer is not used as a timer, but as interrupt trigger by the FPGA which fires
|
|
* everytime the video base address high byte (0xffff8201) gets written by user code (i.e.
|
|
* everytime the video base address is set).
|
|
* The interrupt service routine checks if that page was already set as a video page (in that
|
|
* case it does nothing), if not (if we have a newly set page), it sets up an MMU mapping for
|
|
* that page (effectively rerouting any further access to Falcon video RAM to Firebee FPGA
|
|
* video RAM starting at 0x60000000) and copies SDRAM contents of that page to the video
|
|
* RAM page.
|
|
*/
|
|
bool gpt0_interrupt_handler(void *arg0, void *arg1)
|
|
{
|
|
dbg("gpt0 handler called\n\r");
|
|
|
|
MCF_GPT0_GMS &= ~1; /* rearm trigger */
|
|
NOP();
|
|
MCF_GPT0_GMS |= 1;
|
|
|
|
return true;
|
|
}
|
|
#endif /* MACHINE_FIREBEE */
|
|
|
|
|
|
uint32_t set_ipl(uint32_t ipl)
|
|
{
|
|
uint32_t ret;
|
|
|
|
__asm__ __volatile__(
|
|
" move.w sr,%[ret]\r\n" /* retrieve status register */
|
|
" andi.l #0x07,%[ipl]\n\t" /* mask out ipl bits on new value */
|
|
" lsl.l #8,%[ipl]\n\t" /* shift them to position */
|
|
" move.l %[ret],d0\n\t" /* retrieve original value */
|
|
" andi.l #0x0000f8ff,d0\n\t" /* clear ipl part */
|
|
" or.l %[ipl],d0\n\t" /* or in new value */
|
|
" move.w d0,sr\n\t" /* put it in place */
|
|
" andi.l #0x0700,%[ret]\r\n" /* mask out ipl bits */
|
|
" lsr.l #8,%[ret]\r\n" /* shift them to position */
|
|
: [ret] "=&d" (ret) /* output */
|
|
: [ipl] "d" (ipl) /* input */
|
|
: "cc" /* clobber */
|
|
);
|
|
|
|
return ret;
|
|
}
|