Compare commits
11 Commits
R_0_9
...
Bas_gcc_mm
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c70dc9ae0d | ||
|
|
c427fea43a | ||
|
|
69539e93a6 | ||
|
|
aa3ae8ecba | ||
|
|
4d68242185 | ||
|
|
68b4240355 | ||
|
|
83666ba2f5 | ||
|
|
f044fbbe72 | ||
|
|
6a1bcae947 | ||
|
|
a1c4fdff47 | ||
|
|
8d6154e69b |
1
Makefile
1
Makefile
@@ -143,7 +143,6 @@ CSRCS= \
|
||||
|
||||
ASRCS= \
|
||||
startcf.S \
|
||||
printf_helper.S \
|
||||
exceptions.S \
|
||||
xhdi_vec.S \
|
||||
pci_wrappers.S
|
||||
|
||||
@@ -78,7 +78,6 @@ SECTIONS
|
||||
OBJDIR/s19reader.o(.text)
|
||||
OBJDIR/bas_printf.o(.text)
|
||||
OBJDIR/bas_string.o(.text)
|
||||
OBJDIR/printf_helper.o(.text)
|
||||
OBJDIR/cache.o(.text)
|
||||
OBJDIR/dma.o(.text)
|
||||
OBJDIR/MCD_dmaApi.o(.text)
|
||||
|
||||
@@ -55,11 +55,6 @@
|
||||
#define CF_CACR_EUSP (0x00000020) /* Switch stacks in user mode */
|
||||
#define CF_CACR_DF (0x00000010) /* Disable FPU */
|
||||
|
||||
#define _DCACHE_SET_MASK ((DCACHE_SIZE/64-1)<<CACHE_WAYS)
|
||||
#define _ICACHE_SET_MASK ((ICACHE_SIZE/64-1)<<CACHE_WAYS)
|
||||
#define LAST_DCACHE_ADDR _DCACHE_SET_MASK
|
||||
#define LAST_ICACHE_ADDR _ICACHE_SET_MASK
|
||||
|
||||
#define ICACHE_SIZE 0x8000 /* instruction - 32k */
|
||||
#define DCACHE_SIZE 0x8000 /* data - 32k */
|
||||
|
||||
@@ -67,6 +62,10 @@
|
||||
#define CACHE_SETS 0x0200 /* 512 sets */
|
||||
#define CACHE_WAYS 0x0004 /* 4 way */
|
||||
|
||||
#define _DCACHE_SET_MASK ((DCACHE_SIZE / 64 - 1) << CACHE_WAYS)
|
||||
#define _ICACHE_SET_MASK ((ICACHE_SIZE / 64 - 1) << CACHE_WAYS)
|
||||
#define LAST_DCACHE_ADDR _DCACHE_SET_MASK
|
||||
#define LAST_ICACHE_ADDR _ICACHE_SET_MASK
|
||||
|
||||
#define CACHE_DISABLE_MODE (CF_CACR_DCINVA+ \
|
||||
CF_CACR_BCINVA+ \
|
||||
|
||||
@@ -50,27 +50,30 @@
|
||||
* MMU register handling macros
|
||||
*/
|
||||
|
||||
#define SCA_PAGE_ID 6 /* indicates video memory page */
|
||||
|
||||
#define SCA_PAGE_ID 6 /* indicates video memory page */
|
||||
#define DEFAULT_PAGE_SIZE 0x2000 /* use 8k pages for MiNT compatibility */
|
||||
/*
|
||||
* MMU page sizes
|
||||
*/
|
||||
|
||||
enum mmu_page_size
|
||||
{
|
||||
MMU_PAGE_SIZE_1M = 0,
|
||||
MMU_PAGE_SIZE_4K = 1,
|
||||
MMU_PAGE_SIZE_8K = 2,
|
||||
MMU_PAGE_SIZE_1K = 3
|
||||
MMU_PAGE_SIZE_1M = 0,
|
||||
MMU_PAGE_SIZE_4K = 1,
|
||||
MMU_PAGE_SIZE_8K = 2,
|
||||
MMU_PAGE_SIZE_1K = 3
|
||||
};
|
||||
|
||||
/*
|
||||
* cache modes
|
||||
*/
|
||||
#define CACHE_WRITETHROUGH 0
|
||||
#define CACHE_COPYBACK 1
|
||||
#define CACHE_NOCACHE_PRECISE 2
|
||||
#define CACHE_NOCACHE_IMPRECISE 3
|
||||
enum mmu_cache_modes
|
||||
{
|
||||
CACHE_WRITETHROUGH = 0,
|
||||
CACHE_COPYBACK = 1,
|
||||
CACHE_NOCACHE_PRECISE = 2,
|
||||
CACHE_NOCACHE_IMPRECISE = 3
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
@@ -83,23 +86,14 @@ enum mmu_page_size
|
||||
#define ACCESS_WRITE (1 << 1)
|
||||
#define ACCESS_EXECUTE (1 << 2)
|
||||
|
||||
struct mmu_map_flags
|
||||
{
|
||||
unsigned cache_mode:2;
|
||||
unsigned protection:1;
|
||||
unsigned page_id:8;
|
||||
unsigned access:3;
|
||||
unsigned locked:1;
|
||||
unsigned unused:17;
|
||||
};
|
||||
|
||||
/*
|
||||
* global variables from linker script
|
||||
*/
|
||||
extern long video_tlb;
|
||||
extern long video_sbt;
|
||||
|
||||
extern void mmu_enable(void);
|
||||
extern void mmu_init(void);
|
||||
extern int mmu_map_page(uint32_t virt, uint32_t phys, enum mmu_page_size sz, const struct mmu_map_flags *flags);
|
||||
extern int mmu_map_8k_page(uint32_t adr, uint8_t asid);
|
||||
|
||||
#endif /* _MMU_H_ */
|
||||
|
||||
422
sys/BaS.c
422
sys/BaS.c
@@ -76,10 +76,10 @@ extern uint8_t _EMUTOS_SIZE[];
|
||||
*/
|
||||
static inline bool pic_txready(void)
|
||||
{
|
||||
if (MCF_PSC3_PSCSR & MCF_PSC_PSCSR_TXRDY)
|
||||
return true;
|
||||
if (MCF_PSC3_PSCSR & MCF_PSC_PSCSR_TXRDY)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -87,84 +87,84 @@ static inline bool pic_txready(void)
|
||||
*/
|
||||
static inline bool pic_rxready(void)
|
||||
{
|
||||
if (MCF_PSC3_PSCSR & MCF_PSC_PSCSR_RXRDY)
|
||||
return true;
|
||||
if (MCF_PSC3_PSCSR & MCF_PSC_PSCSR_RXRDY)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
void write_pic_byte(uint8_t value)
|
||||
{
|
||||
/* Wait until the transmitter is ready or 1000us are passed */
|
||||
waitfor(1000, pic_txready);
|
||||
/* Wait until the transmitter is ready or 1000us are passed */
|
||||
waitfor(1000, pic_txready);
|
||||
|
||||
/* Transmit the byte */
|
||||
*(volatile uint8_t*)(&MCF_PSC3_PSCTB_8BIT) = value; // Really 8-bit
|
||||
/* Transmit the byte */
|
||||
*(volatile uint8_t*)(&MCF_PSC3_PSCTB_8BIT) = value; // Really 8-bit
|
||||
}
|
||||
|
||||
uint8_t read_pic_byte(void)
|
||||
{
|
||||
/* Wait until a byte has been received or 1000us are passed */
|
||||
waitfor(1000, pic_rxready);
|
||||
/* Wait until a byte has been received or 1000us are passed */
|
||||
waitfor(1000, pic_rxready);
|
||||
|
||||
/* Return the received byte */
|
||||
return * (volatile uint8_t *) (&MCF_PSC3_PSCTB_8BIT); // Really 8-bit
|
||||
/* Return the received byte */
|
||||
return * (volatile uint8_t *) (&MCF_PSC3_PSCTB_8BIT); // Really 8-bit
|
||||
}
|
||||
|
||||
void pic_init(void)
|
||||
{
|
||||
char answer[4] = "OLD";
|
||||
char answer[4] = "OLD";
|
||||
|
||||
xprintf("initialize the PIC: ");
|
||||
xprintf("initialize the PIC: ");
|
||||
|
||||
/* Send the PIC initialization string */
|
||||
write_pic_byte('A');
|
||||
write_pic_byte('C');
|
||||
write_pic_byte('P');
|
||||
write_pic_byte('F');
|
||||
/* Send the PIC initialization string */
|
||||
write_pic_byte('A');
|
||||
write_pic_byte('C');
|
||||
write_pic_byte('P');
|
||||
write_pic_byte('F');
|
||||
|
||||
/* Read the 3-char answer string. Should be "OK!". */
|
||||
answer[0] = read_pic_byte();
|
||||
answer[1] = read_pic_byte();
|
||||
answer[2] = read_pic_byte();
|
||||
answer[3] = '\0';
|
||||
/* Read the 3-char answer string. Should be "OK!". */
|
||||
answer[0] = read_pic_byte();
|
||||
answer[1] = read_pic_byte();
|
||||
answer[2] = read_pic_byte();
|
||||
answer[3] = '\0';
|
||||
|
||||
if (answer[0] != 'O' || answer[1] != 'K' || answer[2] != '!')
|
||||
{
|
||||
dbg("PIC initialization failed. Already initialized?\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
xprintf("%s\r\n", answer);
|
||||
}
|
||||
if (answer[0] != 'O' || answer[1] != 'K' || answer[2] != '!')
|
||||
{
|
||||
dbg("PIC initialization failed. Already initialized?\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
xprintf("%s\r\n", answer);
|
||||
}
|
||||
}
|
||||
|
||||
void nvram_init(void)
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
|
||||
xprintf("Restore the NVRAM data: ");
|
||||
xprintf("Restore the NVRAM data: ");
|
||||
|
||||
/* Request for NVRAM backup data */
|
||||
write_pic_byte(0x01);
|
||||
/* Request for NVRAM backup data */
|
||||
write_pic_byte(0x01);
|
||||
|
||||
/* Check answer type */
|
||||
if (read_pic_byte() != 0x81)
|
||||
{
|
||||
// FIXME: PIC protocol error
|
||||
xprintf("FAILED\r\n");
|
||||
return;
|
||||
}
|
||||
/* Check answer type */
|
||||
if (read_pic_byte() != 0x81)
|
||||
{
|
||||
// FIXME: PIC protocol error
|
||||
xprintf("FAILED\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Restore the NVRAM backup to the FPGA */
|
||||
for (i = 0; i < 64; i++)
|
||||
{
|
||||
uint8_t data = read_pic_byte();
|
||||
*(volatile uint8_t*)0xffff8961 = i;
|
||||
*(volatile uint8_t*)0xffff8963 = data;
|
||||
}
|
||||
/* Restore the NVRAM backup to the FPGA */
|
||||
for (i = 0; i < 64; i++)
|
||||
{
|
||||
uint8_t data = read_pic_byte();
|
||||
*(volatile uint8_t*)0xffff8961 = i;
|
||||
*(volatile uint8_t*)0xffff8963 = data;
|
||||
}
|
||||
|
||||
xprintf("finished\r\n");
|
||||
xprintf("finished\r\n");
|
||||
}
|
||||
|
||||
#define KBD_ACIA_CONTROL ((uint8_t *) 0xfffffc00)
|
||||
@@ -174,24 +174,24 @@ void nvram_init(void)
|
||||
|
||||
void acia_init()
|
||||
{
|
||||
xprintf("init ACIA: ");
|
||||
/* init ACIA */
|
||||
* KBD_ACIA_CONTROL = 3; /* master reset */
|
||||
NOP();
|
||||
xprintf("init ACIA: ");
|
||||
/* init ACIA */
|
||||
* KBD_ACIA_CONTROL = 3; /* master reset */
|
||||
NOP();
|
||||
|
||||
* MIDI_ACIA_CONTROL = 3; /* master reset */
|
||||
NOP();
|
||||
* MIDI_ACIA_CONTROL = 3; /* master reset */
|
||||
NOP();
|
||||
|
||||
* KBD_ACIA_CONTROL = 0x96; /* clock div = 64, 8N1, RTS low, TX int disable, RX int enable */
|
||||
NOP();
|
||||
* KBD_ACIA_CONTROL = 0x96; /* clock div = 64, 8N1, RTS low, TX int disable, RX int enable */
|
||||
NOP();
|
||||
|
||||
* MFP_INTR_IN_SERVICE_A = -1;
|
||||
NOP();
|
||||
* MFP_INTR_IN_SERVICE_A = -1;
|
||||
NOP();
|
||||
|
||||
* MFP_INTR_IN_SERVICE_B = -1;
|
||||
NOP();
|
||||
* MFP_INTR_IN_SERVICE_B = -1;
|
||||
NOP();
|
||||
|
||||
xprintf("finished\r\n");
|
||||
xprintf("finished\r\n");
|
||||
}
|
||||
|
||||
/* ACP interrupt controller */
|
||||
@@ -201,43 +201,43 @@ void acia_init()
|
||||
|
||||
void enable_coldfire_interrupts()
|
||||
{
|
||||
xprintf("enable interrupts: ");
|
||||
xprintf("enable interrupts: ");
|
||||
#if defined(MACHINE_FIREBEE)
|
||||
*FPGA_INTR_CONTRL = 0L; /* disable all interrupts */
|
||||
*FPGA_INTR_CONTRL = 0L; /* disable all interrupts */
|
||||
#endif /* MACHINE_FIREBEE */
|
||||
MCF_EPORT_EPPAR = 0xaaa8; /* all interrupts on falling edge */
|
||||
MCF_EPORT_EPPAR = 0xaaa8; /* all interrupts on falling edge */
|
||||
|
||||
#if defined(MACHINE_FIREBEE)
|
||||
/*
|
||||
* TIN0 on the Coldfire is connected to the FPGA. TIN0 triggers every write
|
||||
* access to 0xff8201 (vbasehi), i.e. everytime the video base address is written
|
||||
*/
|
||||
MCF_GPT0_GMS = MCF_GPT_GMS_ICT(1) | /* timer 0 on, video change capture on rising edge */
|
||||
MCF_GPT_GMS_IEN |
|
||||
MCF_GPT_GMS_TMS(1);
|
||||
/* route GPT0 interrupt on interrupt controller */
|
||||
MCF_INTC_ICR62 = 0x3f; /* interrupt level 7, interrupt priority 7 */
|
||||
/*
|
||||
* TIN0 on the Coldfire is connected to the FPGA. TIN0 triggers every write
|
||||
* access to 0xff8201 (vbasehi), i.e. everytime the video base address is written
|
||||
*/
|
||||
MCF_GPT0_GMS = MCF_GPT_GMS_ICT(1) | /* timer 0 on, video change capture on rising edge */
|
||||
MCF_GPT_GMS_IEN |
|
||||
MCF_GPT_GMS_TMS(1);
|
||||
/* route GPT0 interrupt on interrupt controller */
|
||||
MCF_INTC_ICR62 = 0x3f; /* interrupt level 7, interrupt priority 7 */
|
||||
|
||||
*FPGA_INTR_ENABLE = 0xfe; /* enable int 1-7 */
|
||||
MCF_EPORT_EPIER = 0xfe; /* int 1-7 on */
|
||||
MCF_EPORT_EPFR = 0xff; /* clear all pending interrupts */
|
||||
MCF_INTC_IMRL = 0xffffff00; /* int 1-7 on */
|
||||
MCF_INTC_IMRH = 0xbffffffe; /* psc3 and timer 0 int on */
|
||||
*FPGA_INTR_ENABLE = 0xfe; /* enable int 1-7 */
|
||||
MCF_EPORT_EPIER = 0xfe; /* int 1-7 on */
|
||||
MCF_EPORT_EPFR = 0xff; /* clear all pending interrupts */
|
||||
MCF_INTC_IMRL = 0xffffff00; /* int 1-7 on */
|
||||
MCF_INTC_IMRH = 0xbffffffe; /* psc3 and timer 0 int on */
|
||||
#endif
|
||||
|
||||
xprintf("finished\r\n");
|
||||
xprintf("finished\r\n");
|
||||
}
|
||||
|
||||
void disable_coldfire_interrupts()
|
||||
{
|
||||
#if defined(MACHINE_FIREBEE)
|
||||
*FPGA_INTR_ENABLE = 0; /* disable all interrupts */
|
||||
*FPGA_INTR_ENABLE = 0; /* disable all interrupts */
|
||||
#endif /* MACHINE_FIREBEE */
|
||||
|
||||
MCF_EPORT_EPIER = 0x0;
|
||||
MCF_EPORT_EPFR = 0x0;
|
||||
MCF_INTC_IMRL = 0xfffffffe;
|
||||
MCF_INTC_IMRH = 0xffffffff;
|
||||
MCF_EPORT_EPIER = 0x0;
|
||||
MCF_EPORT_EPFR = 0x0;
|
||||
MCF_INTC_IMRL = 0xfffffffe;
|
||||
MCF_INTC_IMRH = 0xffffffff;
|
||||
}
|
||||
|
||||
|
||||
@@ -252,178 +252,180 @@ NIF nif2;
|
||||
*/
|
||||
void init_isr(void)
|
||||
{
|
||||
isr_init(); /* need to call that explicitely, otherwise isr table might be full */
|
||||
isr_init(); /* need to call that explicitely, otherwise isr table might be full */
|
||||
|
||||
/*
|
||||
* register the FEC interrupt handler
|
||||
*/
|
||||
if (!isr_register_handler(64 + INT_SOURCE_FEC0, fec0_interrupt_handler, NULL, (void *) &nif1))
|
||||
{
|
||||
dbg("unable to register isr for FEC0\r\n");
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* register the FEC interrupt handler
|
||||
*/
|
||||
if (!isr_register_handler(64 + INT_SOURCE_FEC0, fec0_interrupt_handler, NULL, (void *) &nif1))
|
||||
{
|
||||
dbg("unable to register isr for FEC0\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register the DMA interrupt handler
|
||||
*/
|
||||
/*
|
||||
* Register the DMA interrupt handler
|
||||
*/
|
||||
|
||||
if (!isr_register_handler(64 + INT_SOURCE_DMA, dma_interrupt_handler, NULL,NULL))
|
||||
{
|
||||
dbg("Error: Unable to register isr for DMA\r\n");
|
||||
return;
|
||||
}
|
||||
if (!isr_register_handler(64 + INT_SOURCE_DMA, dma_interrupt_handler, NULL,NULL))
|
||||
{
|
||||
dbg("Error: Unable to register isr for DMA\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dma_irq_enable(5, 3); /* TODO: need to match the FEC driver's specs in MiNT? */
|
||||
dma_irq_enable(5, 3); /* TODO: need to match the FEC driver's specs in MiNT? */
|
||||
|
||||
/*
|
||||
* register the PIC interrupt handler
|
||||
*/
|
||||
if (isr_register_handler(64 + INT_SOURCE_PSC3, pic_interrupt_handler, NULL, NULL))
|
||||
{
|
||||
dbg("Error: unable to register ISR for PSC3\r\n");
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* register the PIC interrupt handler
|
||||
*/
|
||||
if (isr_register_handler(64 + INT_SOURCE_PSC3, pic_interrupt_handler, NULL, NULL))
|
||||
{
|
||||
dbg("Error: unable to register ISR for PSC3\r\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void BaS(void)
|
||||
{
|
||||
uint8_t *src;
|
||||
uint8_t *dst = (uint8_t *) TOS;
|
||||
uint8_t *src;
|
||||
uint8_t *dst = (uint8_t *) TOS;
|
||||
|
||||
#if defined(MACHINE_FIREBEE) /* LITE board has no pic and (currently) no nvram */
|
||||
pic_init();
|
||||
nvram_init();
|
||||
pic_init();
|
||||
nvram_init();
|
||||
#endif /* MACHINE_FIREBEE */
|
||||
|
||||
xprintf("copy EmuTOS: ");
|
||||
xprintf("copy EmuTOS: ");
|
||||
|
||||
/* copy EMUTOS */
|
||||
src = (uint8_t *) EMUTOS;
|
||||
dma_memcpy(dst, src, EMUTOS_SIZE);
|
||||
xprintf("finished\r\n");
|
||||
/* copy EMUTOS */
|
||||
src = (uint8_t *) EMUTOS;
|
||||
dma_memcpy(dst, src, EMUTOS_SIZE);
|
||||
xprintf("finished\r\n");
|
||||
|
||||
xprintf("initialize MMU: ");
|
||||
mmu_init();
|
||||
xprintf("finished\r\n");
|
||||
xprintf("initialize MMU: ");
|
||||
mmu_init();
|
||||
xprintf("finished\r\n");
|
||||
|
||||
xprintf("initialize exception vector table: ");
|
||||
vec_init();
|
||||
xprintf("finished\r\n");
|
||||
xprintf("enable MMU: ");
|
||||
|
||||
xprintf("flush caches: ");
|
||||
flush_and_invalidate_caches();
|
||||
xprintf("finished\r\n");
|
||||
xprintf("enable MMU: ");
|
||||
MCF_MMU_MMUCR = MCF_MMU_MMUCR_EN; /* MMU on */
|
||||
NOP(); /* force pipeline sync */
|
||||
xprintf("finished\r\n");
|
||||
mmu_enable(); /* force pipeline sync */
|
||||
|
||||
#ifdef MACHINE_FIREBEE
|
||||
xprintf("IDE reset: ");
|
||||
/* IDE reset */
|
||||
* (volatile uint8_t *) (0xffff8802 - 2) = 14;
|
||||
* (volatile uint8_t *) (0xffff8802 - 0) = 0x80;
|
||||
wait(1);
|
||||
xprintf("finished\r\n");
|
||||
|
||||
* (volatile uint8_t *) (0xffff8802 - 0) = 0;
|
||||
xprintf("initialize exception vector table: ");
|
||||
vec_init();
|
||||
xprintf("finished\r\n");
|
||||
|
||||
xprintf("finished\r\n");
|
||||
xprintf("enable video: ");
|
||||
/*
|
||||
* video setup (25MHz)
|
||||
*/
|
||||
* (volatile uint32_t *) (0xf0000410 + 0) = 0x032002ba; /* horizontal 640x480 */
|
||||
* (volatile uint32_t *) (0xf0000410 + 4) = 0x020c020a; /* vertical 640x480 */
|
||||
* (volatile uint32_t *) (0xf0000410 + 8) = 0x0190015d; /* horizontal 320x240 */
|
||||
* (volatile uint32_t *) (0xf0000410 + 12) = 0x020C020A; /* vertical 320x230 */
|
||||
xprintf("flush caches: ");
|
||||
flush_and_invalidate_caches();
|
||||
xprintf("finished\r\n");
|
||||
|
||||
#ifdef MACHINE_FIREBEE
|
||||
xprintf("IDE reset: ");
|
||||
/* IDE reset */
|
||||
* (volatile uint8_t *) (0xffff8802 - 2) = 14;
|
||||
* (volatile uint8_t *) (0xffff8802 - 0) = 0x80;
|
||||
wait(1);
|
||||
|
||||
* (volatile uint8_t *) (0xffff8802 - 0) = 0;
|
||||
|
||||
xprintf("finished\r\n");
|
||||
xprintf("enable video: ");
|
||||
/*
|
||||
* video setup (25MHz)
|
||||
*/
|
||||
* (volatile uint32_t *) (0xf0000410 + 0) = 0x032002ba; /* horizontal 640x480 */
|
||||
* (volatile uint32_t *) (0xf0000410 + 4) = 0x020c020a; /* vertical 640x480 */
|
||||
* (volatile uint32_t *) (0xf0000410 + 8) = 0x0190015d; /* horizontal 320x240 */
|
||||
* (volatile uint32_t *) (0xf0000410 + 12) = 0x020C020A; /* vertical 320x230 */
|
||||
|
||||
#ifdef _NOT_USED_
|
||||
// 32MHz
|
||||
* (volatile uint32_t *) (0xf0000410 + 0) = 0x037002ba; /* horizontal 640x480 */
|
||||
* (volatile uint32_t *) (0xf0000410 + 4) = 0x020d020a; /* vertical 640x480 */
|
||||
* (volatile uint32_t *) (0xf0000410 + 8) = 0x02a001e0; /* horizontal 320x240 */
|
||||
* (volatile uint32_t *) (0xf0000410 + 12) = 0x05a00160; /* vertical 320x230 */
|
||||
* (volatile uint32_t *) (0xf0000410 + 0) = 0x037002ba; /* horizontal 640x480 */
|
||||
* (volatile uint32_t *) (0xf0000410 + 4) = 0x020d020a; /* vertical 640x480 */
|
||||
* (volatile uint32_t *) (0xf0000410 + 8) = 0x02a001e0; /* horizontal 320x240 */
|
||||
* (volatile uint32_t *) (0xf0000410 + 12) = 0x05a00160; /* vertical 320x230 */
|
||||
#endif /* _NOT_USED_ */
|
||||
|
||||
/* fifo on, refresh on, ddrcs and cke on, video dac on */
|
||||
* (volatile uint32_t *) (0xf0000410 - 0x20) = 0x01070002;
|
||||
/* fifo on, refresh on, ddrcs and cke on, video dac on */
|
||||
* (volatile uint32_t *) (0xf0000410 - 0x20) = 0x01070002;
|
||||
|
||||
xprintf("finished\r\n");
|
||||
xprintf("finished\r\n");
|
||||
|
||||
enable_coldfire_interrupts();
|
||||
enable_coldfire_interrupts();
|
||||
|
||||
#ifdef _NOT_USED_
|
||||
screen_init();
|
||||
screen_init();
|
||||
|
||||
/* experimental */
|
||||
{
|
||||
int i;
|
||||
uint32_t *scradr = 0xd00000;
|
||||
/* experimental */
|
||||
{
|
||||
int i;
|
||||
uint32_t *scradr = 0xd00000;
|
||||
|
||||
for (i = 0; i < 100; i++)
|
||||
{
|
||||
uint32_t *p = scradr;
|
||||
for (i = 0; i < 100; i++)
|
||||
{
|
||||
uint32_t *p = scradr;
|
||||
|
||||
for (p = scradr; p < scradr + 1024 * 150L; p++)
|
||||
{
|
||||
*p = 0xffffffff;
|
||||
}
|
||||
for (p = scradr; p < scradr + 1024 * 150L; p++)
|
||||
{
|
||||
*p = 0xffffffff;
|
||||
}
|
||||
|
||||
for (p = scradr; p < scradr + 1024 * 150L; p++)
|
||||
{
|
||||
*p = 0x0;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (p = scradr; p < scradr + 1024 * 150L; p++)
|
||||
{
|
||||
*p = 0x0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* _NOT_USED_ */
|
||||
|
||||
#endif /* MACHINE_FIREBEE */
|
||||
|
||||
sd_card_init();
|
||||
sd_card_init();
|
||||
|
||||
/*
|
||||
* memory setup
|
||||
*/
|
||||
memset((void *) 0x400, 0, 0x400);
|
||||
/*
|
||||
* memory setup
|
||||
*/
|
||||
memset((void *) 0x400, 0, 0x400);
|
||||
|
||||
#if defined(MACHINE_FIREBEE)
|
||||
/* set Falcon bus control register */
|
||||
/* sets bit 3 and 6. Both are undefined on an original Falcon? */
|
||||
/* set Falcon bus control register */
|
||||
/* sets bit 3 and 6. Both are undefined on an original Falcon? */
|
||||
|
||||
* (volatile uint8_t *) 0xffff8007 = 0x48;
|
||||
* (volatile uint8_t *) 0xffff8007 = 0x48;
|
||||
#endif /* MACHINE_FIREBEE */
|
||||
|
||||
/* ST RAM */
|
||||
/* ST RAM */
|
||||
|
||||
* (uint32_t *) 0x42e = STRAM_END; /* phystop TOS system variable */
|
||||
* (uint32_t *) 0x420 = 0x752019f3; /* memvalid TOS system variable */
|
||||
* (uint32_t *) 0x43a = 0x237698aa; /* memval2 TOS system variable */
|
||||
* (uint32_t *) 0x51a = 0x5555aaaa; /* memval3 TOS system variable */
|
||||
* (uint32_t *) 0x42e = STRAM_END; /* phystop TOS system variable */
|
||||
* (uint32_t *) 0x420 = 0x752019f3; /* memvalid TOS system variable */
|
||||
* (uint32_t *) 0x43a = 0x237698aa; /* memval2 TOS system variable */
|
||||
* (uint32_t *) 0x51a = 0x5555aaaa; /* memval3 TOS system variable */
|
||||
|
||||
/* TT-RAM */
|
||||
/* TT-RAM */
|
||||
|
||||
* (uint32_t *) 0x5a4 = FASTRAM_END; /* ramtop TOS system variable */
|
||||
* (uint32_t *) 0x5a8 = 0x1357bd13; /* ramvalid TOS system variable */
|
||||
* (uint32_t *) 0x5a4 = FASTRAM_END; /* ramtop TOS system variable */
|
||||
* (uint32_t *) 0x5a8 = 0x1357bd13; /* ramvalid TOS system variable */
|
||||
|
||||
#if defined(MACHINE_FIREBEE) /* m5484lite has no ACIA and no dip switch... */
|
||||
acia_init();
|
||||
acia_init();
|
||||
#endif /* MACHINE_FIREBEE */
|
||||
|
||||
srec_execute("BASFLASH.S19");
|
||||
srec_execute("BASFLASH.S19");
|
||||
|
||||
/* Jump into the OS */
|
||||
typedef void void_func(void);
|
||||
struct rom_header
|
||||
{
|
||||
void *initial_sp;
|
||||
void_func *initial_pc;
|
||||
};
|
||||
/* Jump into the OS */
|
||||
typedef void void_func(void);
|
||||
struct rom_header
|
||||
{
|
||||
void *initial_sp;
|
||||
void_func *initial_pc;
|
||||
};
|
||||
|
||||
xprintf("BaS initialization finished, enable interrupts\r\n");
|
||||
enable_coldfire_interrupts();
|
||||
init_isr();
|
||||
xprintf("BaS initialization finished, enable interrupts\r\n");
|
||||
enable_coldfire_interrupts();
|
||||
init_isr();
|
||||
|
||||
xprintf("call EmuTOS\r\n");
|
||||
struct rom_header *os_header = (struct rom_header *) TOS;
|
||||
os_header->initial_pc();
|
||||
xprintf("call EmuTOS\r\n");
|
||||
struct rom_header *os_header = (struct rom_header *) TOS;
|
||||
os_header->initial_pc();
|
||||
}
|
||||
|
||||
@@ -95,7 +95,8 @@ void flush_icache_range(void *address, size_t size)
|
||||
start_set = (uint32_t) address & _ICACHE_SET_MASK;
|
||||
end_set = (uint32_t) endaddr & _ICACHE_SET_MASK;
|
||||
|
||||
if (start_set > end_set) {
|
||||
if (start_set > end_set)
|
||||
{
|
||||
/* from the begining to the lowest address */
|
||||
for (set = 0; set <= end_set; set += (0x10 - 3))
|
||||
{
|
||||
@@ -115,7 +116,8 @@ void flush_icache_range(void *address, size_t size)
|
||||
/* next loop will finish the cache ie pass the hole */
|
||||
end_set = LAST_ICACHE_ADDR;
|
||||
}
|
||||
for (set = start_set; set <= end_set; set += (0x10 - 3)) {
|
||||
for (set = start_set; set <= end_set; set += (0x10 - 3))
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
" cpushl ic,(%[set]) \n\t"
|
||||
" addq.l #1,%[set] \n\t"
|
||||
|
||||
298
sys/exceptions.S
298
sys/exceptions.S
@@ -45,22 +45,37 @@
|
||||
.extern _irq5_handler
|
||||
.extern _irq7_handler
|
||||
|
||||
/* Register read/write macros */
|
||||
|
||||
#define MCF_EPORT_EPPAR __MBAR+0xF00
|
||||
#define MCF_EPORT_EPDDR __MBAR+0xF04
|
||||
#define MCF_EPORT_EPIER __MBAR+0xF05
|
||||
#define MCF_EPORT_EPDR __MBAR+0xF08
|
||||
#define MCF_EPORT_EPPDR __MBAR+0xF09
|
||||
#define MCF_EPORT_EPFR __MBAR+0xF0C
|
||||
|
||||
#define MCF_GPIO_PODR_FEC1L __MBAR+0xA07
|
||||
|
||||
#define MCF_PSC0_PSCTB_8BIT __MBAR+0x860C
|
||||
|
||||
.global _vec_init
|
||||
|
||||
// interrupt sources
|
||||
|
||||
/* 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
|
||||
@@ -115,85 +130,15 @@
|
||||
// Atari register equates (provided by FPGA)
|
||||
.equ vbasehi, 0xffff8201
|
||||
|
||||
//mmu ---------------------------------------------------
|
||||
|
||||
/* Register read/write macros */
|
||||
#define MCF_MMU_MMUCR __MMUBAR
|
||||
#define MCF_MMU_MMUOR __MMUBAR + 0x04
|
||||
#define MCF_MMU_MMUSR __MMUBAR + 0x08
|
||||
#define MCF_MMU_MMUAR __MMUBAR + 0x10
|
||||
#define MCF_MMU_MMUTR __MMUBAR + 0x14
|
||||
#define MCF_MMU_MMUDR __MMUBAR + 0x18
|
||||
|
||||
|
||||
/* Bit definitions and macros for MCF_MMU_MMUCR */
|
||||
#define MCF_MMU_MMUCR_EN (0x1)
|
||||
#define MCF_MMU_MMUCR_ASM (0x2)
|
||||
|
||||
/* Bit definitions and macros for MCF_MMU_MMUOR */
|
||||
#define MCF_MMU_MMUOR_UAA (0x1) /* update allocation address, i.e. write to TLB */
|
||||
#define MCF_MMU_MMUOR_ACC (0x2) /* activate access to TLB */
|
||||
#define MCF_MMU_MMUOR_RW (0x4) /* read/write TLB */
|
||||
#define MCF_MMU_MMUOR_ADR (0x8) /* search by address/TLB address */
|
||||
#define MCF_MMU_MMUOR_ITLB (0x10) /* act on instruction/data TLBs */
|
||||
#define MCF_MMU_MMUOR_CAS (0x20) /* clear all unlocked TLBs with matching ASID */
|
||||
#define MCF_MMU_MMUOR_CNL (0x40) /* clear all unlocked TLBs regardless of ASID */
|
||||
#define MCF_MMU_MMUOR_CA (0x80) /* clear all TLBs */
|
||||
#define MCF_MMU_MMUOR_STLB (0x100) /* search TLBs */
|
||||
#define MCF_MMU_MMUOR_AA(x) (((x) & 0xFFFF) << 0x10) /* TLB allocation address */
|
||||
|
||||
/* Bit definitions and macros for MCF_MMU_MMUSR */
|
||||
#define MCF_MMU_MMUSR_HIT (0x2) /* last lookup had a hit in TLB */
|
||||
#define MCF_MMU_MMUSR_WF (0x8) /* indicate write fault */
|
||||
#define MCF_MMU_MMUSR_RF (0x10) /* indicate read fault */
|
||||
#define MCF_MMU_MMUSR_SPF (0x20) /* indicate supervisor protect fault */
|
||||
|
||||
/* Bit definitions and macros for MCF_MMU_MMUAR */
|
||||
#define MCF_MMU_MMUAR_FA(x) (((x) & 0xFFFFFFFF) << 0)
|
||||
|
||||
/* Bit definitions and macros for MCF_MMU_MMUTR */
|
||||
#define MCF_MMU_MMUTR_V (0x1) /* valid bit for TLB */
|
||||
#define MCF_MMU_MMUTR_SG (0x2) /* set page as shared global */
|
||||
#define MCF_MMU_MMUTR_ID(x) (((x) & 0xFF) << 0x2) /* ASID (address space id) of page */
|
||||
#define MCF_MMU_MMUTR_VA(x) (((x) & 0x3FFFFF) << 0xA) /* virtual address of page */
|
||||
|
||||
/* Bit definitions and macros for MCF_MMU_MMUDR */
|
||||
#define MCF_MMU_MMUDR_LK (0x2) /* lock page */
|
||||
#define MCF_MMU_MMUDR_X (0x4) /* allow code execution in memory page */
|
||||
#define MCF_MMU_MMUDR_W (0x8) /* allow write to memory page */
|
||||
#define MCF_MMU_MMUDR_R (0x10) /* allow read from memory page */
|
||||
#define MCF_MMU_MMUDR_SP (0x20) /* supervisor protect memory page */
|
||||
#define MCF_MMU_MMUDR_CM(x) (((x) & 0x3) << 0x6) /* cache mode */
|
||||
#define MCF_MMU_MMUDR_SZ(x) (((x) & 0x3) << 0x8) /* page size */
|
||||
#define MCF_MMU_MMUDR_PA(x) (((x) & 0x3FFFFF) << 0xA) /* page physical address */
|
||||
|
||||
#define std_mmutr (MCF_MMU_MMUTR_SG | MCF_MMU_MMUTR_V)
|
||||
#define writethrough_mmudr (MCF_MMU_MMUDR_SZ(00) | MCF_MMU_MMUDR_CM(00) | MCF_MMU_MMUDR_R | MCF_MMU_MMUDR_W | MCF_MMU_MMUDR_X)
|
||||
#define copyback_mmudr (MCF_MMU_MMUDR_SZ(00) | MCF_MMU_MMUDR_CM(01) | MCF_MMU_MMUDR_R | MCF_MMU_MMUDR_W | MCF_MMU_MMUDR_X)
|
||||
|
||||
/*
|
||||
*
|
||||
* General Purpose Timers (GPT)
|
||||
*
|
||||
* macros
|
||||
*/
|
||||
|
||||
/* Register read/write macros */
|
||||
#define MCF_GPT0_GMS __MBAR+0x800
|
||||
|
||||
/*
|
||||
*
|
||||
* Slice Timers (SLT)
|
||||
*
|
||||
*/
|
||||
|
||||
#define MCF_SLT0_SCNT __MBAR+0x908
|
||||
|
||||
/**********************************************************/
|
||||
// macros
|
||||
/**********************************************************/
|
||||
.altmacro
|
||||
.macro irq vector,int_mask,clr_int
|
||||
//move.w #0x2700,sr // disable interrupt
|
||||
move.w #0x2700,sr // disable interrupt
|
||||
subq.l #8,sp
|
||||
movem.l d0/a5,(sp) // save registers
|
||||
|
||||
@@ -207,25 +152,6 @@
|
||||
rts
|
||||
.endm
|
||||
|
||||
/*
|
||||
* FIXME: this is a GNU gas kludge. Ugly, but I just can't come up with any smarter solution
|
||||
*
|
||||
* GNU as does not support multi-character constants. At least I don't know of any way it would.
|
||||
* The following might look more than strange, but I considered the statement
|
||||
*
|
||||
* mchar move.l, 'T,'E,'S,'T,-(SP)
|
||||
*
|
||||
* somewhat more readable than
|
||||
*
|
||||
* move.l #1413829460,-(SP)
|
||||
*
|
||||
* If anybody knows of any better way on how to do this - please do!
|
||||
*
|
||||
*/
|
||||
.macro mchar st,a,b,c,d,tgt
|
||||
\st #\a << 24|\b<<16|\c<<8|\d,\tgt
|
||||
.endm
|
||||
|
||||
.text
|
||||
_vec_init:
|
||||
move.l a2,-(sp) // Backup registers
|
||||
@@ -310,12 +236,12 @@ init_vec_loop:
|
||||
*/
|
||||
vector_table_start:
|
||||
std_exc_vec:
|
||||
//move.w #0x2700,sr // disable interrupt
|
||||
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
|
||||
|
||||
#define DBG_EXC
|
||||
#ifdef DBG_EXC
|
||||
// printout vector number of exception
|
||||
|
||||
@@ -323,16 +249,17 @@ std_exc_vec:
|
||||
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
|
||||
|
||||
cmp.l #33,d0 // do not debug-print various traps
|
||||
beq noprint // this would slow down interrupt
|
||||
cmp.l #34,d0 // processing enormously
|
||||
beq noprint
|
||||
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()
|
||||
move.l d0,-(sp) // vector number
|
||||
pea exception_text
|
||||
jsr _xprintf // call xprintf()
|
||||
add.l #3*4,sp // adjust stack
|
||||
@@ -349,14 +276,15 @@ noprint:
|
||||
move.l 4(sp),a5 // restore a5
|
||||
move.l d0,4(sp) // store exception routine address
|
||||
|
||||
//move.w 10(sp),d0 // restore original SR
|
||||
//bset #13,d0 // set supervisor bit
|
||||
//move.w d0,sr //
|
||||
// FIXME: what does this do and why?
|
||||
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 routine
|
||||
|
||||
exception_text:
|
||||
.ascii "DEBUG: EXCEPTION %d caught at %p"
|
||||
.ascii "DEBUG: EXCEPTION 0x%x caught at %p"
|
||||
.byte 13, 10, 0
|
||||
.align 4
|
||||
|
||||
@@ -369,54 +297,28 @@ reset_vector:
|
||||
|
||||
access:
|
||||
move.w #0x2700,sr // disable interrupts
|
||||
move.l d0,-(sp) // ++ vr
|
||||
|
||||
move.w 4(sp),d0 // get format_status word from stack
|
||||
andi.l #0x0c03,d0 // mask out fault status bits
|
||||
cmpi.l #0x0401,d0 // TLB miss on opword of instruction fetch?
|
||||
beq access_mmu // yes
|
||||
cmpi.l #0x0402,d0 // TLB miss on extension word of instruction fetch?
|
||||
beq access_mmu // yes
|
||||
cmpi.l #0x0802,d0 // TLB miss on data write?
|
||||
beq access_mmu // yes
|
||||
cmpi.l #0x0c02,d0 // TLB miss on data read, or read-modify-write?
|
||||
beq access_mmu // yes
|
||||
link a6,#-4 * 4 // make room for gcc scratch registers
|
||||
movem.l d0-d1/a0-a1,(sp) // and save them
|
||||
|
||||
bra bus_error // everything else is a classic bus error
|
||||
move.l 4(a6),-(sp) // get format_status longword
|
||||
move.l 8(a6),-(sp) // PC at exception
|
||||
move.l MCF_MMU_MMUAR,-(sp) // fault address
|
||||
move.l MCF_MMU_MMUSR,-(sp) // MMU status register
|
||||
move.w #0x2300,sr // can lower interrupt mask once MMU status is safe
|
||||
jsr _mmutr_miss
|
||||
lea 4 * 4(sp),sp // adjust stack
|
||||
|
||||
access_mmu:
|
||||
move.l MCF_MMU_MMUSR,d0 // did the last fault hit in TLB?
|
||||
btst #1,d0 // yes, it did. So we already mapped that page
|
||||
bne bus_error // and this must be a real bus error
|
||||
btst #5,d0 // supervisor protection fault?
|
||||
bne bus_error
|
||||
btst #4,d0 // read access fault?
|
||||
bne bus_error
|
||||
btst #3,d0 // write access fault?
|
||||
tst.l d0 // exception handler signals bus error
|
||||
bne bus_error
|
||||
|
||||
move.l MCF_MMU_MMUAR,d0
|
||||
cmp.l #__FASTRAM_END,d0 // above max User RAM area?
|
||||
bge bus_error // -> bus error
|
||||
|
||||
lea -3 * 4(sp),sp // save gcc scratch registers
|
||||
movem.l d1/a0-a1,(sp)
|
||||
|
||||
move.l 3 * 4 + 4 (sp),-(sp) // push exception stack frame
|
||||
move.l 5 * 4 + 4 (sp),-(sp) // push program counter at exception
|
||||
move.l d0,-(sp) // fault address
|
||||
jsr _mmutr_miss // else we have an MMU TLB miss
|
||||
add.l #3 * 4,sp // adjust stack
|
||||
|
||||
movem.l (sp),d1/a0-a1 // restore gcc scratch registers
|
||||
lea 3 * 4(sp),sp
|
||||
|
||||
move.l (sp)+,d0 // restore register
|
||||
|
||||
movem.l (sp),d0-d1/a0-a1 // restore stack
|
||||
unlk a6
|
||||
rte
|
||||
|
||||
bus_error:
|
||||
move.l (sp)+,d0 // restore register
|
||||
movem.l (sp),d0-d1/a0-a1
|
||||
unlk a6
|
||||
bra std_exc_vec
|
||||
|
||||
zero_divide:
|
||||
@@ -543,79 +445,6 @@ irq6: // MFP interrupt from FPGA
|
||||
lea MCF_EPORT_EPFR,a5 // clear int6 from edge port
|
||||
bset #6,(a5)
|
||||
|
||||
// screen adr change timed out?
|
||||
move.l _video_sbt,d0
|
||||
beq irq6_non_sca // nothing to do if 0
|
||||
|
||||
sub.l #0x70000000,d0 // substract 14 seconds
|
||||
lea MCF_SLT0_SCNT,a5
|
||||
cmp.l (a5),d0 // time reached?
|
||||
ble irq6_non_sca // not yet
|
||||
|
||||
lea -7 * 4(sp),sp // save more registers
|
||||
movem.l d0-d4/a0-a1,(sp) //
|
||||
clr.l d3 // beginn mit 0
|
||||
// jsr _flush_and_invalidate_caches FIXME: why should we need that?
|
||||
|
||||
// eintrag suchen
|
||||
irq6_next_sca:
|
||||
move.l d3,d0
|
||||
move.l d0,MCF_MMU_MMUAR // addresse
|
||||
move.l #0x106,d4
|
||||
move.l d4,MCF_MMU_MMUOR // suchen ->
|
||||
nop
|
||||
move.l MCF_MMU_MMUOR,d4
|
||||
clr.w d4
|
||||
swap d4
|
||||
move.l d4,MCF_MMU_MMUAR
|
||||
mvz.w #0x10e,d4
|
||||
move.l d4,MCF_MMU_MMUOR // einträge holen aus mmu
|
||||
nop
|
||||
move.l MCF_MMU_MMUTR,d4 // ID holen
|
||||
lsr.l #2,d4 // bit 9 bis 2
|
||||
cmp.w #sca_page_ID,d4 // ist screen change ID?
|
||||
bne irq6_sca_pn // nein -> page keine screen area next
|
||||
// eintrag <EFBFBD>ndern
|
||||
add.l #std_mmutr,d0
|
||||
move.l d3,d1 // page 0?
|
||||
beq irq6_sca_pn0 // ja ->
|
||||
add.l #copyback_mmudr,d1 // sonst page cb
|
||||
bra irq6_sca_pn1c
|
||||
irq6_sca_pn0:
|
||||
add.l #writethrough_mmudr/*|MCF_MMU_MMUDR_LK*/,d1 // page wt and locked
|
||||
irq6_sca_pn1c:
|
||||
mvz.w #0x10b,d2 // MMU update
|
||||
move.l d0,MCF_MMU_MMUTR
|
||||
move.l d1,MCF_MMU_MMUDR
|
||||
move.l d2,MCF_MMU_MMUOR // setze tlb data only
|
||||
nop
|
||||
// page copy
|
||||
move.l d3,a0
|
||||
add.l #0x60000000,a0
|
||||
move.l d3,a1
|
||||
move.l #0x10000,d4 // one whole page (1 MB)
|
||||
|
||||
|
||||
irq6_vcd0_loop:
|
||||
move.l (a0)+,(a1)+ // page copy
|
||||
move.l (a0)+,(a1)+
|
||||
move.l (a0)+,(a1)+
|
||||
move.l (a0)+,(a1)+
|
||||
subq.l #1,d4
|
||||
bne irq6_vcd0_loop
|
||||
|
||||
irq6_sca_pn:
|
||||
add.l #0x00100000,d3 // next
|
||||
cmp.l #0x00d00000,d3 // ende?
|
||||
blt irq6_next_sca // nein->
|
||||
|
||||
move.l #0x2000,d0
|
||||
move.l d0,_video_tlb // anfangszustand wieder herstellen
|
||||
clr.l _video_sbt // zeit löschen
|
||||
|
||||
movem.l (sp),d0-d4/a0-a1 // restore registers
|
||||
lea 7 * 4(sp),sp
|
||||
|
||||
irq6_non_sca:
|
||||
// test auf acsi dma -----------------------------------------------------------------
|
||||
lea 0xfffffa0b,a5
|
||||
@@ -666,10 +495,6 @@ acsi_dma: // atari dma
|
||||
move.l d1,-(sp)
|
||||
|
||||
lea MCF_PSC0_PSCTB_8BIT,a1 // ++ vr
|
||||
mchar move.l, 'D,'M','A,'\ ,(a1)
|
||||
//move.l #"DMA ",(a1)
|
||||
mchar move.l,'I,'N,'T,'!,(a1)
|
||||
// move.l #'INT!',(a1)
|
||||
|
||||
lea 0xf0020110,a5 // fifo daten
|
||||
acsi_dma_start:
|
||||
@@ -752,7 +577,10 @@ irq7:
|
||||
*
|
||||
* 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
|
||||
* when the video base address gets changed. In the "MiNT-compatible MMU"-version this
|
||||
* doesn't do anything, currently, but
|
||||
* TODO: could be used for e.g. activating copyback cache mode on those ST-RAM pages
|
||||
* that aren't video pages.
|
||||
*/
|
||||
|
||||
|
||||
@@ -763,11 +591,13 @@ handler_gpt0:
|
||||
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 */
|
||||
|
||||
552
sys/interrupts.c
552
sys/interrupts.c
@@ -52,45 +52,45 @@ extern void (*rt_vbr[])(void);
|
||||
*/
|
||||
int register_interrupt_handler(uint8_t source, uint8_t level, uint8_t priority, uint8_t intr, void (*handler)(void))
|
||||
{
|
||||
int ipl;
|
||||
int i;
|
||||
volatile uint8_t *ICR = &MCF_INTC_ICR01 - 1;
|
||||
uint8_t lp;
|
||||
int ipl;
|
||||
int i;
|
||||
volatile uint8_t *ICR = &MCF_INTC_ICR01 - 1;
|
||||
uint8_t lp;
|
||||
|
||||
source &= 63;
|
||||
priority &= 7;
|
||||
source &= 63;
|
||||
priority &= 7;
|
||||
|
||||
if (source < 1 || source > 63)
|
||||
{
|
||||
dbg("interrupt source %d not defined\r\n", source);
|
||||
return -1;
|
||||
}
|
||||
if (source < 1 || source > 63)
|
||||
{
|
||||
dbg("interrupt source %d not defined\r\n", source);
|
||||
return -1;
|
||||
}
|
||||
|
||||
lp = MCF_INTC_ICR_IL(level) | MCF_INTC_ICR_IP(priority);
|
||||
lp = MCF_INTC_ICR_IL(level) | MCF_INTC_ICR_IP(priority);
|
||||
|
||||
/* check if this combination is already set somewhere */
|
||||
for (i = 1; i < 64; i++)
|
||||
{
|
||||
if (ICR[i] == lp)
|
||||
{
|
||||
dbg("level %d and priority %d already used for interrupt source %d!\r\n",
|
||||
level, priority, i);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* check if this combination is already set somewhere */
|
||||
for (i = 1; i < 64; i++)
|
||||
{
|
||||
if (ICR[i] == lp)
|
||||
{
|
||||
dbg("level %d and priority %d already used for interrupt source %d!\r\n",
|
||||
level, priority, i);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* disable interrupts */
|
||||
ipl = set_ipl(7);
|
||||
/* disable interrupts */
|
||||
ipl = set_ipl(7);
|
||||
|
||||
VBR[64 + source] = handler; /* first 64 vectors are system exceptions */
|
||||
VBR[64 + source] = handler; /* first 64 vectors are system exceptions */
|
||||
|
||||
/* set level and priority in interrupt controller */
|
||||
ICR[source] = lp;
|
||||
/* set level and priority in interrupt controller */
|
||||
ICR[source] = lp;
|
||||
|
||||
/* set interrupt mask to where it was before */
|
||||
set_ipl(ipl);
|
||||
/* set interrupt mask to where it was before */
|
||||
set_ipl(ipl);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef MAX_ISR_ENTRY
|
||||
@@ -100,10 +100,10 @@ int register_interrupt_handler(uint8_t source, uint8_t level, uint8_t priority,
|
||||
|
||||
struct isrentry
|
||||
{
|
||||
int vector;
|
||||
int (*handler)(void *, void *);
|
||||
void *hdev;
|
||||
void *harg;
|
||||
int vector;
|
||||
int (*handler)(void *, void *);
|
||||
void *hdev;
|
||||
void *harg;
|
||||
};
|
||||
|
||||
static struct isrentry isrtab[MAX_ISR_ENTRY]; /* list of interrupt service routines */
|
||||
@@ -113,7 +113,7 @@ static struct isrentry isrtab[MAX_ISR_ENTRY]; /* list of interrupt service
|
||||
*/
|
||||
void isr_init(void)
|
||||
{
|
||||
memset(isrtab, 0, sizeof(isrtab));
|
||||
memset(isrtab, 0, sizeof(isrtab));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -126,56 +126,56 @@ void isr_init(void)
|
||||
*/
|
||||
int isr_register_handler(int vector, int (*handler)(void *, void *), void *hdev, void *harg)
|
||||
{
|
||||
int index;
|
||||
int index;
|
||||
|
||||
if ((vector == 0) || (handler == NULL))
|
||||
{
|
||||
dbg("illegal vector or handler!\r\n");
|
||||
return false;
|
||||
}
|
||||
if ((vector == 0) || (handler == NULL))
|
||||
{
|
||||
dbg("illegal vector or handler!\r\n");
|
||||
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;
|
||||
}
|
||||
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;
|
||||
if (isrtab[index].vector == 0)
|
||||
{
|
||||
isrtab[index].vector = vector;
|
||||
isrtab[index].handler = handler;
|
||||
isrtab[index].hdev = hdev;
|
||||
isrtab[index].harg = harg;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
dbg("no available slots to register handler for vector %d\n\r", vector);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
dbg("no available slots to register handler for vector %d\n\r", vector);
|
||||
|
||||
return false; /* no available slots */
|
||||
return false; /* no available slots */
|
||||
}
|
||||
|
||||
void isr_remove_handler(int (*handler)(void *, void *))
|
||||
{
|
||||
/*
|
||||
* This routine removes from the ISR table all
|
||||
* entries that matches 'handler'.
|
||||
*/
|
||||
int index;
|
||||
/*
|
||||
* 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));
|
||||
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);
|
||||
return;
|
||||
}
|
||||
}
|
||||
dbg("no such handler registered (handler=%p\r\n", handler);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -184,27 +184,27 @@ void isr_remove_handler(int (*handler)(void *, void *))
|
||||
*/
|
||||
bool isr_execute_handler(int vector)
|
||||
{
|
||||
int index;
|
||||
bool retval = false;
|
||||
int index;
|
||||
bool retval = false;
|
||||
|
||||
/*
|
||||
* locate a BaS Interrupt Service Routine handler.
|
||||
*/
|
||||
for (index = 0; index < MAX_ISR_ENTRY; index++)
|
||||
{
|
||||
if (isrtab[index].vector == vector)
|
||||
{
|
||||
retval = true;
|
||||
/*
|
||||
* locate a BaS Interrupt Service Routine handler.
|
||||
*/
|
||||
for (index = 0; index < MAX_ISR_ENTRY; index++)
|
||||
{
|
||||
if (isrtab[index].vector == vector)
|
||||
{
|
||||
retval = true;
|
||||
|
||||
if (isrtab[index].handler(isrtab[index].hdev, isrtab[index].harg))
|
||||
{
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
}
|
||||
dbg("no BaS isr handler for vector %d found\r\n", vector);
|
||||
if (isrtab[index].handler(isrtab[index].hdev, isrtab[index].harg))
|
||||
{
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
}
|
||||
dbg("no BaS isr handler for vector %d found\r\n", vector);
|
||||
|
||||
return retval;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -215,25 +215,25 @@ bool isr_execute_handler(int vector)
|
||||
*/
|
||||
int pic_interrupt_handler(void *arg1, void *arg2)
|
||||
{
|
||||
uint8_t rcv_byte;
|
||||
uint8_t rcv_byte;
|
||||
|
||||
rcv_byte = MCF_PSC3_PSCRB_8BIT;
|
||||
if (rcv_byte == 2) // PIC requests RTC data
|
||||
{
|
||||
uint8_t *rtc_reg = (uint8_t *) 0xffff8961;
|
||||
uint8_t *rtc_data = (uint8_t *) 0xffff8963;
|
||||
int index = 0;
|
||||
rcv_byte = MCF_PSC3_PSCRB_8BIT;
|
||||
if (rcv_byte == 2) // PIC requests RTC data
|
||||
{
|
||||
uint8_t *rtc_reg = (uint8_t *) 0xffff8961;
|
||||
uint8_t *rtc_data = (uint8_t *) 0xffff8963;
|
||||
int index = 0;
|
||||
|
||||
xprintf("PIC interrupt: requesting RTC data\r\n");
|
||||
xprintf("PIC interrupt: requesting RTC data\r\n");
|
||||
|
||||
MCF_PSC3_PSCTB_8BIT = 0x82; // header byte to PIC
|
||||
do
|
||||
{
|
||||
*rtc_reg = 0;
|
||||
MCF_PSC3_PSCTB_8BIT = *rtc_data;
|
||||
} while (index++ < 64);
|
||||
}
|
||||
return 1;
|
||||
MCF_PSC3_PSCTB_8BIT = 0x82; // header byte to PIC
|
||||
do
|
||||
{
|
||||
*rtc_reg = 0;
|
||||
MCF_PSC3_PSCTB_8BIT = *rtc_data;
|
||||
} while (index++ < 64);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern int32_t video_sbt;
|
||||
@@ -241,93 +241,93 @@ extern int32_t video_tlb;
|
||||
|
||||
void video_addr_timeout(void)
|
||||
{
|
||||
uint32_t addr = 0x0L;
|
||||
uint32_t *src;
|
||||
uint32_t *dst;
|
||||
uint32_t asid;
|
||||
uint32_t addr = 0x0L;
|
||||
uint32_t *src;
|
||||
uint32_t *dst;
|
||||
uint32_t asid;
|
||||
|
||||
dbg("video address timeout\r\n");
|
||||
flush_and_invalidate_caches();
|
||||
dbg("video address timeout\r\n");
|
||||
flush_and_invalidate_caches();
|
||||
|
||||
do
|
||||
{
|
||||
uint32_t tlb;
|
||||
uint32_t page_attr;
|
||||
do
|
||||
{
|
||||
uint32_t tlb;
|
||||
uint32_t page_attr;
|
||||
|
||||
/*
|
||||
* search tlb entry id for addr (if not available, the MMU
|
||||
* will provide a new one based on its LRU algorithm)
|
||||
*/
|
||||
MCF_MMU_MMUAR = addr;
|
||||
MCF_MMU_MMUOR =
|
||||
MCF_MMU_MMUOR_STLB |
|
||||
MCF_MMU_MMUOR_RW |
|
||||
MCF_MMU_MMUOR_ACC;
|
||||
NOP();
|
||||
tlb = (MCF_MMU_MMUOR >> 16) & 0xffff;
|
||||
/*
|
||||
* search tlb entry id for addr (if not available, the MMU
|
||||
* will provide a new one based on its LRU algorithm)
|
||||
*/
|
||||
MCF_MMU_MMUAR = addr;
|
||||
MCF_MMU_MMUOR =
|
||||
MCF_MMU_MMUOR_STLB |
|
||||
MCF_MMU_MMUOR_RW |
|
||||
MCF_MMU_MMUOR_ACC;
|
||||
NOP();
|
||||
tlb = (MCF_MMU_MMUOR >> 16) & 0xffff;
|
||||
|
||||
/*
|
||||
* retrieve tlb entry with the found TLB entry id
|
||||
*/
|
||||
MCF_MMU_MMUAR = tlb;
|
||||
MCF_MMU_MMUOR =
|
||||
MCF_MMU_MMUOR_STLB |
|
||||
MCF_MMU_MMUOR_ADR |
|
||||
MCF_MMU_MMUOR_RW |
|
||||
MCF_MMU_MMUOR_ACC;
|
||||
NOP();
|
||||
/*
|
||||
* retrieve tlb entry with the found TLB entry id
|
||||
*/
|
||||
MCF_MMU_MMUAR = tlb;
|
||||
MCF_MMU_MMUOR =
|
||||
MCF_MMU_MMUOR_STLB |
|
||||
MCF_MMU_MMUOR_ADR |
|
||||
MCF_MMU_MMUOR_RW |
|
||||
MCF_MMU_MMUOR_ACC;
|
||||
NOP();
|
||||
|
||||
asid = (MCF_MMU_MMUTR >> 2) & 0x1fff; /* fetch ASID of page */;
|
||||
if (asid != sca_page_ID) /* check if screen area */
|
||||
{
|
||||
addr += 0x100000;
|
||||
continue; /* next page */
|
||||
}
|
||||
asid = (MCF_MMU_MMUTR >> 2) & 0x1fff; /* fetch ASID of page */;
|
||||
if (asid != sca_page_ID) /* check if screen area */
|
||||
{
|
||||
addr += 0x100000;
|
||||
continue; /* next page */
|
||||
}
|
||||
|
||||
/* modify found TLB entry */
|
||||
if (addr == 0x0)
|
||||
{
|
||||
page_attr =
|
||||
MCF_MMU_MMUDR_LK |
|
||||
MCF_MMU_MMUDR_SZ(0) |
|
||||
MCF_MMU_MMUDR_CM(0) |
|
||||
MCF_MMU_MMUDR_R |
|
||||
MCF_MMU_MMUDR_W |
|
||||
MCF_MMU_MMUDR_X;
|
||||
}
|
||||
else
|
||||
{
|
||||
page_attr =
|
||||
MCF_MMU_MMUTR_SG |
|
||||
MCF_MMU_MMUTR_V;
|
||||
}
|
||||
/* modify found TLB entry */
|
||||
if (addr == 0x0)
|
||||
{
|
||||
page_attr =
|
||||
MCF_MMU_MMUDR_LK |
|
||||
MCF_MMU_MMUDR_SZ(0) |
|
||||
MCF_MMU_MMUDR_CM(0) |
|
||||
MCF_MMU_MMUDR_R |
|
||||
MCF_MMU_MMUDR_W |
|
||||
MCF_MMU_MMUDR_X;
|
||||
}
|
||||
else
|
||||
{
|
||||
page_attr =
|
||||
MCF_MMU_MMUTR_SG |
|
||||
MCF_MMU_MMUTR_V;
|
||||
}
|
||||
|
||||
|
||||
MCF_MMU_MMUTR = addr;
|
||||
MCF_MMU_MMUDR = page_attr;
|
||||
MCF_MMU_MMUOR =
|
||||
MCF_MMU_MMUOR_STLB |
|
||||
MCF_MMU_MMUOR_ADR |
|
||||
MCF_MMU_MMUOR_ACC |
|
||||
MCF_MMU_MMUOR_UAA;
|
||||
NOP();
|
||||
MCF_MMU_MMUTR = addr;
|
||||
MCF_MMU_MMUDR = page_attr;
|
||||
MCF_MMU_MMUOR =
|
||||
MCF_MMU_MMUOR_STLB |
|
||||
MCF_MMU_MMUOR_ADR |
|
||||
MCF_MMU_MMUOR_ACC |
|
||||
MCF_MMU_MMUOR_UAA;
|
||||
NOP();
|
||||
|
||||
dst = (uint32_t *) 0x60000000 + addr;
|
||||
src = (uint32_t *) addr;
|
||||
while (dst < (uint32_t *) 0x60000000 + addr + 0x10000)
|
||||
{
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
}
|
||||
dst = (uint32_t *) 0x60000000 + addr;
|
||||
src = (uint32_t *) addr;
|
||||
while (dst < (uint32_t *) 0x60000000 + addr + 0x10000)
|
||||
{
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
addr += 0x100000;
|
||||
} while (addr < 0xd00000);
|
||||
video_tlb = 0x2000;
|
||||
video_sbt = 0;
|
||||
addr += 0x100000;
|
||||
} while (addr < 0xd00000);
|
||||
video_tlb = 0x2000;
|
||||
video_sbt = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -336,16 +336,16 @@ void video_addr_timeout(void)
|
||||
*/
|
||||
void blink_led(void)
|
||||
{
|
||||
static uint16_t blinker = 0;
|
||||
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 */
|
||||
}
|
||||
if ((blinker++ & 0x80) > 0)
|
||||
{
|
||||
MCF_GPIO_PODR_FEC1L |= (1 << 4); /* LED off */
|
||||
}
|
||||
else
|
||||
{
|
||||
MCF_GPIO_PODR_FEC1L &= ~(1 << 4); /* LED on */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -363,47 +363,47 @@ void blink_led(void)
|
||||
|
||||
bool irq6_acsi_dma_interrupt(void)
|
||||
{
|
||||
dbg("ACSI DMA interrupt\r\n");
|
||||
dbg("ACSI DMA interrupt\r\n");
|
||||
|
||||
/*
|
||||
* TODO: implement handler
|
||||
*/
|
||||
/*
|
||||
* TODO: implement handler
|
||||
*/
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool irq6_interrupt_handler(uint32_t sf1, uint32_t sf2)
|
||||
{
|
||||
bool handled = false;
|
||||
bool handled = false;
|
||||
|
||||
MCF_EPORT_EPFR |= (1 << 6); /* clear int6 from edge port */
|
||||
MCF_EPORT_EPFR |= (1 << 6); /* clear int6 from edge port */
|
||||
|
||||
if (video_sbt != 0 && (video_sbt - 0x70000000) > MCF_SLT0_SCNT)
|
||||
{
|
||||
video_addr_timeout();
|
||||
handled = true;
|
||||
}
|
||||
if (video_sbt != 0 && (video_sbt - 0x70000000) > MCF_SLT0_SCNT)
|
||||
{
|
||||
video_addr_timeout();
|
||||
handled = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* check if ACSI DMA interrupt
|
||||
*/
|
||||
/*
|
||||
* check if ACSI DMA interrupt
|
||||
*/
|
||||
|
||||
if (FALCON_MFP_IERA & (1 << 7))
|
||||
{
|
||||
/* ACSI interrupt is enabled */
|
||||
if (FALCON_MFP_IPRA & (1 << 7))
|
||||
{
|
||||
irq6_acsi_dma_interrupt();
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
if (FALCON_MFP_IERA & (1 << 7))
|
||||
{
|
||||
/* ACSI interrupt is enabled */
|
||||
if (FALCON_MFP_IPRA & (1 << 7))
|
||||
{
|
||||
irq6_acsi_dma_interrupt();
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (FALCON_MFP_IPRA || FALCON_MFP_IPRB)
|
||||
{
|
||||
blink_led();
|
||||
}
|
||||
if (FALCON_MFP_IPRA || FALCON_MFP_IPRB)
|
||||
{
|
||||
blink_led();
|
||||
}
|
||||
|
||||
return handled;
|
||||
return handled;
|
||||
}
|
||||
|
||||
#if defined(MACHINE_FIREBEE)
|
||||
@@ -430,112 +430,10 @@ bool irq6_interrupt_handler(uint32_t sf1, uint32_t sf2)
|
||||
*/
|
||||
void gpt0_interrupt_handler(void)
|
||||
{
|
||||
uint32_t video_address;
|
||||
uint32_t video_end_address;
|
||||
int page_number;
|
||||
bool already_set;
|
||||
extern uint32_t _STRAM_END;
|
||||
dbg("screen base = 0x%x\r\n", vbasehi);
|
||||
|
||||
dbg("screen base = 0x%x\r\n", vbasehi);
|
||||
|
||||
if (vbasehi < 2) /* screen base lower than 0x20000? */
|
||||
{
|
||||
goto rearm_trigger; /* do nothing */
|
||||
}
|
||||
else if (vbasehi >= 0xd0) /* higher than 0xd00000 (normal Falcon address)? */
|
||||
{
|
||||
video_sbt = MCF_SLT0_SCNT; /* FIXME: no idea why we need to save the time here */
|
||||
}
|
||||
video_address = (vbasehi << 16) | (vbasemid << 8) | vbaselow;
|
||||
|
||||
page_number = video_address >> 20; /* calculate a page number */
|
||||
already_set = (video_tlb & (1 << page_number)); /* already in bitset? */
|
||||
video_tlb |= page_number; /* set it */
|
||||
|
||||
if (! already_set) /* newly set page, need to copy contents */
|
||||
{
|
||||
flush_and_invalidate_caches();
|
||||
dma_memcpy((uint8_t *) video_address + 0x60000000, (uint8_t *) video_address, 0x100000);
|
||||
|
||||
/*
|
||||
* create an MMU TLB entry for the new video page
|
||||
*/
|
||||
|
||||
/*
|
||||
* first search for an existing entry with our address. If none is found,
|
||||
* the MMU will propose a new one
|
||||
*/
|
||||
MCF_MMU_MMUAR = video_address;
|
||||
MCF_MMU_MMUOR = 0x106;
|
||||
NOP();
|
||||
|
||||
/*
|
||||
* take this MMU TLB entry and set it to our video address and page mapping
|
||||
*/
|
||||
MCF_MMU_MMUAR = (MCF_MMU_MMUOR >> 16) & 0xffff; /* set TLB id */
|
||||
|
||||
MCF_MMU_MMUTR = video_address |
|
||||
MCF_MMU_MMUTR_ID(sca_page_ID) | /* set video page ID */
|
||||
MCF_MMU_MMUTR_SG | /* shared global */
|
||||
MCF_MMU_MMUTR_V; /* valid */
|
||||
MCF_MMU_MMUDR = (video_address + 0x60000000) | /* physical address */
|
||||
MCF_MMU_MMUDR_SZ(0) | /* 1 MB page size */
|
||||
MCF_MMU_MMUDR_CM(0) | /* writethrough */
|
||||
MCF_MMU_MMUDR_R | /* readable */
|
||||
MCF_MMU_MMUDR_W | /* writeable */
|
||||
MCF_MMU_MMUDR_X; /* executable */
|
||||
MCF_MMU_MMUOR = 0x10b; /* update TLB entry */
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the effective screen memory size to see if we need to map another page
|
||||
* in case the new screen spans more than one single page
|
||||
*/
|
||||
video_end_address = video_address + (vde - vdb) * vwrap;
|
||||
if (video_end_address < _STRAM_END)
|
||||
{
|
||||
page_number = video_end_address >> 20; /* calculate a page number */
|
||||
already_set = (video_tlb & (1 << page_number)); /* already in bitset? */
|
||||
video_tlb |= page_number; /* set it */
|
||||
|
||||
if (! already_set) /* newly set page, need to copy contents */
|
||||
{
|
||||
flush_and_invalidate_caches();
|
||||
dma_memcpy((uint8_t *) video_end_address + 0x60000000, (uint8_t *) video_end_address, 0x100000);
|
||||
|
||||
/*
|
||||
* create an MMU TLB entry for the new video page
|
||||
*/
|
||||
|
||||
/*
|
||||
* first search for an existing entry with our address. If none is found,
|
||||
* the MMU will propose a new one
|
||||
*/
|
||||
MCF_MMU_MMUAR = video_end_address;
|
||||
MCF_MMU_MMUOR = 0x106;
|
||||
NOP();
|
||||
|
||||
/*
|
||||
* take this MMU TLB entry and set it to our video address and page mapping
|
||||
*/
|
||||
MCF_MMU_MMUAR = (MCF_MMU_MMUOR >> 16) & 0xffff; /* set TLB id */
|
||||
|
||||
MCF_MMU_MMUTR = video_end_address |
|
||||
MCF_MMU_MMUTR_ID(sca_page_ID) | /* set video page ID */
|
||||
MCF_MMU_MMUTR_SG | /* shared global */
|
||||
MCF_MMU_MMUTR_V; /* valid */
|
||||
MCF_MMU_MMUDR = (video_end_address + 0x60000000) | /* physical address */
|
||||
MCF_MMU_MMUDR_SZ(0) | /* 1 MB page size */
|
||||
MCF_MMU_MMUDR_CM(0) | /* writethrough */
|
||||
MCF_MMU_MMUDR_R | /* readable */
|
||||
MCF_MMU_MMUDR_W | /* writeable */
|
||||
MCF_MMU_MMUDR_X; /* executable */
|
||||
MCF_MMU_MMUOR = 0x10b; /* update TLB entry */
|
||||
}
|
||||
}
|
||||
rearm_trigger:
|
||||
MCF_GPT0_GMS &= ~1; /* rearm trigger */
|
||||
NOP();
|
||||
MCF_GPT0_GMS |= 1;
|
||||
MCF_GPT0_GMS &= ~1; /* rearm trigger */
|
||||
NOP();
|
||||
MCF_GPT0_GMS |= 1;
|
||||
}
|
||||
#endif /* MACHINE_FIREBEE */
|
||||
|
||||
771
sys/mmu.c
771
sys/mmu.c
@@ -1,5 +1,6 @@
|
||||
#include "mmu.h"
|
||||
#include "acia.h"
|
||||
#include "exceptions.h"
|
||||
|
||||
/*
|
||||
* mmu.c
|
||||
@@ -62,12 +63,14 @@
|
||||
#error "unknown machine!"
|
||||
#endif /* MACHINE_FIREBEE */
|
||||
|
||||
// #define DEBUG_MMU
|
||||
#ifdef DEBUG_MMU
|
||||
//#define DBG_MMU
|
||||
#ifdef DBG_MMU
|
||||
#define dbg(format, arg...) do { xprintf("DEBUG (%s()): " format, __FUNCTION__, ##arg);} while(0)
|
||||
#else
|
||||
#define dbg(format, arg...) do {;} while (0)
|
||||
#endif /* DEBUG_MMU */
|
||||
#endif /* DBG_MMU */
|
||||
#define err(format, arg...) do { xprintf("ERROR (%s()): " format, __FUNCTION__, ##arg); xprintf("system halted\r\n"); } while(0); while(1)
|
||||
|
||||
|
||||
/*
|
||||
* set ASID register
|
||||
@@ -75,19 +78,19 @@
|
||||
*/
|
||||
inline uint32_t set_asid(uint32_t value)
|
||||
{
|
||||
extern long rt_asid;
|
||||
uint32_t ret = rt_asid;
|
||||
extern long rt_asid;
|
||||
uint32_t ret = rt_asid;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"movec %[value],ASID\n\t"
|
||||
: /* no output */
|
||||
: [value] "r" (value)
|
||||
:
|
||||
);
|
||||
__asm__ __volatile__(
|
||||
"movec %[value],ASID\n\t"
|
||||
: /* no output */
|
||||
: [value] "r" (value)
|
||||
: "memory"
|
||||
);
|
||||
|
||||
rt_asid = value;
|
||||
rt_asid = value;
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -97,18 +100,18 @@ inline uint32_t set_asid(uint32_t value)
|
||||
*/
|
||||
inline uint32_t set_acr0(uint32_t value)
|
||||
{
|
||||
extern uint32_t rt_acr0;
|
||||
uint32_t ret = rt_acr0;
|
||||
extern uint32_t rt_acr0;
|
||||
uint32_t ret = rt_acr0;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"movec %[value],ACR0\n\t"
|
||||
: /* not output */
|
||||
: [value] "r" (value)
|
||||
:
|
||||
);
|
||||
rt_acr0 = value;
|
||||
__asm__ __volatile__(
|
||||
"movec %[value],ACR0\n\t"
|
||||
: /* not output */
|
||||
: [value] "r" (value)
|
||||
: "memory"
|
||||
);
|
||||
rt_acr0 = value;
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -117,18 +120,18 @@ inline uint32_t set_acr0(uint32_t value)
|
||||
*/
|
||||
inline uint32_t set_acr1(uint32_t value)
|
||||
{
|
||||
extern uint32_t rt_acr1;
|
||||
uint32_t ret = rt_acr1;
|
||||
extern uint32_t rt_acr1;
|
||||
uint32_t ret = rt_acr1;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"movec %[value],ACR1\n\t"
|
||||
: /* not output */
|
||||
: [value] "r" (value)
|
||||
:
|
||||
);
|
||||
rt_acr1 = value;
|
||||
__asm__ __volatile__(
|
||||
"movec %[value],ACR1\n\t"
|
||||
: /* not output */
|
||||
: [value] "r" (value)
|
||||
: "memory"
|
||||
);
|
||||
rt_acr1 = value;
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -138,18 +141,18 @@ inline uint32_t set_acr1(uint32_t value)
|
||||
*/
|
||||
inline uint32_t set_acr2(uint32_t value)
|
||||
{
|
||||
extern uint32_t rt_acr2;
|
||||
uint32_t ret = rt_acr2;
|
||||
extern uint32_t rt_acr2;
|
||||
uint32_t ret = rt_acr2;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"movec %[value],ACR2\n\t"
|
||||
: /* not output */
|
||||
: [value] "r" (value)
|
||||
:
|
||||
);
|
||||
rt_acr2 = value;
|
||||
__asm__ __volatile__(
|
||||
"movec %[value],ACR2\n\t"
|
||||
: /* not output */
|
||||
: [value] "r" (value)
|
||||
: "memory"
|
||||
);
|
||||
rt_acr2 = value;
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -158,35 +161,247 @@ inline uint32_t set_acr2(uint32_t value)
|
||||
*/
|
||||
inline uint32_t set_acr3(uint32_t value)
|
||||
{
|
||||
extern uint32_t rt_acr3;
|
||||
uint32_t ret = rt_acr3;
|
||||
extern uint32_t rt_acr3;
|
||||
uint32_t ret = rt_acr3;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"movec %[value],ACR3\n\t"
|
||||
: /* not output */
|
||||
: [value] "r" (value)
|
||||
:
|
||||
);
|
||||
rt_acr3 = value;
|
||||
__asm__ __volatile__(
|
||||
"movec %[value],ACR3\n\t"
|
||||
: /* not output */
|
||||
: [value] "r" (value)
|
||||
: "memory"
|
||||
);
|
||||
rt_acr3 = value;
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline uint32_t set_mmubar(uint32_t value)
|
||||
{
|
||||
extern uint32_t rt_mmubar;
|
||||
uint32_t ret = rt_mmubar;
|
||||
extern uint32_t rt_mmubar;
|
||||
uint32_t ret = rt_mmubar;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"movec %[value],MMUBAR\n\t"
|
||||
: /* no output */
|
||||
: [value] "r" (value)
|
||||
: /* no clobber */
|
||||
);
|
||||
rt_mmubar = value;
|
||||
NOP();
|
||||
__asm__ __volatile__(
|
||||
"movec %[value],MMUBAR\n\t"
|
||||
: /* no output */
|
||||
: [value] "r" (value)
|
||||
: "memory"
|
||||
);
|
||||
rt_mmubar = value;
|
||||
NOP();
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* translation table for virtual address ranges. Holds the physical_offset (which must be added to a virtual
|
||||
* address to get its physical counterpart) for memory ranges.
|
||||
*/
|
||||
struct virt_to_phys
|
||||
{
|
||||
uint32_t start_address;
|
||||
uint32_t length;
|
||||
uint32_t physical_offset;
|
||||
};
|
||||
|
||||
static struct virt_to_phys translation[] =
|
||||
{
|
||||
/* virtual , length , offset */
|
||||
{ 0x00000000, 0x00e00000, 0x60000000 }, /* map first 14 MByte to first 14 Mb of video ram */
|
||||
{ 0x00e00000, 0x00100000, 0x00000000 }, /* map TOS to SDRAM */
|
||||
{ 0x00f00000, 0x00100000, 0xff000000 }, /* map Falcon I/O area to FPGA */
|
||||
{ 0x01000000, 0x1f000000, 0x00000000 }, /* map rest of ram virt = phys */
|
||||
};
|
||||
static int num_translations = sizeof(translation) / sizeof(struct virt_to_phys);
|
||||
|
||||
static inline uint32_t lookup_phys(uint32_t virt)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_translations; i++)
|
||||
{
|
||||
if (virt >= translation[i].start_address && virt < translation[i].start_address + translation[i].length)
|
||||
{
|
||||
return virt + translation[i].physical_offset;
|
||||
}
|
||||
}
|
||||
err("virtual address 0x%lx not found in translation table!\r\n", virt);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct page_descriptor
|
||||
{
|
||||
uint8_t cache_mode : 2;
|
||||
uint8_t supervisor_protect : 1;
|
||||
uint8_t read : 1;
|
||||
uint8_t write : 1;
|
||||
uint8_t execute : 1;
|
||||
uint8_t global : 1;
|
||||
uint8_t locked : 1;
|
||||
};
|
||||
|
||||
static struct page_descriptor pages[65536]; /* 512 Mb RAM */
|
||||
|
||||
/*
|
||||
* map a page of memory using virt addresses with the Coldfire MMU.
|
||||
*
|
||||
* Theory of operation: the Coldfire MMU in the Firebee has 64 TLB entries, 32 for data (DTLB), 32 for
|
||||
* instructions (ITLB). Mappings can either be done locked (normal MMU TLB misses will not consider them
|
||||
* for replacement) or unlocked (mappings will reallocate using a LRU scheme when the MMU runs out of
|
||||
* TLB entries). For proper operation, the MMU needs at least two ITLBs and/or four free/allocatable DTLBs
|
||||
* per instruction as a minimum, more for performance. Thus locked pages (that can't be touched by the
|
||||
* LRU algorithm) should be used sparsingly.
|
||||
*
|
||||
*
|
||||
*/
|
||||
int mmu_map_8k_page(uint32_t virt, uint8_t asid)
|
||||
{
|
||||
const uint32_t size_mask = 0xffffe000; /* 8k pagesize */
|
||||
int page_index = (virt & size_mask) / DEFAULT_PAGE_SIZE; /* index into page_descriptor array */
|
||||
struct page_descriptor *page = &pages[page_index]; /* attributes of page to map */
|
||||
|
||||
uint32_t phys = lookup_phys(virt); /* virtual to physical translation of page */
|
||||
|
||||
if (phys == -1)
|
||||
return 0;
|
||||
|
||||
#ifdef DBG_MMU
|
||||
register int sp asm("sp");
|
||||
dbg("page_descriptor: 0x%02x, ssp = 0x%08x\r\n", * (uint8_t *) page, sp);
|
||||
#endif /* DBG_MMU */
|
||||
/*
|
||||
* add page to TLB
|
||||
*/
|
||||
MCF_MMU_MMUTR = (virt & 0xfffffc00) | /* virtual address */
|
||||
MCF_MMU_MMUTR_ID(asid) | /* address space id (ASID) */
|
||||
(page->global ? MCF_MMU_MMUTR_SG : 0) | /* shared global */
|
||||
MCF_MMU_MMUTR_V; /* valid */
|
||||
|
||||
MCF_MMU_MMUDR = (phys & 0xfffffc00) | /* physical address */
|
||||
MCF_MMU_MMUDR_SZ(MMU_PAGE_SIZE_8K) | /* page size */
|
||||
MCF_MMU_MMUDR_CM(page->cache_mode) | /* cache mode */
|
||||
(page->supervisor_protect ? MCF_MMU_MMUDR_SP : 0) | /* supervisor protect */
|
||||
(page->read ? MCF_MMU_MMUDR_R : 0) | /* read access enable */
|
||||
(page->write ? MCF_MMU_MMUDR_W : 0) | /* write access enable */
|
||||
(page->execute ? MCF_MMU_MMUDR_X : 0) | /* execute access enable */
|
||||
(page->locked ? MCF_MMU_MMUDR_LK : 0);
|
||||
|
||||
MCF_MMU_MMUOR = MCF_MMU_MMUOR_ITLB | /* instruction */
|
||||
MCF_MMU_MMUOR_ACC | /* access TLB */
|
||||
MCF_MMU_MMUOR_UAA; /* update allocation address field */
|
||||
dbg("ITLB: MCF_MMU_MMUOR = %08x\r\n", MCF_MMU_MMUOR);
|
||||
|
||||
MCF_MMU_MMUOR = MCF_MMU_MMUOR_ACC | /* access TLB, data */
|
||||
MCF_MMU_MMUOR_UAA; /* update allocation address field */
|
||||
|
||||
dbg("mapped virt=0x%08x to phys=0x%08x\r\n", virt & size_mask, phys & size_mask);
|
||||
|
||||
dbg("DTLB: MCF_MMU_MMUOR = %08x\r\n", MCF_MMU_MMUOR);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mmu_map_8k_instruction_page(uint32_t virt, uint8_t asid)
|
||||
{
|
||||
const uint32_t size_mask = ~ (DEFAULT_PAGE_SIZE - 1); /* 8k pagesize */
|
||||
int page_index = (virt & size_mask) / DEFAULT_PAGE_SIZE; /* index into page_descriptor array */
|
||||
struct page_descriptor *page = &pages[page_index]; /* attributes of page to map */
|
||||
int ipl;
|
||||
uint32_t phys = lookup_phys(virt); /* virtual to physical translation of page */
|
||||
|
||||
if (phys == -1)
|
||||
return 0;
|
||||
|
||||
#ifdef DBG_MMU
|
||||
register int sp asm("sp");
|
||||
dbg("page_descriptor: 0x%02x, ssp = 0x%08x\r\n", * (uint8_t *) page, sp);
|
||||
#endif /* DBG_MMU */
|
||||
|
||||
/*
|
||||
* add page to TLB
|
||||
*/
|
||||
|
||||
ipl = set_ipl(7); /* do not disturb */
|
||||
|
||||
MCF_MMU_MMUAR = (virt & size_mask);
|
||||
|
||||
MCF_MMU_MMUTR = (virt & size_mask) | /* virtual address */
|
||||
MCF_MMU_MMUTR_ID(asid) | /* address space id (ASID) */
|
||||
(page->global ? MCF_MMU_MMUTR_SG : 0) | /* shared global */
|
||||
MCF_MMU_MMUTR_V; /* valid */
|
||||
|
||||
__asm__ __volatile("" : : : "memory"); /* MMU commands must be exactly in sequence */
|
||||
|
||||
MCF_MMU_MMUDR = (phys & size_mask) | /* physical address */
|
||||
MCF_MMU_MMUDR_SZ(MMU_PAGE_SIZE_8K) | /* page size */
|
||||
MCF_MMU_MMUDR_CM(page->cache_mode) | /* cache mode */
|
||||
(page->supervisor_protect ? MCF_MMU_MMUDR_SP : 0) | /* supervisor protect */
|
||||
(page->read ? MCF_MMU_MMUDR_R : 0) | /* read access enable */
|
||||
(page->write ? MCF_MMU_MMUDR_W : 0) | /* write access enable */
|
||||
(page->execute ? MCF_MMU_MMUDR_X : 0) | /* execute access enable */
|
||||
(page->locked ? MCF_MMU_MMUDR_LK : 0);
|
||||
|
||||
__asm__ __volatile("" : : : "memory"); /* MMU commands must be exactly in sequence */
|
||||
|
||||
MCF_MMU_MMUOR = MCF_MMU_MMUOR_ITLB | /* instruction */
|
||||
MCF_MMU_MMUOR_ACC | /* access TLB */
|
||||
MCF_MMU_MMUOR_UAA; /* update allocation address field */
|
||||
|
||||
__asm__ __volatile("" : : : "memory"); /* MMU commands must be exactly in sequence */
|
||||
|
||||
set_ipl(ipl);
|
||||
|
||||
dbg("mapped virt=0x%08x to phys=0x%08x\r\n", virt & size_mask, phys & size_mask);
|
||||
|
||||
dbg("ITLB: MCF_MMU_MMUOR = %08x\r\n", MCF_MMU_MMUOR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mmu_map_8k_data_page(uint32_t virt, uint8_t asid)
|
||||
{
|
||||
uint16_t ipl;
|
||||
const uint32_t size_mask = ~ (DEFAULT_PAGE_SIZE - 1); /* 8k pagesize */
|
||||
int page_index = (virt & size_mask) / DEFAULT_PAGE_SIZE; /* index into page_descriptor array */
|
||||
struct page_descriptor *page = &pages[page_index]; /* attributes of page to map */
|
||||
|
||||
uint32_t phys = lookup_phys(virt); /* virtual to physical translation of page */
|
||||
|
||||
if (phys == -1)
|
||||
return 0;
|
||||
|
||||
#ifdef DBG_MMU
|
||||
register int sp asm("sp");
|
||||
dbg("page_descriptor: 0x%02x, ssp = 0x%08x\r\n", * (uint8_t *) page, sp);
|
||||
#endif /* DBG_MMU */
|
||||
|
||||
/*
|
||||
* add page to TLB
|
||||
*/
|
||||
|
||||
ipl = set_ipl(7); /* do not disturb */
|
||||
|
||||
MCF_MMU_MMUTR = (virt & size_mask) | /* virtual address */
|
||||
MCF_MMU_MMUTR_ID(asid) | /* address space id (ASID) */
|
||||
(page->global ? MCF_MMU_MMUTR_SG : 0) | /* shared global */
|
||||
MCF_MMU_MMUTR_V; /* valid */
|
||||
|
||||
MCF_MMU_MMUDR = (phys & size_mask) | /* physical address */
|
||||
MCF_MMU_MMUDR_SZ(MMU_PAGE_SIZE_8K) | /* page size */
|
||||
MCF_MMU_MMUDR_CM(page->cache_mode) | /* cache mode */
|
||||
(page->supervisor_protect ? MCF_MMU_MMUDR_SP : 0) | /* supervisor protect */
|
||||
(page->read ? MCF_MMU_MMUDR_R : 0) | /* read access enable */
|
||||
(page->write ? MCF_MMU_MMUDR_W : 0) | /* write access enable */
|
||||
(page->execute ? MCF_MMU_MMUDR_X : 0) | /* execute access enable */
|
||||
(page->locked ? MCF_MMU_MMUDR_LK : 0);
|
||||
|
||||
MCF_MMU_MMUOR = MCF_MMU_MMUOR_ACC | /* access TLB, data */
|
||||
MCF_MMU_MMUOR_UAA; /* update allocation address field */
|
||||
|
||||
set_ipl(ipl);
|
||||
dbg("mapped virt=0x%08x to phys=0x%08x\r\n", virt & size_mask, phys & size_mask);
|
||||
|
||||
dbg("DTLB: MCF_MMU_MMUOR = %08x\r\n", MCF_MMU_MMUOR);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -201,233 +416,303 @@ inline uint32_t set_mmubar(uint32_t value)
|
||||
*
|
||||
*
|
||||
*/
|
||||
int mmu_map_page(uint32_t virt, uint32_t phys, enum mmu_page_size sz, const struct mmu_map_flags *flags)
|
||||
int mmu_map_page(uint32_t virt, uint32_t phys, enum mmu_page_size sz, uint8_t page_id, const struct page_descriptor *flags)
|
||||
{
|
||||
int size_mask;
|
||||
int size_mask;
|
||||
int ipl;
|
||||
|
||||
switch (sz)
|
||||
{
|
||||
case MMU_PAGE_SIZE_1M:
|
||||
size_mask = 0xfff00000;
|
||||
break;
|
||||
switch (sz)
|
||||
{
|
||||
case MMU_PAGE_SIZE_1M:
|
||||
size_mask = ~ (0x00010000 - 1);
|
||||
break;
|
||||
|
||||
case MMU_PAGE_SIZE_8K:
|
||||
size_mask = 0xffffe000;
|
||||
break;
|
||||
case MMU_PAGE_SIZE_8K:
|
||||
size_mask = ~ (0x2000 - 1);
|
||||
break;
|
||||
|
||||
case MMU_PAGE_SIZE_4K:
|
||||
size_mask = 0xfffff000;
|
||||
break;
|
||||
case MMU_PAGE_SIZE_4K:
|
||||
size_mask = ~ (0x1000 - 1);
|
||||
break;
|
||||
|
||||
case MMU_PAGE_SIZE_1K:
|
||||
size_mask = 0xfffff800;
|
||||
break;
|
||||
case MMU_PAGE_SIZE_1K:
|
||||
size_mask = ~ (0x400 - 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
dbg("illegal map size %d\r\n", sz);
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
err("illegal map size %d\r\n", sz);
|
||||
}
|
||||
|
||||
/*
|
||||
* add page to TLB
|
||||
*/
|
||||
MCF_MMU_MMUTR = ((int) virt & size_mask) | /* virtual address */
|
||||
MCF_MMU_MMUTR_ID(flags->page_id) | /* address space id (ASID) */
|
||||
MCF_MMU_MMUTR_SG | /* shared global */
|
||||
MCF_MMU_MMUTR_V; /* valid */
|
||||
NOP();
|
||||
/*
|
||||
* add page to TLB
|
||||
*/
|
||||
|
||||
MCF_MMU_MMUDR = ((int) phys & size_mask) | /* physical address */
|
||||
MCF_MMU_MMUDR_SZ(sz) | /* page size */
|
||||
MCF_MMU_MMUDR_CM(flags->cache_mode) |
|
||||
(flags->access & ACCESS_READ ? MCF_MMU_MMUDR_R : 0) | /* read access enable */
|
||||
(flags->access & ACCESS_WRITE ? MCF_MMU_MMUDR_W : 0) | /* write access enable */
|
||||
(flags->access & ACCESS_EXECUTE ? MCF_MMU_MMUDR_X : 0) | /* execute access enable */
|
||||
(flags->locked ? MCF_MMU_MMUDR_LK : 0);
|
||||
NOP();
|
||||
ipl = set_ipl(7);
|
||||
|
||||
MCF_MMU_MMUOR = MCF_MMU_MMUOR_ACC | /* access TLB, data */
|
||||
MCF_MMU_MMUOR_UAA; /* update allocation address field */
|
||||
NOP();
|
||||
MCF_MMU_MMUTR = ((uint32_t) virt & size_mask) | /* virtual address */
|
||||
MCF_MMU_MMUTR_ID(page_id) | /* address space id (ASID) */
|
||||
(flags->global ? MCF_MMU_MMUTR_SG : 0) | /* shared global */
|
||||
MCF_MMU_MMUTR_V; /* valid */
|
||||
NOP();
|
||||
|
||||
MCF_MMU_MMUOR = MCF_MMU_MMUOR_ITLB | /* instruction */
|
||||
MCF_MMU_MMUOR_ACC | /* access TLB */
|
||||
MCF_MMU_MMUOR_UAA; /* update allocation address field */
|
||||
dbg("mapped virt=0x%08x to phys=0x%08x\r\n", virt, phys);
|
||||
MCF_MMU_MMUDR = ((uint32_t) phys & size_mask) | /* physical address */
|
||||
MCF_MMU_MMUDR_SZ(sz) | /* page size */
|
||||
MCF_MMU_MMUDR_CM(flags->cache_mode) |
|
||||
(flags->read ? MCF_MMU_MMUDR_R : 0) | /* read access enable */
|
||||
(flags->write ? MCF_MMU_MMUDR_W : 0) | /* write access enable */
|
||||
(flags->execute ? MCF_MMU_MMUDR_X : 0) | /* execute access enable */
|
||||
(flags->locked ? MCF_MMU_MMUDR_LK : 0);
|
||||
NOP();
|
||||
|
||||
return 1;
|
||||
MCF_MMU_MMUOR = MCF_MMU_MMUOR_ACC | /* access TLB, data */
|
||||
MCF_MMU_MMUOR_UAA; /* update allocation address field */
|
||||
NOP();
|
||||
|
||||
MCF_MMU_MMUOR = MCF_MMU_MMUOR_ITLB | /* instruction */
|
||||
MCF_MMU_MMUOR_ACC | /* access TLB */
|
||||
MCF_MMU_MMUOR_UAA; /* update allocation address field */
|
||||
|
||||
set_ipl(ipl);
|
||||
|
||||
dbg("mapped virt=0x%08x to phys=0x%08x\r\n", virt, phys);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void mmu_init(void)
|
||||
{
|
||||
struct mmu_map_flags flags;
|
||||
extern uint8_t _MMUBAR[];
|
||||
uint32_t MMUBAR = (uint32_t) &_MMUBAR[0];
|
||||
struct page_descriptor flags;
|
||||
int i;
|
||||
|
||||
extern uint8_t _MMUBAR[];
|
||||
uint32_t MMUBAR = (uint32_t) &_MMUBAR[0];
|
||||
extern uint8_t _TOS[];
|
||||
uint32_t TOS = (uint32_t) &_TOS[0];
|
||||
/*
|
||||
* clear all MMU TLB entries first
|
||||
*/
|
||||
MCF_MMU_MMUOR = MCF_MMU_MMUOR_CA; /* clears _all_ TLBs (including locked ones) */
|
||||
NOP();
|
||||
|
||||
set_asid(0); /* do not use address extension (ASID provides virtual 48 bit addresses */
|
||||
/*
|
||||
* prelaminary initialization of page descriptor 0 (root) table
|
||||
*/
|
||||
for (i = 0; i < sizeof(pages) / sizeof(struct page_descriptor); i++)
|
||||
{
|
||||
uint32_t addr = i * DEFAULT_PAGE_SIZE;
|
||||
|
||||
/* set data access attributes in ACR0 and ACR1 */
|
||||
set_acr0(ACR_W(0) | /* read and write accesses permitted */
|
||||
ACR_SP(0) | /* supervisor and user mode access permitted */
|
||||
ACR_CM(ACR_CM_CACHE_INH_PRECISE) | /* cache inhibit, precise */
|
||||
ACR_AMM(0) | /* control region > 16 MB */
|
||||
ACR_S(ACR_S_ALL) | /* match addresses in user and supervisor mode */
|
||||
ACR_E(1) | /* enable ACR */
|
||||
if (addr >= 0x00f00000 && addr < 0x00ffffff)
|
||||
{
|
||||
pages[i].cache_mode = CACHE_NOCACHE_PRECISE;
|
||||
pages[i].execute = 0;
|
||||
pages[i].read = 1;
|
||||
pages[i].write = 1;
|
||||
pages[i].execute = 0;
|
||||
pages[i].global = 1;
|
||||
pages[i].supervisor_protect = 1;
|
||||
}
|
||||
else if (addr >= 0x0 && addr < 0x00e00000) /* ST-RAM, potential video memory */
|
||||
{
|
||||
pages[i].cache_mode = CACHE_WRITETHROUGH;
|
||||
pages[i].execute = 1;
|
||||
pages[i].supervisor_protect = 0;
|
||||
pages[i].read = 1;
|
||||
pages[i].write = 1;
|
||||
pages[i].execute = 1;
|
||||
pages[i].global = 1;
|
||||
}
|
||||
else if (addr >= 0x00e00000 && addr < 0x00f00000) /* EmuTOS */
|
||||
{
|
||||
pages[i].cache_mode = CACHE_COPYBACK;
|
||||
pages[i].execute = 1;
|
||||
pages[i].supervisor_protect = 1;
|
||||
pages[i].read = 1;
|
||||
pages[i].write = 0;
|
||||
pages[i].execute = 1;
|
||||
pages[i].global = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
pages[i].cache_mode = CACHE_COPYBACK;
|
||||
pages[i].execute = 1;
|
||||
pages[i].read = 1;
|
||||
pages[i].write = 1;
|
||||
pages[i].supervisor_protect = 0;
|
||||
pages[i].global = 1;
|
||||
}
|
||||
pages[i].locked = 0; /* not locked */
|
||||
pages[0].supervisor_protect = 0; /* protect system vectors */
|
||||
}
|
||||
|
||||
set_asid(0); /* do not use address extension (ASID provides virtual 48 bit addresses) yet */
|
||||
|
||||
|
||||
/* set data access attributes in ACR0 and ACR1 */
|
||||
set_acr0(ACR_W(0) | /* read and write accesses permitted */
|
||||
ACR_SP(0) | /* supervisor and user mode access permitted */
|
||||
ACR_CM(ACR_CM_CACHE_INH_PRECISE) | /* cache inhibit, precise (i/o area!) */
|
||||
ACR_AMM(0) | /* control region > 16 MB */
|
||||
ACR_S(ACR_S_ALL) | /* match addresses in user and supervisor mode */
|
||||
ACR_E(1) | /* enable ACR */
|
||||
#if defined(MACHINE_FIREBEE)
|
||||
ACR_ADMSK(0x7f) | /* cover 2GB area from 0x80000000 to 0xffffffff */
|
||||
ACR_BA(0x80000000)); /* (equals area from 3 to 4 GB */
|
||||
ACR_ADMSK(0x7f) | /* cover 2GB area from 0x80000000 to 0xffffffff */
|
||||
ACR_BA(0x80000000)); /* (equals area from 3 to 4 GB */
|
||||
#elif defined(MACHINE_M5484LITE)
|
||||
ACR_ADMSK(0x7f) | /* cover 2 GB area from 0x80000000 to 0xffffffff */
|
||||
ACR_BA(0x80000000));
|
||||
ACR_ADMSK(0x7f) | /* cover 2 GB area from 0x80000000 to 0xffffffff */
|
||||
ACR_BA(0x80000000));
|
||||
#elif defined(MACHINE_M54455)
|
||||
ACR_ADMSK(0x7f) |
|
||||
ACR_BA(0x80000000)); /* FIXME: not determined yet */
|
||||
ACR_ADMSK(0x7f) |
|
||||
ACR_BA(0x80000000)); /* FIXME: not determined yet for this machine */
|
||||
#else
|
||||
#error unknown machine!
|
||||
#endif /* MACHINE_FIREBEE */
|
||||
|
||||
// set_acr1(0x601fc000);
|
||||
set_acr1(ACR_W(0) |
|
||||
ACR_SP(0) |
|
||||
ACR_CM(0) |
|
||||
|
||||
|
||||
// set_acr1(0x601fc000);
|
||||
set_acr1(ACR_W(0) |
|
||||
ACR_SP(0) |
|
||||
ACR_CM(0) |
|
||||
#if defined(MACHINE_FIREBEE)
|
||||
ACR_CM(ACR_CM_CACHEABLE_WT) | /* video RAM on the Firebee */
|
||||
ACR_CM(ACR_CM_CACHE_INH_PRECISE) | /* ST RAM on the Firebee */
|
||||
#elif defined(MACHINE_M5484LITE)
|
||||
ACR_CM(ACR_CM_CACHE_INH_PRECISE) | /* Compact Flash on the M548xLITE */
|
||||
ACR_CM(ACR_CM_CACHE_INH_PRECISE) | /* Compact Flash on the M548xLITE */
|
||||
#elif defined(MACHINE_M54455)
|
||||
ACR_CM(ACR_CM_CACHE_INH_PRECISE) | /* FIXME: not determined yet */
|
||||
ACR_CM(ACR_CM_CACHE_INH_PRECISE) | /* FIXME: not determined yet for this machine */
|
||||
#else
|
||||
#error unknown machine!
|
||||
#endif /* MACHINE_FIREBEE */
|
||||
ACR_AMM(0) |
|
||||
ACR_S(ACR_S_ALL) |
|
||||
ACR_E(1) |
|
||||
ACR_ADMSK(0x1f) |
|
||||
ACR_BA(0x60000000));
|
||||
ACR_AMM(0) |
|
||||
ACR_S(ACR_S_ALL) |
|
||||
ACR_E(1) |
|
||||
ACR_ADMSK(0x7f) |
|
||||
ACR_BA(0x00100000));
|
||||
|
||||
/* set instruction access attributes in ACR2 and ACR3 */
|
||||
#ifdef _NOT_USED_
|
||||
/* set instruction access attributes in ACR2 and ACR3 */
|
||||
|
||||
//set_acr2(0xe007c400);
|
||||
set_acr2(ACR_W(0) |
|
||||
ACR_SP(0) |
|
||||
ACR_CM(0) |
|
||||
ACR_CM(ACR_CM_CACHEABLE_WT) |
|
||||
ACR_AMM(1) |
|
||||
ACR_S(ACR_S_ALL) |
|
||||
ACR_E(1) |
|
||||
ACR_ADMSK(0x7) |
|
||||
ACR_BA(0xe0000000));
|
||||
//set_acr2(0xe007c400); /* flash area */
|
||||
set_acr2(ACR_W(0) |
|
||||
ACR_SP(0) |
|
||||
ACR_CM(0) |
|
||||
ACR_CM(ACR_CM_CACHE_INH_PRECISE) |
|
||||
ACR_AMM(1) |
|
||||
ACR_S(ACR_S_ALL) |
|
||||
ACR_E(1) |
|
||||
ACR_ADMSK(0x7) |
|
||||
ACR_BA(0xe0000000));
|
||||
#endif /* _NOT_USED_ */
|
||||
|
||||
/* disable ACR3 */
|
||||
set_acr3(0x0);
|
||||
set_acr1(0x0);
|
||||
set_acr2(0x0);
|
||||
/* disable ACR3 */
|
||||
set_acr3(0x0);
|
||||
|
||||
set_mmubar(MMUBAR + 1); /* set and enable MMUBAR */
|
||||
set_mmubar(MMUBAR + 1); /* set and enable MMUBAR */
|
||||
|
||||
/* clear all MMU TLB entries */
|
||||
MCF_MMU_MMUOR = MCF_MMU_MMUOR_CA;
|
||||
/* clear all MMU TLB entries */
|
||||
MCF_MMU_MMUOR = MCF_MMU_MMUOR_CA;
|
||||
|
||||
/* create locked TLB entries */
|
||||
/* create locked TLB entries */
|
||||
|
||||
flags.cache_mode = CACHE_COPYBACK;
|
||||
flags.protection = SV_USER;
|
||||
flags.page_id = 0;
|
||||
flags.access = ACCESS_READ | ACCESS_WRITE | ACCESS_EXECUTE;
|
||||
flags.locked = true;
|
||||
/*
|
||||
* Map (locked) the second last MB of physical SDRAM (this is where BaS .data and .bss reside) to the same
|
||||
* virtual address. This is also used (completely) when BaS is in RAM
|
||||
*/
|
||||
flags.cache_mode = CACHE_NOCACHE_PRECISE;
|
||||
flags.read = 1;
|
||||
flags.write = 1;
|
||||
flags.execute = 1;
|
||||
flags.supervisor_protect = 1; /* supervisor access only */
|
||||
flags.locked = 1;
|
||||
mmu_map_page(SDRAM_START + SDRAM_SIZE - 0x00200000, SDRAM_START + SDRAM_SIZE - 0x00200000, 0, MMU_PAGE_SIZE_1M, &flags);
|
||||
|
||||
/* 0x0000_0000 - 0x000F_FFFF (first MB of physical memory) locked virt = phys */
|
||||
mmu_map_page(0x0, 0x0, MMU_PAGE_SIZE_1M, &flags);
|
||||
/*
|
||||
* map EmuTOS (locked for now)
|
||||
*/
|
||||
flags.read = 1;
|
||||
flags.write = 1;
|
||||
flags.execute = 1;
|
||||
flags.locked = 1;
|
||||
//mmu_map_page(0xe00000, 0xe00000, MMU_PAGE_SIZE_1M, 0, &flags);
|
||||
|
||||
#if defined(MACHINE_FIREBEE)
|
||||
/*
|
||||
* 0x00d0'0000 - 0x00df'ffff (last megabyte of ST RAM = Falcon video memory) locked ID = 6
|
||||
* mapped to physical address 0x60d0'0000 (FPGA video memory)
|
||||
* video RAM: read write execute normal write true
|
||||
*/
|
||||
flags.cache_mode = CACHE_WRITETHROUGH;
|
||||
flags.protection = SV_USER;
|
||||
flags.page_id = SCA_PAGE_ID;
|
||||
flags.access = ACCESS_READ | ACCESS_WRITE | ACCESS_EXECUTE;
|
||||
flags.locked = true;
|
||||
mmu_map_page(0x00d00000, 0x60d00000, MMU_PAGE_SIZE_1M, &flags);
|
||||
|
||||
video_tlb = 0x2000; /* set page as video page */
|
||||
video_sbt = 0x0; /* clear time */
|
||||
#endif /* MACHINE_FIREBEE */
|
||||
|
||||
/*
|
||||
* Make the TOS (in SDRAM) read-only
|
||||
* This maps virtual 0x00e0'0000 - 0x00ef'ffff to the same virtual address
|
||||
*/
|
||||
flags.cache_mode = CACHE_COPYBACK;
|
||||
flags.page_id = 0;
|
||||
flags.access = ACCESS_READ | ACCESS_EXECUTE;
|
||||
mmu_map_page(TOS, TOS, MMU_PAGE_SIZE_1M, &flags);
|
||||
|
||||
#if defined(MACHINE_FIREBEE)
|
||||
/*
|
||||
* Map FireBee I/O area (0xfff0'0000 - 0xffff'ffff physical) to the Falcon-compatible I/O
|
||||
* area (0x00f0'0000 - 0x00ff'ffff virtual) for the FireBee
|
||||
*/
|
||||
flags.cache_mode = CACHE_NOCACHE_PRECISE;
|
||||
flags.access = ACCESS_WRITE | ACCESS_READ;
|
||||
mmu_map_page(0x00f00000, 0xfff00000, MMU_PAGE_SIZE_1M, &flags);
|
||||
#endif /* MACHINE_FIREBEE */
|
||||
|
||||
/*
|
||||
* Map (locked) the second last MB of physical SDRAM (this is where BaS .data and .bss reside) to the same
|
||||
* virtual address. This is also used (completely) when BaS is in RAM
|
||||
*/
|
||||
flags.cache_mode = CACHE_COPYBACK;
|
||||
flags.access = ACCESS_READ | ACCESS_WRITE | ACCESS_EXECUTE;
|
||||
mmu_map_page(SDRAM_START + SDRAM_SIZE - 0X00200000, SDRAM_START + SDRAM_SIZE - 0X00200000, MMU_PAGE_SIZE_1M, &flags);
|
||||
|
||||
/*
|
||||
* Map (locked) the very last MB of physical SDRAM (this is where the driver buffers reside) to the same
|
||||
* virtual address. Used uncached for drivers.
|
||||
*/
|
||||
flags.cache_mode = CACHE_NOCACHE_PRECISE;
|
||||
flags.access = ACCESS_READ | ACCESS_WRITE;
|
||||
flags.protection = SV_PROTECT;
|
||||
mmu_map_page(SDRAM_START + SDRAM_SIZE - 0x00100000, SDRAM_START + SDRAM_SIZE - 0x00100000, MMU_PAGE_SIZE_1M, &flags);
|
||||
/*
|
||||
* Map (locked) the very last MB of physical SDRAM (this is where the driver buffers reside) to the same
|
||||
* virtual address. Used uncached for drivers.
|
||||
*/
|
||||
flags.cache_mode = CACHE_NOCACHE_PRECISE;
|
||||
flags.read = 1;
|
||||
flags.write = 1;
|
||||
flags.execute = 0;
|
||||
flags.supervisor_protect = 1;
|
||||
flags.locked = 1;
|
||||
mmu_map_page(SDRAM_START + SDRAM_SIZE - 0x00100000, SDRAM_START + SDRAM_SIZE - 0x00100000, 0, MMU_PAGE_SIZE_1M, &flags);
|
||||
}
|
||||
|
||||
static struct mmu_map_flags flags =
|
||||
/*
|
||||
* enable the MMU. The Coldfire MMU can be used in two different modes
|
||||
* ... FIXME:
|
||||
*/
|
||||
void mmu_enable(void)
|
||||
{
|
||||
.cache_mode = CACHE_COPYBACK,
|
||||
.protection = SV_USER,
|
||||
.page_id = 0,
|
||||
.access = ACCESS_READ | ACCESS_WRITE | ACCESS_EXECUTE,
|
||||
.locked = false
|
||||
};
|
||||
MCF_MMU_MMUCR = MCF_MMU_MMUCR_EN; /* MMU on */
|
||||
NOP(); /* force pipeline sync */
|
||||
}
|
||||
|
||||
void mmutr_miss(uint32_t address, uint32_t pc, uint32_t format_status)
|
||||
#ifdef DBG_MMU
|
||||
void verify_mapping(uint32_t address)
|
||||
{
|
||||
dbg("MMU TLB MISS accessing 0x%08x\r\nFS = 0x%08x\r\nPC = 0x%08x\r\n", address, format_status, pc);
|
||||
// flush_and_invalidate_caches();
|
||||
/* retrieve mapped page from MMU and make sure everything is correct */
|
||||
int ds;
|
||||
|
||||
switch (address)
|
||||
{
|
||||
case keyctl:
|
||||
case keybd:
|
||||
/* do something to emulate the IKBD access */
|
||||
dbg("IKBD access\r\n");
|
||||
break;
|
||||
ds = * (int *) address;
|
||||
dbg("found 0x%08x at address\r\n", ds);
|
||||
}
|
||||
#endif /* DBG_MMU */
|
||||
|
||||
case midictl:
|
||||
case midi:
|
||||
/* do something to emulate MIDI access */
|
||||
dbg("MIDI ACIA access\r\n");
|
||||
break;
|
||||
uint32_t mmutr_miss(uint32_t mmu_sr, uint32_t fault_address, uint32_t pc,
|
||||
uint32_t format_status)
|
||||
{
|
||||
uint32_t fault = format_status & 0x0c030000;
|
||||
|
||||
default:
|
||||
/* add missed page to TLB */
|
||||
mmu_map_page(address, address, MMU_PAGE_SIZE_1M, &flags);
|
||||
dbg("DTLB: MCF_MMU_MMUOR = %08x\r\n", MCF_MMU_MMUOR);
|
||||
dbg("ITLB: MCF_MMU_MMUOR = %08x\r\n\r\n", MCF_MMU_MMUOR);
|
||||
}
|
||||
switch (fault)
|
||||
{
|
||||
/* if we have a real TLB miss, map the offending page */
|
||||
|
||||
case 0x04010000: /* TLB miss on opword of instruction fetch */
|
||||
case 0x04020000: /* TLB miss on extension word of instruction fetch */
|
||||
dbg("MMU ITLB MISS accessing 0x%08x\r\n"
|
||||
"FS = 0x%08x\r\n"
|
||||
"MMUSR = 0x%08x\r\n"
|
||||
"PC = 0x%08x\r\n",
|
||||
fault_address, format_status, mmu_sr, pc);
|
||||
dbg("fault = 0x%08x\r\n", fault);
|
||||
mmu_map_8k_instruction_page(pc, 0);
|
||||
|
||||
/* due to prefetch, it makes sense to map the next adjacent page also for ITLBs */
|
||||
mmu_map_8k_instruction_page(pc + DEFAULT_PAGE_SIZE, 0);
|
||||
break;
|
||||
|
||||
case 0x08020000: /* TLB miss on data write */
|
||||
case 0x0c020000: /* TLB miss on data read or read-modify-write */
|
||||
dbg("MMU DTLB MISS accessing 0x%08x\r\n"
|
||||
"FS = 0x%08x\r\n"
|
||||
"MMUSR = 0x%08x\r\n"
|
||||
"PC = 0x%08x\r\n",
|
||||
fault_address, format_status, mmu_sr, pc);
|
||||
dbg("fault = 0x%08x\r\n", fault);
|
||||
mmu_map_8k_data_page(fault_address, 0);
|
||||
break;
|
||||
|
||||
/* else issue an bus error */
|
||||
default:
|
||||
dbg("bus error\r\n");
|
||||
return 1; /* signal bus error to caller */
|
||||
}
|
||||
|
||||
#ifdef DBG_MMU
|
||||
xprintf("\r\n");
|
||||
#endif /* DBG_MMU */
|
||||
|
||||
return 0; /* signal TLB miss handled to caller */
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -49,6 +49,8 @@ _rom_entry:
|
||||
/* set stack pointer to end of SRAM */
|
||||
lea __SUP_SP,a7
|
||||
move.l #0,(sp)
|
||||
subq.l #4,sp
|
||||
move.l #0,(sp)
|
||||
|
||||
/*
|
||||
* Initialize the processor caches.
|
||||
|
||||
@@ -61,148 +61,153 @@ static char snil[] = "(nil)";
|
||||
|
||||
void xputchar(int c)
|
||||
{
|
||||
__asm__ __volatile__
|
||||
(
|
||||
".extern printf_helper\n\t"
|
||||
"move.b %0,d0\n\t"
|
||||
"bsr printf_helper\n\t"
|
||||
/* output */:
|
||||
/* input */: "r" (c)
|
||||
/* clobber */: "d0","d2","a0","memory"
|
||||
);
|
||||
__asm__ __volatile__
|
||||
(
|
||||
" .extern __MBAR \n\t"
|
||||
" move.b %0,d0 \n\t"
|
||||
".wait_txready: \n\t"
|
||||
" move.w __MBAR + 0x8604,d2 \n\t" // PSCSCR0 status register
|
||||
" btst #10,d2 \n\t" // space left in TX fifo?
|
||||
" beq.s .wait_txready \n\t" // no, loop
|
||||
" lea __MBAR + 0x860C,a0 \n\t" // PSCSTB0 transmitter buffer register
|
||||
" move.b d0,(a0) \n\t" // send byte
|
||||
/* output */:
|
||||
/* input */: "r" (c)
|
||||
/* clobber */: "d0","d2","a0","memory"
|
||||
);
|
||||
}
|
||||
|
||||
static void doprnt(void (*addchar)(int), const char *sfmt, va_list ap)
|
||||
{
|
||||
char buf[128];
|
||||
char *bp;
|
||||
const char *f;
|
||||
float flt;
|
||||
long l;
|
||||
unsigned long u;
|
||||
int i;
|
||||
int fmt;
|
||||
unsigned char pad = ' ';
|
||||
int flush_left = 0;
|
||||
int f_width = 0;
|
||||
int prec = INF;
|
||||
int hash = 0;
|
||||
int do_long = 0;
|
||||
int sign = 0;
|
||||
int attributes = 0;
|
||||
char buf[128];
|
||||
char *bp;
|
||||
const char *f;
|
||||
float flt;
|
||||
long l;
|
||||
unsigned long u;
|
||||
int i;
|
||||
int fmt;
|
||||
unsigned char pad = ' ';
|
||||
int flush_left = 0;
|
||||
int f_width = 0;
|
||||
int prec = INF;
|
||||
int hash = 0;
|
||||
int do_long = 0;
|
||||
int sign = 0;
|
||||
int attributes = 0;
|
||||
|
||||
f = sfmt;
|
||||
for (; *f; f++)
|
||||
{
|
||||
if (*f != '%')
|
||||
{
|
||||
/* then just out the char */
|
||||
(*addchar)((int) (((unsigned char) *f) | attributes));
|
||||
}
|
||||
else
|
||||
{
|
||||
f++; /* skip the % */
|
||||
f = sfmt;
|
||||
for (; *f; f++)
|
||||
{
|
||||
if (*f != '%')
|
||||
{
|
||||
/* then just out the char */
|
||||
(*addchar)((int) (((unsigned char) *f) | attributes));
|
||||
}
|
||||
else
|
||||
{
|
||||
f++; /* skip the % */
|
||||
|
||||
if (*f == '-')
|
||||
{ /* minus: flush left */
|
||||
flush_left = 1;
|
||||
f++;
|
||||
}
|
||||
if (*f == '-')
|
||||
{ /* minus: flush left */
|
||||
flush_left = 1;
|
||||
f++;
|
||||
}
|
||||
|
||||
if (*f == '0' || *f == '.')
|
||||
{
|
||||
/* padding with 0 rather than blank */
|
||||
pad = '0';
|
||||
f++;
|
||||
}
|
||||
if (*f == '*')
|
||||
{
|
||||
/* field width */
|
||||
f_width = va_arg(ap, int);
|
||||
f++;
|
||||
}
|
||||
else if (isdigit((unsigned char)*f))
|
||||
{
|
||||
f_width = atoi(f);
|
||||
while (isdigit((unsigned char)*f))
|
||||
f++; /* skip the digits */
|
||||
}
|
||||
if (*f == '0' || *f == '.')
|
||||
{
|
||||
/* padding with 0 rather than blank */
|
||||
pad = '0';
|
||||
f++;
|
||||
}
|
||||
if (*f == '*')
|
||||
{
|
||||
/* field width */
|
||||
f_width = va_arg(ap, int);
|
||||
f++;
|
||||
}
|
||||
else if (isdigit((unsigned char)*f))
|
||||
{
|
||||
f_width = atoi(f);
|
||||
while (isdigit((unsigned char)*f))
|
||||
f++; /* skip the digits */
|
||||
}
|
||||
|
||||
if (*f == '.')
|
||||
{ /* precision */
|
||||
f++;
|
||||
if (*f == '*')
|
||||
{
|
||||
prec = va_arg(ap, int);
|
||||
f++;
|
||||
}
|
||||
else if (isdigit((unsigned char)*f))
|
||||
{
|
||||
prec = atoi(f);
|
||||
while (isdigit((unsigned char)*f))
|
||||
f++; /* skip the digits */
|
||||
}
|
||||
}
|
||||
if (*f == '.')
|
||||
{ /* precision */
|
||||
f++;
|
||||
if (*f == '*')
|
||||
{
|
||||
prec = va_arg(ap, int);
|
||||
f++;
|
||||
}
|
||||
else if (isdigit((unsigned char)*f))
|
||||
{
|
||||
prec = atoi(f);
|
||||
while (isdigit((unsigned char)*f))
|
||||
f++; /* skip the digits */
|
||||
}
|
||||
}
|
||||
|
||||
if (*f == '#')
|
||||
{ /* alternate form */
|
||||
hash = 1;
|
||||
f++;
|
||||
}
|
||||
if (*f == '#')
|
||||
{ /* alternate form */
|
||||
hash = 1;
|
||||
f++;
|
||||
}
|
||||
|
||||
if (*f == 'l')
|
||||
{ /* long format */
|
||||
do_long++;
|
||||
f++;
|
||||
if (*f == 'l')
|
||||
{
|
||||
do_long++;
|
||||
f++;
|
||||
}
|
||||
}
|
||||
if (*f == 'l')
|
||||
{ /* long format */
|
||||
do_long++;
|
||||
f++;
|
||||
if (*f == 'l')
|
||||
{
|
||||
do_long++;
|
||||
f++;
|
||||
}
|
||||
}
|
||||
|
||||
fmt = (unsigned char) *f;
|
||||
if (fmt != 'S' && fmt != 'Q' && isupper(fmt))
|
||||
{
|
||||
do_long = 1;
|
||||
fmt = tolower(fmt);
|
||||
}
|
||||
bp = buf;
|
||||
switch (fmt)
|
||||
{ /* do the format */
|
||||
case 'd':
|
||||
switch (do_long)
|
||||
{
|
||||
case 0:
|
||||
l = (long) (va_arg(ap, int));
|
||||
break;
|
||||
case 1:
|
||||
default:
|
||||
l = va_arg(ap, long);
|
||||
break;
|
||||
}
|
||||
fmt = (unsigned char) *f;
|
||||
if (fmt != 'S' && fmt != 'Q' && isupper(fmt))
|
||||
{
|
||||
do_long = 1;
|
||||
fmt = tolower(fmt);
|
||||
}
|
||||
bp = buf;
|
||||
switch (fmt)
|
||||
{ /* do the format */
|
||||
case 'd':
|
||||
switch (do_long)
|
||||
{
|
||||
case 0:
|
||||
l = (long) (va_arg(ap, int));
|
||||
break;
|
||||
case 1:
|
||||
default:
|
||||
l = va_arg(ap, long);
|
||||
break;
|
||||
}
|
||||
|
||||
if (l < 0)
|
||||
{
|
||||
sign = 1;
|
||||
l = -l;
|
||||
}
|
||||
do
|
||||
{
|
||||
*bp++ = (char) (l % 10) + '0';
|
||||
} while ((l /= 10) > 0);
|
||||
if (sign)
|
||||
*bp++ = '-';
|
||||
f_width = f_width - (int) (bp - buf);
|
||||
if (!flush_left)
|
||||
while (f_width-- > 0)
|
||||
(*addchar)((int) (pad | attributes));
|
||||
for (bp--; bp >= buf; bp--)
|
||||
(*addchar)((int) (((unsigned char) *bp) | attributes));
|
||||
if (flush_left)
|
||||
while (f_width-- > 0)
|
||||
(*addchar)((int) (' ' | attributes));
|
||||
break;
|
||||
if (l < 0)
|
||||
{
|
||||
sign = 1;
|
||||
l = -l;
|
||||
}
|
||||
do
|
||||
{
|
||||
*bp++ = (char) (l % 10) + '0';
|
||||
} while ((l /= 10) > 0);
|
||||
if (sign)
|
||||
*bp++ = '-';
|
||||
f_width = f_width - (int) (bp - buf);
|
||||
if (!flush_left)
|
||||
while (f_width-- > 0)
|
||||
(*addchar)((int) (pad | attributes));
|
||||
for (bp--; bp >= buf; bp--)
|
||||
(*addchar)((int) (((unsigned char) *bp) | attributes));
|
||||
if (flush_left)
|
||||
while (f_width-- > 0)
|
||||
(*addchar)((int) (' ' | attributes));
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
/* this is actually more than stupid, but does work for now */
|
||||
@@ -242,179 +247,179 @@ static void doprnt(void (*addchar)(int), const char *sfmt, va_list ap)
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
do_long = 1;
|
||||
hash = 1;
|
||||
fmt = 'x';
|
||||
/* no break */
|
||||
case 'o':
|
||||
case 'x':
|
||||
case 'u':
|
||||
switch (do_long)
|
||||
{
|
||||
case 0:
|
||||
u = (unsigned long) (va_arg(ap, unsigned int));
|
||||
break;
|
||||
case 1:
|
||||
default:
|
||||
u = va_arg(ap, unsigned long);
|
||||
break;
|
||||
}
|
||||
if (fmt == 'u')
|
||||
{ /* unsigned decimal */
|
||||
do
|
||||
{
|
||||
*bp++ = (char) (u % 10) + '0';
|
||||
} while ((u /= 10) > 0);
|
||||
}
|
||||
else if (fmt == 'o')
|
||||
{ /* octal */
|
||||
do
|
||||
{
|
||||
*bp++ = (char) (u % 8) + '0';
|
||||
} while ((u /= 8) > 0);
|
||||
if (hash)
|
||||
*bp++ = '0';
|
||||
}
|
||||
else if (fmt == 'x')
|
||||
{ /* hex */
|
||||
do
|
||||
{
|
||||
i = (int) (u % 16);
|
||||
if (i < 10)
|
||||
*bp++ = i + '0';
|
||||
else
|
||||
*bp++ = i - 10 + 'a';
|
||||
} while ((u /= 16) > 0);
|
||||
if (hash)
|
||||
{
|
||||
*bp++ = 'x';
|
||||
*bp++ = '0';
|
||||
}
|
||||
}
|
||||
i = f_width - (int) (bp - buf);
|
||||
if (!flush_left)
|
||||
while (i-- > 0)
|
||||
(*addchar)((int) (pad | attributes));
|
||||
for (bp--; bp >= buf; bp--)
|
||||
(*addchar)((int) (((unsigned char) *bp) | attributes));
|
||||
if (flush_left)
|
||||
while (i-- > 0)
|
||||
(*addchar)((int) (' ' | attributes));
|
||||
break;
|
||||
case 'p':
|
||||
do_long = 1;
|
||||
hash = 1;
|
||||
fmt = 'x';
|
||||
/* no break */
|
||||
case 'o':
|
||||
case 'x':
|
||||
case 'u':
|
||||
switch (do_long)
|
||||
{
|
||||
case 0:
|
||||
u = (unsigned long) (va_arg(ap, unsigned int));
|
||||
break;
|
||||
case 1:
|
||||
default:
|
||||
u = va_arg(ap, unsigned long);
|
||||
break;
|
||||
}
|
||||
if (fmt == 'u')
|
||||
{ /* unsigned decimal */
|
||||
do
|
||||
{
|
||||
*bp++ = (char) (u % 10) + '0';
|
||||
} while ((u /= 10) > 0);
|
||||
}
|
||||
else if (fmt == 'o')
|
||||
{ /* octal */
|
||||
do
|
||||
{
|
||||
*bp++ = (char) (u % 8) + '0';
|
||||
} while ((u /= 8) > 0);
|
||||
if (hash)
|
||||
*bp++ = '0';
|
||||
}
|
||||
else if (fmt == 'x')
|
||||
{ /* hex */
|
||||
do
|
||||
{
|
||||
i = (int) (u % 16);
|
||||
if (i < 10)
|
||||
*bp++ = i + '0';
|
||||
else
|
||||
*bp++ = i - 10 + 'a';
|
||||
} while ((u /= 16) > 0);
|
||||
if (hash)
|
||||
{
|
||||
*bp++ = 'x';
|
||||
*bp++ = '0';
|
||||
}
|
||||
}
|
||||
i = f_width - (int) (bp - buf);
|
||||
if (!flush_left)
|
||||
while (i-- > 0)
|
||||
(*addchar)((int) (pad | attributes));
|
||||
for (bp--; bp >= buf; bp--)
|
||||
(*addchar)((int) (((unsigned char) *bp) | attributes));
|
||||
if (flush_left)
|
||||
while (i-- > 0)
|
||||
(*addchar)((int) (' ' | attributes));
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
i = va_arg(ap, int);
|
||||
(*addchar)((int) (i | attributes));
|
||||
break;
|
||||
case 'c':
|
||||
i = va_arg(ap, int);
|
||||
(*addchar)((int) (i | attributes));
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
case 'Q':
|
||||
case 's':
|
||||
case 'q':
|
||||
bp = va_arg(ap, char *);
|
||||
if (!bp)
|
||||
bp = snil;
|
||||
f_width = f_width - strlen((char *) bp);
|
||||
if (!flush_left)
|
||||
while (f_width-- > 0)
|
||||
(*addchar)((int) (pad | attributes));
|
||||
for (i = 0; *bp && i < prec; i++)
|
||||
{
|
||||
if (fmt == 'q' && (*bp & QUOTE))
|
||||
(*addchar)((int) ('\\' | attributes));
|
||||
(*addchar)(
|
||||
(int) (((unsigned char) *bp & TRIM) | attributes));
|
||||
bp++;
|
||||
}
|
||||
if (flush_left)
|
||||
while (f_width-- > 0)
|
||||
(*addchar)((int) (' ' | attributes));
|
||||
break;
|
||||
case 'S':
|
||||
case 'Q':
|
||||
case 's':
|
||||
case 'q':
|
||||
bp = va_arg(ap, char *);
|
||||
if (!bp)
|
||||
bp = snil;
|
||||
f_width = f_width - strlen((char *) bp);
|
||||
if (!flush_left)
|
||||
while (f_width-- > 0)
|
||||
(*addchar)((int) (pad | attributes));
|
||||
for (i = 0; *bp && i < prec; i++)
|
||||
{
|
||||
if (fmt == 'q' && (*bp & QUOTE))
|
||||
(*addchar)((int) ('\\' | attributes));
|
||||
(*addchar)(
|
||||
(int) (((unsigned char) *bp & TRIM) | attributes));
|
||||
bp++;
|
||||
}
|
||||
if (flush_left)
|
||||
while (f_width-- > 0)
|
||||
(*addchar)((int) (' ' | attributes));
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
attributes = va_arg(ap, int);
|
||||
break;
|
||||
case 'a':
|
||||
attributes = va_arg(ap, int);
|
||||
break;
|
||||
|
||||
case '%':
|
||||
(*addchar)((int) ('%' | attributes));
|
||||
break;
|
||||
case '%':
|
||||
(*addchar)((int) ('%' | attributes));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0;
|
||||
sign = 0;
|
||||
pad = ' ';
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0;
|
||||
sign = 0;
|
||||
pad = ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char *xstring, *xestring;
|
||||
|
||||
void xaddchar(int c)
|
||||
{
|
||||
if (xestring == xstring)
|
||||
*xstring = '\0';
|
||||
else
|
||||
*xstring++ = (char) c;
|
||||
if (xestring == xstring)
|
||||
*xstring = '\0';
|
||||
else
|
||||
*xstring++ = (char) c;
|
||||
}
|
||||
|
||||
int sprintf(char *str, const char *format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
|
||||
xstring = str;
|
||||
xstring = str;
|
||||
|
||||
doprnt(xaddchar, format, va);
|
||||
va_end(va);
|
||||
*xstring++ = '\0';
|
||||
doprnt(xaddchar, format, va);
|
||||
va_end(va);
|
||||
*xstring++ = '\0';
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void xsnprintf(char *str, size_t size, const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
|
||||
xstring = str;
|
||||
xestring = str + size - 1;
|
||||
doprnt(xaddchar, fmt, va);
|
||||
va_end(va);
|
||||
*xstring++ = '\0';
|
||||
xstring = str;
|
||||
xestring = str + size - 1;
|
||||
doprnt(xaddchar, fmt, va);
|
||||
va_end(va);
|
||||
*xstring++ = '\0';
|
||||
}
|
||||
|
||||
void xprintf(const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
doprnt(xputchar, fmt, va);
|
||||
va_end(va);
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
doprnt(xputchar, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void xvprintf(const char *fmt, va_list va)
|
||||
{
|
||||
doprnt(xputchar, fmt, va);
|
||||
doprnt(xputchar, fmt, va);
|
||||
}
|
||||
|
||||
void xvsnprintf(char *str, size_t size, const char *fmt, va_list va)
|
||||
{
|
||||
xstring = str;
|
||||
xestring = str + size - 1;
|
||||
doprnt(xaddchar, fmt, va);
|
||||
*xstring++ = '\0';
|
||||
xstring = str;
|
||||
xestring = str + size - 1;
|
||||
doprnt(xaddchar, fmt, va);
|
||||
*xstring++ = '\0';
|
||||
}
|
||||
|
||||
|
||||
void display_progress()
|
||||
{
|
||||
static int _progress_index;
|
||||
char progress_char[] = "|/-\\";
|
||||
static int _progress_index;
|
||||
char progress_char[] = "|/-\\";
|
||||
|
||||
xputchar(progress_char[_progress_index++ % strlen(progress_char)]);
|
||||
xputchar('\r');
|
||||
xputchar(progress_char[_progress_index++ % strlen(progress_char)]);
|
||||
xputchar('\r');
|
||||
}
|
||||
|
||||
void hexdump(uint8_t buffer[], int size)
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* printf_helper.S
|
||||
*
|
||||
* assembler trampoline to let printf (compiled -mpcrel) indirectly reference __MBAR
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* Copyright 2010 - 2012 F. Aschwanden
|
||||
* Copyright 2011 - 2012 V. Riviere
|
||||
* Copyright 2012 M. Froeschle
|
||||
*/
|
||||
|
||||
|
||||
.global printf_helper
|
||||
printf_helper:
|
||||
.extern __MBAR
|
||||
.wait_txready:
|
||||
move.w __MBAR+0x8604,d2 // PSCSCR0 status register
|
||||
btst #10,d2 // space left in TX fifo?
|
||||
beq.s .wait_txready // no, loop
|
||||
lea __MBAR+0x860C,a0 // PSCSTB0 transmitter buffer register
|
||||
move.b d0,(a0) // send byte
|
||||
rts
|
||||
|
||||
// vim: set syntax=asm68k :
|
||||
Reference in New Issue
Block a user