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= \
|
ASRCS= \
|
||||||
startcf.S \
|
startcf.S \
|
||||||
printf_helper.S \
|
|
||||||
exceptions.S \
|
exceptions.S \
|
||||||
xhdi_vec.S \
|
xhdi_vec.S \
|
||||||
pci_wrappers.S
|
pci_wrappers.S
|
||||||
|
|||||||
@@ -78,7 +78,6 @@ SECTIONS
|
|||||||
OBJDIR/s19reader.o(.text)
|
OBJDIR/s19reader.o(.text)
|
||||||
OBJDIR/bas_printf.o(.text)
|
OBJDIR/bas_printf.o(.text)
|
||||||
OBJDIR/bas_string.o(.text)
|
OBJDIR/bas_string.o(.text)
|
||||||
OBJDIR/printf_helper.o(.text)
|
|
||||||
OBJDIR/cache.o(.text)
|
OBJDIR/cache.o(.text)
|
||||||
OBJDIR/dma.o(.text)
|
OBJDIR/dma.o(.text)
|
||||||
OBJDIR/MCD_dmaApi.o(.text)
|
OBJDIR/MCD_dmaApi.o(.text)
|
||||||
|
|||||||
@@ -55,11 +55,6 @@
|
|||||||
#define CF_CACR_EUSP (0x00000020) /* Switch stacks in user mode */
|
#define CF_CACR_EUSP (0x00000020) /* Switch stacks in user mode */
|
||||||
#define CF_CACR_DF (0x00000010) /* Disable FPU */
|
#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 ICACHE_SIZE 0x8000 /* instruction - 32k */
|
||||||
#define DCACHE_SIZE 0x8000 /* data - 32k */
|
#define DCACHE_SIZE 0x8000 /* data - 32k */
|
||||||
|
|
||||||
@@ -67,6 +62,10 @@
|
|||||||
#define CACHE_SETS 0x0200 /* 512 sets */
|
#define CACHE_SETS 0x0200 /* 512 sets */
|
||||||
#define CACHE_WAYS 0x0004 /* 4 way */
|
#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+ \
|
#define CACHE_DISABLE_MODE (CF_CACR_DCINVA+ \
|
||||||
CF_CACR_BCINVA+ \
|
CF_CACR_BCINVA+ \
|
||||||
|
|||||||
@@ -50,27 +50,30 @@
|
|||||||
* MMU register handling macros
|
* 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
|
* MMU page sizes
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum mmu_page_size
|
enum mmu_page_size
|
||||||
{
|
{
|
||||||
MMU_PAGE_SIZE_1M = 0,
|
MMU_PAGE_SIZE_1M = 0,
|
||||||
MMU_PAGE_SIZE_4K = 1,
|
MMU_PAGE_SIZE_4K = 1,
|
||||||
MMU_PAGE_SIZE_8K = 2,
|
MMU_PAGE_SIZE_8K = 2,
|
||||||
MMU_PAGE_SIZE_1K = 3
|
MMU_PAGE_SIZE_1K = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* cache modes
|
* cache modes
|
||||||
*/
|
*/
|
||||||
#define CACHE_WRITETHROUGH 0
|
enum mmu_cache_modes
|
||||||
#define CACHE_COPYBACK 1
|
{
|
||||||
#define CACHE_NOCACHE_PRECISE 2
|
CACHE_WRITETHROUGH = 0,
|
||||||
#define CACHE_NOCACHE_IMPRECISE 3
|
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_WRITE (1 << 1)
|
||||||
#define ACCESS_EXECUTE (1 << 2)
|
#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
|
* global variables from linker script
|
||||||
*/
|
*/
|
||||||
extern long video_tlb;
|
extern long video_tlb;
|
||||||
extern long video_sbt;
|
extern long video_sbt;
|
||||||
|
|
||||||
|
extern void mmu_enable(void);
|
||||||
extern void mmu_init(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_ */
|
#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)
|
static inline bool pic_txready(void)
|
||||||
{
|
{
|
||||||
if (MCF_PSC3_PSCSR & MCF_PSC_PSCSR_TXRDY)
|
if (MCF_PSC3_PSCSR & MCF_PSC_PSCSR_TXRDY)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -87,84 +87,84 @@ static inline bool pic_txready(void)
|
|||||||
*/
|
*/
|
||||||
static inline bool pic_rxready(void)
|
static inline bool pic_rxready(void)
|
||||||
{
|
{
|
||||||
if (MCF_PSC3_PSCSR & MCF_PSC_PSCSR_RXRDY)
|
if (MCF_PSC3_PSCSR & MCF_PSC_PSCSR_RXRDY)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_pic_byte(uint8_t value)
|
void write_pic_byte(uint8_t value)
|
||||||
{
|
{
|
||||||
/* Wait until the transmitter is ready or 1000us are passed */
|
/* Wait until the transmitter is ready or 1000us are passed */
|
||||||
waitfor(1000, pic_txready);
|
waitfor(1000, pic_txready);
|
||||||
|
|
||||||
/* Transmit the byte */
|
/* Transmit the byte */
|
||||||
*(volatile uint8_t*)(&MCF_PSC3_PSCTB_8BIT) = value; // Really 8-bit
|
*(volatile uint8_t*)(&MCF_PSC3_PSCTB_8BIT) = value; // Really 8-bit
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t read_pic_byte(void)
|
uint8_t read_pic_byte(void)
|
||||||
{
|
{
|
||||||
/* Wait until a byte has been received or 1000us are passed */
|
/* Wait until a byte has been received or 1000us are passed */
|
||||||
waitfor(1000, pic_rxready);
|
waitfor(1000, pic_rxready);
|
||||||
|
|
||||||
/* Return the received byte */
|
/* Return the received byte */
|
||||||
return * (volatile uint8_t *) (&MCF_PSC3_PSCTB_8BIT); // Really 8-bit
|
return * (volatile uint8_t *) (&MCF_PSC3_PSCTB_8BIT); // Really 8-bit
|
||||||
}
|
}
|
||||||
|
|
||||||
void pic_init(void)
|
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 */
|
/* Send the PIC initialization string */
|
||||||
write_pic_byte('A');
|
write_pic_byte('A');
|
||||||
write_pic_byte('C');
|
write_pic_byte('C');
|
||||||
write_pic_byte('P');
|
write_pic_byte('P');
|
||||||
write_pic_byte('F');
|
write_pic_byte('F');
|
||||||
|
|
||||||
/* Read the 3-char answer string. Should be "OK!". */
|
/* Read the 3-char answer string. Should be "OK!". */
|
||||||
answer[0] = read_pic_byte();
|
answer[0] = read_pic_byte();
|
||||||
answer[1] = read_pic_byte();
|
answer[1] = read_pic_byte();
|
||||||
answer[2] = read_pic_byte();
|
answer[2] = read_pic_byte();
|
||||||
answer[3] = '\0';
|
answer[3] = '\0';
|
||||||
|
|
||||||
if (answer[0] != 'O' || answer[1] != 'K' || answer[2] != '!')
|
if (answer[0] != 'O' || answer[1] != 'K' || answer[2] != '!')
|
||||||
{
|
{
|
||||||
dbg("PIC initialization failed. Already initialized?\r\n");
|
dbg("PIC initialization failed. Already initialized?\r\n");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
xprintf("%s\r\n", answer);
|
xprintf("%s\r\n", answer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nvram_init(void)
|
void nvram_init(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
xprintf("Restore the NVRAM data: ");
|
xprintf("Restore the NVRAM data: ");
|
||||||
|
|
||||||
/* Request for NVRAM backup data */
|
/* Request for NVRAM backup data */
|
||||||
write_pic_byte(0x01);
|
write_pic_byte(0x01);
|
||||||
|
|
||||||
/* Check answer type */
|
/* Check answer type */
|
||||||
if (read_pic_byte() != 0x81)
|
if (read_pic_byte() != 0x81)
|
||||||
{
|
{
|
||||||
// FIXME: PIC protocol error
|
// FIXME: PIC protocol error
|
||||||
xprintf("FAILED\r\n");
|
xprintf("FAILED\r\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Restore the NVRAM backup to the FPGA */
|
/* Restore the NVRAM backup to the FPGA */
|
||||||
for (i = 0; i < 64; i++)
|
for (i = 0; i < 64; i++)
|
||||||
{
|
{
|
||||||
uint8_t data = read_pic_byte();
|
uint8_t data = read_pic_byte();
|
||||||
*(volatile uint8_t*)0xffff8961 = i;
|
*(volatile uint8_t*)0xffff8961 = i;
|
||||||
*(volatile uint8_t*)0xffff8963 = data;
|
*(volatile uint8_t*)0xffff8963 = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
xprintf("finished\r\n");
|
xprintf("finished\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#define KBD_ACIA_CONTROL ((uint8_t *) 0xfffffc00)
|
#define KBD_ACIA_CONTROL ((uint8_t *) 0xfffffc00)
|
||||||
@@ -174,24 +174,24 @@ void nvram_init(void)
|
|||||||
|
|
||||||
void acia_init()
|
void acia_init()
|
||||||
{
|
{
|
||||||
xprintf("init ACIA: ");
|
xprintf("init ACIA: ");
|
||||||
/* init ACIA */
|
/* init ACIA */
|
||||||
* KBD_ACIA_CONTROL = 3; /* master reset */
|
* KBD_ACIA_CONTROL = 3; /* master reset */
|
||||||
NOP();
|
NOP();
|
||||||
|
|
||||||
* MIDI_ACIA_CONTROL = 3; /* master reset */
|
* MIDI_ACIA_CONTROL = 3; /* master reset */
|
||||||
NOP();
|
NOP();
|
||||||
|
|
||||||
* KBD_ACIA_CONTROL = 0x96; /* clock div = 64, 8N1, RTS low, TX int disable, RX int enable */
|
* KBD_ACIA_CONTROL = 0x96; /* clock div = 64, 8N1, RTS low, TX int disable, RX int enable */
|
||||||
NOP();
|
NOP();
|
||||||
|
|
||||||
* MFP_INTR_IN_SERVICE_A = -1;
|
* MFP_INTR_IN_SERVICE_A = -1;
|
||||||
NOP();
|
NOP();
|
||||||
|
|
||||||
* MFP_INTR_IN_SERVICE_B = -1;
|
* MFP_INTR_IN_SERVICE_B = -1;
|
||||||
NOP();
|
NOP();
|
||||||
|
|
||||||
xprintf("finished\r\n");
|
xprintf("finished\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ACP interrupt controller */
|
/* ACP interrupt controller */
|
||||||
@@ -201,43 +201,43 @@ void acia_init()
|
|||||||
|
|
||||||
void enable_coldfire_interrupts()
|
void enable_coldfire_interrupts()
|
||||||
{
|
{
|
||||||
xprintf("enable interrupts: ");
|
xprintf("enable interrupts: ");
|
||||||
#if defined(MACHINE_FIREBEE)
|
#if defined(MACHINE_FIREBEE)
|
||||||
*FPGA_INTR_CONTRL = 0L; /* disable all interrupts */
|
*FPGA_INTR_CONTRL = 0L; /* disable all interrupts */
|
||||||
#endif /* MACHINE_FIREBEE */
|
#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)
|
#if defined(MACHINE_FIREBEE)
|
||||||
/*
|
/*
|
||||||
* TIN0 on the Coldfire is connected to the FPGA. TIN0 triggers every write
|
* 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
|
* 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_GPT0_GMS = MCF_GPT_GMS_ICT(1) | /* timer 0 on, video change capture on rising edge */
|
||||||
MCF_GPT_GMS_IEN |
|
MCF_GPT_GMS_IEN |
|
||||||
MCF_GPT_GMS_TMS(1);
|
MCF_GPT_GMS_TMS(1);
|
||||||
/* route GPT0 interrupt on interrupt controller */
|
/* route GPT0 interrupt on interrupt controller */
|
||||||
MCF_INTC_ICR62 = 0x3f; /* interrupt level 7, interrupt priority 7 */
|
MCF_INTC_ICR62 = 0x3f; /* interrupt level 7, interrupt priority 7 */
|
||||||
|
|
||||||
*FPGA_INTR_ENABLE = 0xfe; /* enable int 1-7 */
|
*FPGA_INTR_ENABLE = 0xfe; /* enable int 1-7 */
|
||||||
MCF_EPORT_EPIER = 0xfe; /* int 1-7 on */
|
MCF_EPORT_EPIER = 0xfe; /* int 1-7 on */
|
||||||
MCF_EPORT_EPFR = 0xff; /* clear all pending interrupts */
|
MCF_EPORT_EPFR = 0xff; /* clear all pending interrupts */
|
||||||
MCF_INTC_IMRL = 0xffffff00; /* int 1-7 on */
|
MCF_INTC_IMRL = 0xffffff00; /* int 1-7 on */
|
||||||
MCF_INTC_IMRH = 0xbffffffe; /* psc3 and timer 0 int on */
|
MCF_INTC_IMRH = 0xbffffffe; /* psc3 and timer 0 int on */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
xprintf("finished\r\n");
|
xprintf("finished\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void disable_coldfire_interrupts()
|
void disable_coldfire_interrupts()
|
||||||
{
|
{
|
||||||
#if defined(MACHINE_FIREBEE)
|
#if defined(MACHINE_FIREBEE)
|
||||||
*FPGA_INTR_ENABLE = 0; /* disable all interrupts */
|
*FPGA_INTR_ENABLE = 0; /* disable all interrupts */
|
||||||
#endif /* MACHINE_FIREBEE */
|
#endif /* MACHINE_FIREBEE */
|
||||||
|
|
||||||
MCF_EPORT_EPIER = 0x0;
|
MCF_EPORT_EPIER = 0x0;
|
||||||
MCF_EPORT_EPFR = 0x0;
|
MCF_EPORT_EPFR = 0x0;
|
||||||
MCF_INTC_IMRL = 0xfffffffe;
|
MCF_INTC_IMRL = 0xfffffffe;
|
||||||
MCF_INTC_IMRH = 0xffffffff;
|
MCF_INTC_IMRH = 0xffffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -252,178 +252,180 @@ NIF nif2;
|
|||||||
*/
|
*/
|
||||||
void init_isr(void)
|
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
|
* register the FEC interrupt handler
|
||||||
*/
|
*/
|
||||||
if (!isr_register_handler(64 + INT_SOURCE_FEC0, fec0_interrupt_handler, NULL, (void *) &nif1))
|
if (!isr_register_handler(64 + INT_SOURCE_FEC0, fec0_interrupt_handler, NULL, (void *) &nif1))
|
||||||
{
|
{
|
||||||
dbg("unable to register isr for FEC0\r\n");
|
dbg("unable to register isr for FEC0\r\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register the DMA interrupt handler
|
* Register the DMA interrupt handler
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!isr_register_handler(64 + INT_SOURCE_DMA, dma_interrupt_handler, NULL,NULL))
|
if (!isr_register_handler(64 + INT_SOURCE_DMA, dma_interrupt_handler, NULL,NULL))
|
||||||
{
|
{
|
||||||
dbg("Error: Unable to register isr for DMA\r\n");
|
dbg("Error: Unable to register isr for DMA\r\n");
|
||||||
return;
|
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
|
* register the PIC interrupt handler
|
||||||
*/
|
*/
|
||||||
if (isr_register_handler(64 + INT_SOURCE_PSC3, pic_interrupt_handler, NULL, NULL))
|
if (isr_register_handler(64 + INT_SOURCE_PSC3, pic_interrupt_handler, NULL, NULL))
|
||||||
{
|
{
|
||||||
dbg("Error: unable to register ISR for PSC3\r\n");
|
dbg("Error: unable to register ISR for PSC3\r\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaS(void)
|
void BaS(void)
|
||||||
{
|
{
|
||||||
uint8_t *src;
|
uint8_t *src;
|
||||||
uint8_t *dst = (uint8_t *) TOS;
|
uint8_t *dst = (uint8_t *) TOS;
|
||||||
|
|
||||||
#if defined(MACHINE_FIREBEE) /* LITE board has no pic and (currently) no nvram */
|
#if defined(MACHINE_FIREBEE) /* LITE board has no pic and (currently) no nvram */
|
||||||
pic_init();
|
pic_init();
|
||||||
nvram_init();
|
nvram_init();
|
||||||
#endif /* MACHINE_FIREBEE */
|
#endif /* MACHINE_FIREBEE */
|
||||||
|
|
||||||
xprintf("copy EmuTOS: ");
|
xprintf("copy EmuTOS: ");
|
||||||
|
|
||||||
/* copy EMUTOS */
|
/* copy EMUTOS */
|
||||||
src = (uint8_t *) EMUTOS;
|
src = (uint8_t *) EMUTOS;
|
||||||
dma_memcpy(dst, src, EMUTOS_SIZE);
|
dma_memcpy(dst, src, EMUTOS_SIZE);
|
||||||
xprintf("finished\r\n");
|
xprintf("finished\r\n");
|
||||||
|
|
||||||
xprintf("initialize MMU: ");
|
xprintf("initialize MMU: ");
|
||||||
mmu_init();
|
mmu_init();
|
||||||
xprintf("finished\r\n");
|
xprintf("finished\r\n");
|
||||||
|
|
||||||
xprintf("initialize exception vector table: ");
|
xprintf("enable MMU: ");
|
||||||
vec_init();
|
|
||||||
xprintf("finished\r\n");
|
|
||||||
|
|
||||||
xprintf("flush caches: ");
|
mmu_enable(); /* force pipeline sync */
|
||||||
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");
|
|
||||||
|
|
||||||
#ifdef MACHINE_FIREBEE
|
xprintf("finished\r\n");
|
||||||
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("initialize exception vector table: ");
|
||||||
|
vec_init();
|
||||||
|
xprintf("finished\r\n");
|
||||||
|
|
||||||
xprintf("finished\r\n");
|
xprintf("flush caches: ");
|
||||||
xprintf("enable video: ");
|
flush_and_invalidate_caches();
|
||||||
/*
|
xprintf("finished\r\n");
|
||||||
* video setup (25MHz)
|
|
||||||
*/
|
#ifdef MACHINE_FIREBEE
|
||||||
* (volatile uint32_t *) (0xf0000410 + 0) = 0x032002ba; /* horizontal 640x480 */
|
xprintf("IDE reset: ");
|
||||||
* (volatile uint32_t *) (0xf0000410 + 4) = 0x020c020a; /* vertical 640x480 */
|
/* IDE reset */
|
||||||
* (volatile uint32_t *) (0xf0000410 + 8) = 0x0190015d; /* horizontal 320x240 */
|
* (volatile uint8_t *) (0xffff8802 - 2) = 14;
|
||||||
* (volatile uint32_t *) (0xf0000410 + 12) = 0x020C020A; /* vertical 320x230 */
|
* (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_
|
#ifdef _NOT_USED_
|
||||||
// 32MHz
|
// 32MHz
|
||||||
* (volatile uint32_t *) (0xf0000410 + 0) = 0x037002ba; /* horizontal 640x480 */
|
* (volatile uint32_t *) (0xf0000410 + 0) = 0x037002ba; /* horizontal 640x480 */
|
||||||
* (volatile uint32_t *) (0xf0000410 + 4) = 0x020d020a; /* vertical 640x480 */
|
* (volatile uint32_t *) (0xf0000410 + 4) = 0x020d020a; /* vertical 640x480 */
|
||||||
* (volatile uint32_t *) (0xf0000410 + 8) = 0x02a001e0; /* horizontal 320x240 */
|
* (volatile uint32_t *) (0xf0000410 + 8) = 0x02a001e0; /* horizontal 320x240 */
|
||||||
* (volatile uint32_t *) (0xf0000410 + 12) = 0x05a00160; /* vertical 320x230 */
|
* (volatile uint32_t *) (0xf0000410 + 12) = 0x05a00160; /* vertical 320x230 */
|
||||||
#endif /* _NOT_USED_ */
|
#endif /* _NOT_USED_ */
|
||||||
|
|
||||||
/* fifo on, refresh on, ddrcs and cke on, video dac on */
|
/* fifo on, refresh on, ddrcs and cke on, video dac on */
|
||||||
* (volatile uint32_t *) (0xf0000410 - 0x20) = 0x01070002;
|
* (volatile uint32_t *) (0xf0000410 - 0x20) = 0x01070002;
|
||||||
|
|
||||||
xprintf("finished\r\n");
|
xprintf("finished\r\n");
|
||||||
|
|
||||||
enable_coldfire_interrupts();
|
enable_coldfire_interrupts();
|
||||||
|
|
||||||
#ifdef _NOT_USED_
|
#ifdef _NOT_USED_
|
||||||
screen_init();
|
screen_init();
|
||||||
|
|
||||||
/* experimental */
|
/* experimental */
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
uint32_t *scradr = 0xd00000;
|
uint32_t *scradr = 0xd00000;
|
||||||
|
|
||||||
for (i = 0; i < 100; i++)
|
for (i = 0; i < 100; i++)
|
||||||
{
|
{
|
||||||
uint32_t *p = scradr;
|
uint32_t *p = scradr;
|
||||||
|
|
||||||
for (p = scradr; p < scradr + 1024 * 150L; p++)
|
for (p = scradr; p < scradr + 1024 * 150L; p++)
|
||||||
{
|
{
|
||||||
*p = 0xffffffff;
|
*p = 0xffffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (p = scradr; p < scradr + 1024 * 150L; p++)
|
for (p = scradr; p < scradr + 1024 * 150L; p++)
|
||||||
{
|
{
|
||||||
*p = 0x0;
|
*p = 0x0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* _NOT_USED_ */
|
#endif /* _NOT_USED_ */
|
||||||
|
|
||||||
#endif /* MACHINE_FIREBEE */
|
#endif /* MACHINE_FIREBEE */
|
||||||
|
|
||||||
sd_card_init();
|
sd_card_init();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* memory setup
|
* memory setup
|
||||||
*/
|
*/
|
||||||
memset((void *) 0x400, 0, 0x400);
|
memset((void *) 0x400, 0, 0x400);
|
||||||
|
|
||||||
#if defined(MACHINE_FIREBEE)
|
#if defined(MACHINE_FIREBEE)
|
||||||
/* set Falcon bus control register */
|
/* set Falcon bus control register */
|
||||||
/* sets bit 3 and 6. Both are undefined on an original Falcon? */
|
/* 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 */
|
#endif /* MACHINE_FIREBEE */
|
||||||
|
|
||||||
/* ST RAM */
|
/* ST RAM */
|
||||||
|
|
||||||
* (uint32_t *) 0x42e = STRAM_END; /* phystop TOS system variable */
|
* (uint32_t *) 0x42e = STRAM_END; /* phystop TOS system variable */
|
||||||
* (uint32_t *) 0x420 = 0x752019f3; /* memvalid TOS system variable */
|
* (uint32_t *) 0x420 = 0x752019f3; /* memvalid TOS system variable */
|
||||||
* (uint32_t *) 0x43a = 0x237698aa; /* memval2 TOS system variable */
|
* (uint32_t *) 0x43a = 0x237698aa; /* memval2 TOS system variable */
|
||||||
* (uint32_t *) 0x51a = 0x5555aaaa; /* memval3 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 *) 0x5a4 = FASTRAM_END; /* ramtop TOS system variable */
|
||||||
* (uint32_t *) 0x5a8 = 0x1357bd13; /* ramvalid TOS system variable */
|
* (uint32_t *) 0x5a8 = 0x1357bd13; /* ramvalid TOS system variable */
|
||||||
|
|
||||||
#if defined(MACHINE_FIREBEE) /* m5484lite has no ACIA and no dip switch... */
|
#if defined(MACHINE_FIREBEE) /* m5484lite has no ACIA and no dip switch... */
|
||||||
acia_init();
|
acia_init();
|
||||||
#endif /* MACHINE_FIREBEE */
|
#endif /* MACHINE_FIREBEE */
|
||||||
|
|
||||||
srec_execute("BASFLASH.S19");
|
srec_execute("BASFLASH.S19");
|
||||||
|
|
||||||
/* Jump into the OS */
|
/* Jump into the OS */
|
||||||
typedef void void_func(void);
|
typedef void void_func(void);
|
||||||
struct rom_header
|
struct rom_header
|
||||||
{
|
{
|
||||||
void *initial_sp;
|
void *initial_sp;
|
||||||
void_func *initial_pc;
|
void_func *initial_pc;
|
||||||
};
|
};
|
||||||
|
|
||||||
xprintf("BaS initialization finished, enable interrupts\r\n");
|
xprintf("BaS initialization finished, enable interrupts\r\n");
|
||||||
enable_coldfire_interrupts();
|
enable_coldfire_interrupts();
|
||||||
init_isr();
|
init_isr();
|
||||||
|
|
||||||
xprintf("call EmuTOS\r\n");
|
xprintf("call EmuTOS\r\n");
|
||||||
struct rom_header *os_header = (struct rom_header *) TOS;
|
struct rom_header *os_header = (struct rom_header *) TOS;
|
||||||
os_header->initial_pc();
|
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;
|
start_set = (uint32_t) address & _ICACHE_SET_MASK;
|
||||||
end_set = (uint32_t) endaddr & _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 */
|
/* from the begining to the lowest address */
|
||||||
for (set = 0; set <= end_set; set += (0x10 - 3))
|
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 */
|
/* next loop will finish the cache ie pass the hole */
|
||||||
end_set = LAST_ICACHE_ADDR;
|
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__(
|
__asm__ __volatile__(
|
||||||
" cpushl ic,(%[set]) \n\t"
|
" cpushl ic,(%[set]) \n\t"
|
||||||
" addq.l #1,%[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 _irq5_handler
|
||||||
.extern _irq7_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
|
.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_EPF1,1 // edge port flag 1
|
||||||
.equ INT_SOURCE_EPORT_EPF2,2 // edge port flag 2
|
.equ INT_SOURCE_EPORT_EPF2,2 // edge port flag 2
|
||||||
.equ INT_SOURCE_EPORT_EPF3,3 // edge port flag 3
|
.equ INT_SOURCE_EPORT_EPF3,3 // edge port flag 3
|
||||||
@@ -115,85 +130,15 @@
|
|||||||
// Atari register equates (provided by FPGA)
|
// Atari register equates (provided by FPGA)
|
||||||
.equ vbasehi, 0xffff8201
|
.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)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
* macros
|
||||||
* General Purpose Timers (GPT)
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Register read/write macros */
|
|
||||||
#define MCF_GPT0_GMS __MBAR+0x800
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* Slice Timers (SLT)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define MCF_SLT0_SCNT __MBAR+0x908
|
|
||||||
|
|
||||||
/**********************************************************/
|
|
||||||
// macros
|
|
||||||
/**********************************************************/
|
|
||||||
.altmacro
|
.altmacro
|
||||||
.macro irq vector,int_mask,clr_int
|
.macro irq vector,int_mask,clr_int
|
||||||
//move.w #0x2700,sr // disable interrupt
|
move.w #0x2700,sr // disable interrupt
|
||||||
subq.l #8,sp
|
subq.l #8,sp
|
||||||
movem.l d0/a5,(sp) // save registers
|
movem.l d0/a5,(sp) // save registers
|
||||||
|
|
||||||
@@ -207,25 +152,6 @@
|
|||||||
rts
|
rts
|
||||||
.endm
|
.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
|
.text
|
||||||
_vec_init:
|
_vec_init:
|
||||||
move.l a2,-(sp) // Backup registers
|
move.l a2,-(sp) // Backup registers
|
||||||
@@ -310,12 +236,12 @@ init_vec_loop:
|
|||||||
*/
|
*/
|
||||||
vector_table_start:
|
vector_table_start:
|
||||||
std_exc_vec:
|
std_exc_vec:
|
||||||
//move.w #0x2700,sr // disable interrupt
|
move.w #0x2700,sr // disable interrupt
|
||||||
subq.l #8,sp
|
subq.l #8,sp
|
||||||
movem.l d0/a5,(sp) // save registers
|
movem.l d0/a5,(sp) // save registers
|
||||||
move.w 8(sp),d0 // fetch vector
|
move.w 8(sp),d0 // fetch vector
|
||||||
and.l #0x3fc,d0 // mask out vector number
|
and.l #0x3fc,d0 // mask out vector number
|
||||||
|
#define DBG_EXC
|
||||||
#ifdef DBG_EXC
|
#ifdef DBG_EXC
|
||||||
// printout vector number of exception
|
// printout vector number of exception
|
||||||
|
|
||||||
@@ -323,16 +249,17 @@ std_exc_vec:
|
|||||||
movem.l d0-d1/a0-a1,(sp) // save gcc scratch registers
|
movem.l d0-d1/a0-a1,(sp) // save gcc scratch registers
|
||||||
|
|
||||||
lsr.l #2,d0 // shift vector number in place
|
lsr.l #2,d0 // shift vector number in place
|
||||||
cmp.l #33,d0
|
|
||||||
beq noprint
|
cmp.l #33,d0 // do not debug-print various traps
|
||||||
cmp.l #34,d0
|
beq noprint // this would slow down interrupt
|
||||||
|
cmp.l #34,d0 // processing enormously
|
||||||
beq noprint
|
beq noprint
|
||||||
cmp.l #45,d0
|
cmp.l #45,d0
|
||||||
beq noprint
|
beq noprint
|
||||||
cmp.l #46,d0
|
cmp.l #46,d0
|
||||||
beq noprint
|
beq noprint
|
||||||
move.l 4 * 4 + 8 + 4(sp),-(sp) // pc at exception
|
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
|
pea exception_text
|
||||||
jsr _xprintf // call xprintf()
|
jsr _xprintf // call xprintf()
|
||||||
add.l #3*4,sp // adjust stack
|
add.l #3*4,sp // adjust stack
|
||||||
@@ -349,14 +276,15 @@ noprint:
|
|||||||
move.l 4(sp),a5 // restore a5
|
move.l 4(sp),a5 // restore a5
|
||||||
move.l d0,4(sp) // store exception routine address
|
move.l d0,4(sp) // store exception routine address
|
||||||
|
|
||||||
//move.w 10(sp),d0 // restore original SR
|
// FIXME: what does this do and why?
|
||||||
//bset #13,d0 // set supervisor bit
|
move.w 10(sp),d0 // restore original SR
|
||||||
//move.w d0,sr //
|
bset #13,d0 // set supervisor bit
|
||||||
|
move.w d0,sr //
|
||||||
move.l (sp)+,d0 // restore d0
|
move.l (sp)+,d0 // restore d0
|
||||||
rts // jump to exception routine
|
rts // jump to exception routine
|
||||||
|
|
||||||
exception_text:
|
exception_text:
|
||||||
.ascii "DEBUG: EXCEPTION %d caught at %p"
|
.ascii "DEBUG: EXCEPTION 0x%x caught at %p"
|
||||||
.byte 13, 10, 0
|
.byte 13, 10, 0
|
||||||
.align 4
|
.align 4
|
||||||
|
|
||||||
@@ -369,54 +297,28 @@ reset_vector:
|
|||||||
|
|
||||||
access:
|
access:
|
||||||
move.w #0x2700,sr // disable interrupts
|
move.w #0x2700,sr // disable interrupts
|
||||||
move.l d0,-(sp) // ++ vr
|
|
||||||
|
|
||||||
move.w 4(sp),d0 // get format_status word from stack
|
link a6,#-4 * 4 // make room for gcc scratch registers
|
||||||
andi.l #0x0c03,d0 // mask out fault status bits
|
movem.l d0-d1/a0-a1,(sp) // and save them
|
||||||
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
|
|
||||||
|
|
||||||
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:
|
tst.l d0 // exception handler signals bus error
|
||||||
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?
|
|
||||||
bne bus_error
|
bne bus_error
|
||||||
|
|
||||||
move.l MCF_MMU_MMUAR,d0
|
movem.l (sp),d0-d1/a0-a1 // restore stack
|
||||||
cmp.l #__FASTRAM_END,d0 // above max User RAM area?
|
unlk a6
|
||||||
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
|
|
||||||
|
|
||||||
rte
|
rte
|
||||||
|
|
||||||
bus_error:
|
bus_error:
|
||||||
move.l (sp)+,d0 // restore register
|
movem.l (sp),d0-d1/a0-a1
|
||||||
|
unlk a6
|
||||||
bra std_exc_vec
|
bra std_exc_vec
|
||||||
|
|
||||||
zero_divide:
|
zero_divide:
|
||||||
@@ -543,79 +445,6 @@ irq6: // MFP interrupt from FPGA
|
|||||||
lea MCF_EPORT_EPFR,a5 // clear int6 from edge port
|
lea MCF_EPORT_EPFR,a5 // clear int6 from edge port
|
||||||
bset #6,(a5)
|
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:
|
irq6_non_sca:
|
||||||
// test auf acsi dma -----------------------------------------------------------------
|
// test auf acsi dma -----------------------------------------------------------------
|
||||||
lea 0xfffffa0b,a5
|
lea 0xfffffa0b,a5
|
||||||
@@ -666,10 +495,6 @@ acsi_dma: // atari dma
|
|||||||
move.l d1,-(sp)
|
move.l d1,-(sp)
|
||||||
|
|
||||||
lea MCF_PSC0_PSCTB_8BIT,a1 // ++ vr
|
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
|
lea 0xf0020110,a5 // fifo daten
|
||||||
acsi_dma_start:
|
acsi_dma_start:
|
||||||
@@ -752,7 +577,10 @@ irq7:
|
|||||||
*
|
*
|
||||||
* GPT0 is used as input trigger. It is connected to the TIN0 signal of
|
* 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.
|
* 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
|
link a6,#-4 * 4 // make room for
|
||||||
movem.l d0-d1/a0-a1,(sp) // gcc scratch registers and save them,
|
movem.l d0-d1/a0-a1,(sp) // gcc scratch registers and save them,
|
||||||
// other registers will be handled by gcc itself
|
// other registers will be handled by gcc itself
|
||||||
|
|
||||||
move.w 4(a6),d0 // fetch vector number from stack
|
move.w 4(a6),d0 // fetch vector number from stack
|
||||||
move.l d0,-(sp) // push it
|
move.l d0,-(sp) // push it
|
||||||
jsr _gpt0_interrupt_handler // call C handler
|
jsr _gpt0_interrupt_handler // call C handler
|
||||||
addq.l #4,sp // adjust stack
|
addq.l #4,sp // adjust stack
|
||||||
|
|
||||||
|
movem.l (sp),d0-d1/a0-a1 // restore registers
|
||||||
|
|
||||||
unlk a6
|
unlk a6
|
||||||
rte
|
rte
|
||||||
#endif /* MACHINE_FIREBEE */
|
#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 register_interrupt_handler(uint8_t source, uint8_t level, uint8_t priority, uint8_t intr, void (*handler)(void))
|
||||||
{
|
{
|
||||||
int ipl;
|
int ipl;
|
||||||
int i;
|
int i;
|
||||||
volatile uint8_t *ICR = &MCF_INTC_ICR01 - 1;
|
volatile uint8_t *ICR = &MCF_INTC_ICR01 - 1;
|
||||||
uint8_t lp;
|
uint8_t lp;
|
||||||
|
|
||||||
source &= 63;
|
source &= 63;
|
||||||
priority &= 7;
|
priority &= 7;
|
||||||
|
|
||||||
if (source < 1 || source > 63)
|
if (source < 1 || source > 63)
|
||||||
{
|
{
|
||||||
dbg("interrupt source %d not defined\r\n", source);
|
dbg("interrupt source %d not defined\r\n", source);
|
||||||
return -1;
|
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 */
|
/* check if this combination is already set somewhere */
|
||||||
for (i = 1; i < 64; i++)
|
for (i = 1; i < 64; i++)
|
||||||
{
|
{
|
||||||
if (ICR[i] == lp)
|
if (ICR[i] == lp)
|
||||||
{
|
{
|
||||||
dbg("level %d and priority %d already used for interrupt source %d!\r\n",
|
dbg("level %d and priority %d already used for interrupt source %d!\r\n",
|
||||||
level, priority, i);
|
level, priority, i);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* disable interrupts */
|
/* disable interrupts */
|
||||||
ipl = set_ipl(7);
|
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 */
|
/* set level and priority in interrupt controller */
|
||||||
ICR[source] = lp;
|
ICR[source] = lp;
|
||||||
|
|
||||||
/* set interrupt mask to where it was before */
|
/* set interrupt mask to where it was before */
|
||||||
set_ipl(ipl);
|
set_ipl(ipl);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef MAX_ISR_ENTRY
|
#ifndef MAX_ISR_ENTRY
|
||||||
@@ -100,10 +100,10 @@ int register_interrupt_handler(uint8_t source, uint8_t level, uint8_t priority,
|
|||||||
|
|
||||||
struct isrentry
|
struct isrentry
|
||||||
{
|
{
|
||||||
int vector;
|
int vector;
|
||||||
int (*handler)(void *, void *);
|
int (*handler)(void *, void *);
|
||||||
void *hdev;
|
void *hdev;
|
||||||
void *harg;
|
void *harg;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct isrentry isrtab[MAX_ISR_ENTRY]; /* list of interrupt service routines */
|
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)
|
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 isr_register_handler(int vector, int (*handler)(void *, void *), void *hdev, void *harg)
|
||||||
{
|
{
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
if ((vector == 0) || (handler == NULL))
|
if ((vector == 0) || (handler == NULL))
|
||||||
{
|
{
|
||||||
dbg("illegal vector or handler!\r\n");
|
dbg("illegal vector or handler!\r\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (index = 0; index < MAX_ISR_ENTRY; index++)
|
for (index = 0; index < MAX_ISR_ENTRY; index++)
|
||||||
{
|
{
|
||||||
if (isrtab[index].vector == vector)
|
if (isrtab[index].vector == vector)
|
||||||
{
|
{
|
||||||
/* one cross each, only! */
|
/* one cross each, only! */
|
||||||
dbg("already set handler with this vector (%d, %d)\r\n", vector);
|
dbg("already set handler with this vector (%d, %d)\r\n", vector);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isrtab[index].vector == 0)
|
if (isrtab[index].vector == 0)
|
||||||
{
|
{
|
||||||
isrtab[index].vector = vector;
|
isrtab[index].vector = vector;
|
||||||
isrtab[index].handler = handler;
|
isrtab[index].handler = handler;
|
||||||
isrtab[index].hdev = hdev;
|
isrtab[index].hdev = hdev;
|
||||||
isrtab[index].harg = harg;
|
isrtab[index].harg = harg;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dbg("no available slots to register handler for vector %d\n\r", vector);
|
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 *))
|
void isr_remove_handler(int (*handler)(void *, void *))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* This routine removes from the ISR table all
|
* This routine removes from the ISR table all
|
||||||
* entries that matches 'handler'.
|
* entries that matches 'handler'.
|
||||||
*/
|
*/
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
for (index = 0; index < MAX_ISR_ENTRY; index++)
|
for (index = 0; index < MAX_ISR_ENTRY; index++)
|
||||||
{
|
{
|
||||||
if (isrtab[index].handler == handler)
|
if (isrtab[index].handler == handler)
|
||||||
{
|
{
|
||||||
memset(&isrtab[index], 0, sizeof(struct isrentry));
|
memset(&isrtab[index], 0, sizeof(struct isrentry));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dbg("no such handler registered (handler=%p\r\n", handler);
|
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)
|
bool isr_execute_handler(int vector)
|
||||||
{
|
{
|
||||||
int index;
|
int index;
|
||||||
bool retval = false;
|
bool retval = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* locate a BaS Interrupt Service Routine handler.
|
* locate a BaS Interrupt Service Routine handler.
|
||||||
*/
|
*/
|
||||||
for (index = 0; index < MAX_ISR_ENTRY; index++)
|
for (index = 0; index < MAX_ISR_ENTRY; index++)
|
||||||
{
|
{
|
||||||
if (isrtab[index].vector == vector)
|
if (isrtab[index].vector == vector)
|
||||||
{
|
{
|
||||||
retval = true;
|
retval = true;
|
||||||
|
|
||||||
if (isrtab[index].handler(isrtab[index].hdev, isrtab[index].harg))
|
if (isrtab[index].handler(isrtab[index].hdev, isrtab[index].harg))
|
||||||
{
|
{
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dbg("no BaS isr handler for vector %d found\r\n", vector);
|
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)
|
int pic_interrupt_handler(void *arg1, void *arg2)
|
||||||
{
|
{
|
||||||
uint8_t rcv_byte;
|
uint8_t rcv_byte;
|
||||||
|
|
||||||
rcv_byte = MCF_PSC3_PSCRB_8BIT;
|
rcv_byte = MCF_PSC3_PSCRB_8BIT;
|
||||||
if (rcv_byte == 2) // PIC requests RTC data
|
if (rcv_byte == 2) // PIC requests RTC data
|
||||||
{
|
{
|
||||||
uint8_t *rtc_reg = (uint8_t *) 0xffff8961;
|
uint8_t *rtc_reg = (uint8_t *) 0xffff8961;
|
||||||
uint8_t *rtc_data = (uint8_t *) 0xffff8963;
|
uint8_t *rtc_data = (uint8_t *) 0xffff8963;
|
||||||
int index = 0;
|
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
|
MCF_PSC3_PSCTB_8BIT = 0x82; // header byte to PIC
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
*rtc_reg = 0;
|
*rtc_reg = 0;
|
||||||
MCF_PSC3_PSCTB_8BIT = *rtc_data;
|
MCF_PSC3_PSCTB_8BIT = *rtc_data;
|
||||||
} while (index++ < 64);
|
} while (index++ < 64);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int32_t video_sbt;
|
extern int32_t video_sbt;
|
||||||
@@ -241,93 +241,93 @@ extern int32_t video_tlb;
|
|||||||
|
|
||||||
void video_addr_timeout(void)
|
void video_addr_timeout(void)
|
||||||
{
|
{
|
||||||
uint32_t addr = 0x0L;
|
uint32_t addr = 0x0L;
|
||||||
uint32_t *src;
|
uint32_t *src;
|
||||||
uint32_t *dst;
|
uint32_t *dst;
|
||||||
uint32_t asid;
|
uint32_t asid;
|
||||||
|
|
||||||
dbg("video address timeout\r\n");
|
dbg("video address timeout\r\n");
|
||||||
flush_and_invalidate_caches();
|
flush_and_invalidate_caches();
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
uint32_t tlb;
|
uint32_t tlb;
|
||||||
uint32_t page_attr;
|
uint32_t page_attr;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* search tlb entry id for addr (if not available, the MMU
|
* search tlb entry id for addr (if not available, the MMU
|
||||||
* will provide a new one based on its LRU algorithm)
|
* will provide a new one based on its LRU algorithm)
|
||||||
*/
|
*/
|
||||||
MCF_MMU_MMUAR = addr;
|
MCF_MMU_MMUAR = addr;
|
||||||
MCF_MMU_MMUOR =
|
MCF_MMU_MMUOR =
|
||||||
MCF_MMU_MMUOR_STLB |
|
MCF_MMU_MMUOR_STLB |
|
||||||
MCF_MMU_MMUOR_RW |
|
MCF_MMU_MMUOR_RW |
|
||||||
MCF_MMU_MMUOR_ACC;
|
MCF_MMU_MMUOR_ACC;
|
||||||
NOP();
|
NOP();
|
||||||
tlb = (MCF_MMU_MMUOR >> 16) & 0xffff;
|
tlb = (MCF_MMU_MMUOR >> 16) & 0xffff;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* retrieve tlb entry with the found TLB entry id
|
* retrieve tlb entry with the found TLB entry id
|
||||||
*/
|
*/
|
||||||
MCF_MMU_MMUAR = tlb;
|
MCF_MMU_MMUAR = tlb;
|
||||||
MCF_MMU_MMUOR =
|
MCF_MMU_MMUOR =
|
||||||
MCF_MMU_MMUOR_STLB |
|
MCF_MMU_MMUOR_STLB |
|
||||||
MCF_MMU_MMUOR_ADR |
|
MCF_MMU_MMUOR_ADR |
|
||||||
MCF_MMU_MMUOR_RW |
|
MCF_MMU_MMUOR_RW |
|
||||||
MCF_MMU_MMUOR_ACC;
|
MCF_MMU_MMUOR_ACC;
|
||||||
NOP();
|
NOP();
|
||||||
|
|
||||||
asid = (MCF_MMU_MMUTR >> 2) & 0x1fff; /* fetch ASID of page */;
|
asid = (MCF_MMU_MMUTR >> 2) & 0x1fff; /* fetch ASID of page */;
|
||||||
if (asid != sca_page_ID) /* check if screen area */
|
if (asid != sca_page_ID) /* check if screen area */
|
||||||
{
|
{
|
||||||
addr += 0x100000;
|
addr += 0x100000;
|
||||||
continue; /* next page */
|
continue; /* next page */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* modify found TLB entry */
|
/* modify found TLB entry */
|
||||||
if (addr == 0x0)
|
if (addr == 0x0)
|
||||||
{
|
{
|
||||||
page_attr =
|
page_attr =
|
||||||
MCF_MMU_MMUDR_LK |
|
MCF_MMU_MMUDR_LK |
|
||||||
MCF_MMU_MMUDR_SZ(0) |
|
MCF_MMU_MMUDR_SZ(0) |
|
||||||
MCF_MMU_MMUDR_CM(0) |
|
MCF_MMU_MMUDR_CM(0) |
|
||||||
MCF_MMU_MMUDR_R |
|
MCF_MMU_MMUDR_R |
|
||||||
MCF_MMU_MMUDR_W |
|
MCF_MMU_MMUDR_W |
|
||||||
MCF_MMU_MMUDR_X;
|
MCF_MMU_MMUDR_X;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
page_attr =
|
page_attr =
|
||||||
MCF_MMU_MMUTR_SG |
|
MCF_MMU_MMUTR_SG |
|
||||||
MCF_MMU_MMUTR_V;
|
MCF_MMU_MMUTR_V;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MCF_MMU_MMUTR = addr;
|
MCF_MMU_MMUTR = addr;
|
||||||
MCF_MMU_MMUDR = page_attr;
|
MCF_MMU_MMUDR = page_attr;
|
||||||
MCF_MMU_MMUOR =
|
MCF_MMU_MMUOR =
|
||||||
MCF_MMU_MMUOR_STLB |
|
MCF_MMU_MMUOR_STLB |
|
||||||
MCF_MMU_MMUOR_ADR |
|
MCF_MMU_MMUOR_ADR |
|
||||||
MCF_MMU_MMUOR_ACC |
|
MCF_MMU_MMUOR_ACC |
|
||||||
MCF_MMU_MMUOR_UAA;
|
MCF_MMU_MMUOR_UAA;
|
||||||
NOP();
|
NOP();
|
||||||
|
|
||||||
dst = (uint32_t *) 0x60000000 + addr;
|
dst = (uint32_t *) 0x60000000 + addr;
|
||||||
src = (uint32_t *) addr;
|
src = (uint32_t *) addr;
|
||||||
while (dst < (uint32_t *) 0x60000000 + addr + 0x10000)
|
while (dst < (uint32_t *) 0x60000000 + addr + 0x10000)
|
||||||
{
|
{
|
||||||
*dst++ = *src++;
|
*dst++ = *src++;
|
||||||
*dst++ = *src++;
|
*dst++ = *src++;
|
||||||
*dst++ = *src++;
|
*dst++ = *src++;
|
||||||
*dst++ = *src++;
|
*dst++ = *src++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
addr += 0x100000;
|
addr += 0x100000;
|
||||||
} while (addr < 0xd00000);
|
} while (addr < 0xd00000);
|
||||||
video_tlb = 0x2000;
|
video_tlb = 0x2000;
|
||||||
video_sbt = 0;
|
video_sbt = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -336,16 +336,16 @@ void video_addr_timeout(void)
|
|||||||
*/
|
*/
|
||||||
void blink_led(void)
|
void blink_led(void)
|
||||||
{
|
{
|
||||||
static uint16_t blinker = 0;
|
static uint16_t blinker = 0;
|
||||||
|
|
||||||
if ((blinker++ & 0x80) > 0)
|
if ((blinker++ & 0x80) > 0)
|
||||||
{
|
{
|
||||||
MCF_GPIO_PODR_FEC1L |= (1 << 4); /* LED off */
|
MCF_GPIO_PODR_FEC1L |= (1 << 4); /* LED off */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MCF_GPIO_PODR_FEC1L &= ~(1 << 4); /* LED on */
|
MCF_GPIO_PODR_FEC1L &= ~(1 << 4); /* LED on */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -363,47 +363,47 @@ void blink_led(void)
|
|||||||
|
|
||||||
bool irq6_acsi_dma_interrupt(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 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)
|
if (video_sbt != 0 && (video_sbt - 0x70000000) > MCF_SLT0_SCNT)
|
||||||
{
|
{
|
||||||
video_addr_timeout();
|
video_addr_timeout();
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* check if ACSI DMA interrupt
|
* check if ACSI DMA interrupt
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (FALCON_MFP_IERA & (1 << 7))
|
if (FALCON_MFP_IERA & (1 << 7))
|
||||||
{
|
{
|
||||||
/* ACSI interrupt is enabled */
|
/* ACSI interrupt is enabled */
|
||||||
if (FALCON_MFP_IPRA & (1 << 7))
|
if (FALCON_MFP_IPRA & (1 << 7))
|
||||||
{
|
{
|
||||||
irq6_acsi_dma_interrupt();
|
irq6_acsi_dma_interrupt();
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FALCON_MFP_IPRA || FALCON_MFP_IPRB)
|
if (FALCON_MFP_IPRA || FALCON_MFP_IPRB)
|
||||||
{
|
{
|
||||||
blink_led();
|
blink_led();
|
||||||
}
|
}
|
||||||
|
|
||||||
return handled;
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(MACHINE_FIREBEE)
|
#if defined(MACHINE_FIREBEE)
|
||||||
@@ -430,112 +430,10 @@ bool irq6_interrupt_handler(uint32_t sf1, uint32_t sf2)
|
|||||||
*/
|
*/
|
||||||
void gpt0_interrupt_handler(void)
|
void gpt0_interrupt_handler(void)
|
||||||
{
|
{
|
||||||
uint32_t video_address;
|
dbg("screen base = 0x%x\r\n", vbasehi);
|
||||||
uint32_t video_end_address;
|
|
||||||
int page_number;
|
|
||||||
bool already_set;
|
|
||||||
extern uint32_t _STRAM_END;
|
|
||||||
|
|
||||||
dbg("screen base = 0x%x\r\n", vbasehi);
|
MCF_GPT0_GMS &= ~1; /* rearm trigger */
|
||||||
|
NOP();
|
||||||
if (vbasehi < 2) /* screen base lower than 0x20000? */
|
MCF_GPT0_GMS |= 1;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
#endif /* MACHINE_FIREBEE */
|
#endif /* MACHINE_FIREBEE */
|
||||||
|
|||||||
771
sys/mmu.c
771
sys/mmu.c
@@ -1,5 +1,6 @@
|
|||||||
#include "mmu.h"
|
#include "mmu.h"
|
||||||
#include "acia.h"
|
#include "acia.h"
|
||||||
|
#include "exceptions.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* mmu.c
|
* mmu.c
|
||||||
@@ -62,12 +63,14 @@
|
|||||||
#error "unknown machine!"
|
#error "unknown machine!"
|
||||||
#endif /* MACHINE_FIREBEE */
|
#endif /* MACHINE_FIREBEE */
|
||||||
|
|
||||||
// #define DEBUG_MMU
|
//#define DBG_MMU
|
||||||
#ifdef DEBUG_MMU
|
#ifdef DBG_MMU
|
||||||
#define dbg(format, arg...) do { xprintf("DEBUG (%s()): " format, __FUNCTION__, ##arg);} while(0)
|
#define dbg(format, arg...) do { xprintf("DEBUG (%s()): " format, __FUNCTION__, ##arg);} while(0)
|
||||||
#else
|
#else
|
||||||
#define dbg(format, arg...) do {;} while (0)
|
#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
|
* set ASID register
|
||||||
@@ -75,19 +78,19 @@
|
|||||||
*/
|
*/
|
||||||
inline uint32_t set_asid(uint32_t value)
|
inline uint32_t set_asid(uint32_t value)
|
||||||
{
|
{
|
||||||
extern long rt_asid;
|
extern long rt_asid;
|
||||||
uint32_t ret = rt_asid;
|
uint32_t ret = rt_asid;
|
||||||
|
|
||||||
__asm__ __volatile__(
|
__asm__ __volatile__(
|
||||||
"movec %[value],ASID\n\t"
|
"movec %[value],ASID\n\t"
|
||||||
: /* no output */
|
: /* no output */
|
||||||
: [value] "r" (value)
|
: [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)
|
inline uint32_t set_acr0(uint32_t value)
|
||||||
{
|
{
|
||||||
extern uint32_t rt_acr0;
|
extern uint32_t rt_acr0;
|
||||||
uint32_t ret = rt_acr0;
|
uint32_t ret = rt_acr0;
|
||||||
|
|
||||||
__asm__ __volatile__(
|
__asm__ __volatile__(
|
||||||
"movec %[value],ACR0\n\t"
|
"movec %[value],ACR0\n\t"
|
||||||
: /* not output */
|
: /* not output */
|
||||||
: [value] "r" (value)
|
: [value] "r" (value)
|
||||||
:
|
: "memory"
|
||||||
);
|
);
|
||||||
rt_acr0 = value;
|
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)
|
inline uint32_t set_acr1(uint32_t value)
|
||||||
{
|
{
|
||||||
extern uint32_t rt_acr1;
|
extern uint32_t rt_acr1;
|
||||||
uint32_t ret = rt_acr1;
|
uint32_t ret = rt_acr1;
|
||||||
|
|
||||||
__asm__ __volatile__(
|
__asm__ __volatile__(
|
||||||
"movec %[value],ACR1\n\t"
|
"movec %[value],ACR1\n\t"
|
||||||
: /* not output */
|
: /* not output */
|
||||||
: [value] "r" (value)
|
: [value] "r" (value)
|
||||||
:
|
: "memory"
|
||||||
);
|
);
|
||||||
rt_acr1 = value;
|
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)
|
inline uint32_t set_acr2(uint32_t value)
|
||||||
{
|
{
|
||||||
extern uint32_t rt_acr2;
|
extern uint32_t rt_acr2;
|
||||||
uint32_t ret = rt_acr2;
|
uint32_t ret = rt_acr2;
|
||||||
|
|
||||||
__asm__ __volatile__(
|
__asm__ __volatile__(
|
||||||
"movec %[value],ACR2\n\t"
|
"movec %[value],ACR2\n\t"
|
||||||
: /* not output */
|
: /* not output */
|
||||||
: [value] "r" (value)
|
: [value] "r" (value)
|
||||||
:
|
: "memory"
|
||||||
);
|
);
|
||||||
rt_acr2 = value;
|
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)
|
inline uint32_t set_acr3(uint32_t value)
|
||||||
{
|
{
|
||||||
extern uint32_t rt_acr3;
|
extern uint32_t rt_acr3;
|
||||||
uint32_t ret = rt_acr3;
|
uint32_t ret = rt_acr3;
|
||||||
|
|
||||||
__asm__ __volatile__(
|
__asm__ __volatile__(
|
||||||
"movec %[value],ACR3\n\t"
|
"movec %[value],ACR3\n\t"
|
||||||
: /* not output */
|
: /* not output */
|
||||||
: [value] "r" (value)
|
: [value] "r" (value)
|
||||||
:
|
: "memory"
|
||||||
);
|
);
|
||||||
rt_acr3 = value;
|
rt_acr3 = value;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint32_t set_mmubar(uint32_t value)
|
inline uint32_t set_mmubar(uint32_t value)
|
||||||
{
|
{
|
||||||
extern uint32_t rt_mmubar;
|
extern uint32_t rt_mmubar;
|
||||||
uint32_t ret = rt_mmubar;
|
uint32_t ret = rt_mmubar;
|
||||||
|
|
||||||
__asm__ __volatile__(
|
__asm__ __volatile__(
|
||||||
"movec %[value],MMUBAR\n\t"
|
"movec %[value],MMUBAR\n\t"
|
||||||
: /* no output */
|
: /* no output */
|
||||||
: [value] "r" (value)
|
: [value] "r" (value)
|
||||||
: /* no clobber */
|
: "memory"
|
||||||
);
|
);
|
||||||
rt_mmubar = value;
|
rt_mmubar = value;
|
||||||
NOP();
|
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)
|
switch (sz)
|
||||||
{
|
{
|
||||||
case MMU_PAGE_SIZE_1M:
|
case MMU_PAGE_SIZE_1M:
|
||||||
size_mask = 0xfff00000;
|
size_mask = ~ (0x00010000 - 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MMU_PAGE_SIZE_8K:
|
case MMU_PAGE_SIZE_8K:
|
||||||
size_mask = 0xffffe000;
|
size_mask = ~ (0x2000 - 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MMU_PAGE_SIZE_4K:
|
case MMU_PAGE_SIZE_4K:
|
||||||
size_mask = 0xfffff000;
|
size_mask = ~ (0x1000 - 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MMU_PAGE_SIZE_1K:
|
case MMU_PAGE_SIZE_1K:
|
||||||
size_mask = 0xfffff800;
|
size_mask = ~ (0x400 - 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
dbg("illegal map size %d\r\n", sz);
|
err("illegal map size %d\r\n", sz);
|
||||||
return 0;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* add page to TLB
|
* 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();
|
|
||||||
|
|
||||||
MCF_MMU_MMUDR = ((int) phys & size_mask) | /* physical address */
|
ipl = set_ipl(7);
|
||||||
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();
|
|
||||||
|
|
||||||
MCF_MMU_MMUOR = MCF_MMU_MMUOR_ACC | /* access TLB, data */
|
MCF_MMU_MMUTR = ((uint32_t) virt & size_mask) | /* virtual address */
|
||||||
MCF_MMU_MMUOR_UAA; /* update allocation address field */
|
MCF_MMU_MMUTR_ID(page_id) | /* address space id (ASID) */
|
||||||
NOP();
|
(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_MMUDR = ((uint32_t) phys & size_mask) | /* physical address */
|
||||||
MCF_MMU_MMUOR_ACC | /* access TLB */
|
MCF_MMU_MMUDR_SZ(sz) | /* page size */
|
||||||
MCF_MMU_MMUOR_UAA; /* update allocation address field */
|
MCF_MMU_MMUDR_CM(flags->cache_mode) |
|
||||||
dbg("mapped virt=0x%08x to phys=0x%08x\r\n", virt, phys);
|
(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)
|
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];
|
* clear all MMU TLB entries first
|
||||||
extern uint8_t _TOS[];
|
*/
|
||||||
uint32_t TOS = (uint32_t) &_TOS[0];
|
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 */
|
if (addr >= 0x00f00000 && addr < 0x00ffffff)
|
||||||
set_acr0(ACR_W(0) | /* read and write accesses permitted */
|
{
|
||||||
ACR_SP(0) | /* supervisor and user mode access permitted */
|
pages[i].cache_mode = CACHE_NOCACHE_PRECISE;
|
||||||
ACR_CM(ACR_CM_CACHE_INH_PRECISE) | /* cache inhibit, precise */
|
pages[i].execute = 0;
|
||||||
ACR_AMM(0) | /* control region > 16 MB */
|
pages[i].read = 1;
|
||||||
ACR_S(ACR_S_ALL) | /* match addresses in user and supervisor mode */
|
pages[i].write = 1;
|
||||||
ACR_E(1) | /* enable ACR */
|
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)
|
#if defined(MACHINE_FIREBEE)
|
||||||
ACR_ADMSK(0x7f) | /* cover 2GB area from 0x80000000 to 0xffffffff */
|
ACR_ADMSK(0x7f) | /* cover 2GB area from 0x80000000 to 0xffffffff */
|
||||||
ACR_BA(0x80000000)); /* (equals area from 3 to 4 GB */
|
ACR_BA(0x80000000)); /* (equals area from 3 to 4 GB */
|
||||||
#elif defined(MACHINE_M5484LITE)
|
#elif defined(MACHINE_M5484LITE)
|
||||||
ACR_ADMSK(0x7f) | /* cover 2 GB area from 0x80000000 to 0xffffffff */
|
ACR_ADMSK(0x7f) | /* cover 2 GB area from 0x80000000 to 0xffffffff */
|
||||||
ACR_BA(0x80000000));
|
ACR_BA(0x80000000));
|
||||||
#elif defined(MACHINE_M54455)
|
#elif defined(MACHINE_M54455)
|
||||||
ACR_ADMSK(0x7f) |
|
ACR_ADMSK(0x7f) |
|
||||||
ACR_BA(0x80000000)); /* FIXME: not determined yet */
|
ACR_BA(0x80000000)); /* FIXME: not determined yet for this machine */
|
||||||
#else
|
#else
|
||||||
#error unknown machine!
|
#error unknown machine!
|
||||||
#endif /* MACHINE_FIREBEE */
|
#endif /* MACHINE_FIREBEE */
|
||||||
|
|
||||||
// set_acr1(0x601fc000);
|
|
||||||
set_acr1(ACR_W(0) |
|
|
||||||
ACR_SP(0) |
|
// set_acr1(0x601fc000);
|
||||||
ACR_CM(0) |
|
set_acr1(ACR_W(0) |
|
||||||
|
ACR_SP(0) |
|
||||||
|
ACR_CM(0) |
|
||||||
#if defined(MACHINE_FIREBEE)
|
#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)
|
#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)
|
#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
|
#else
|
||||||
#error unknown machine!
|
#error unknown machine!
|
||||||
#endif /* MACHINE_FIREBEE */
|
#endif /* MACHINE_FIREBEE */
|
||||||
ACR_AMM(0) |
|
ACR_AMM(0) |
|
||||||
ACR_S(ACR_S_ALL) |
|
ACR_S(ACR_S_ALL) |
|
||||||
ACR_E(1) |
|
ACR_E(1) |
|
||||||
ACR_ADMSK(0x1f) |
|
ACR_ADMSK(0x7f) |
|
||||||
ACR_BA(0x60000000));
|
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(0xe007c400); /* flash area */
|
||||||
set_acr2(ACR_W(0) |
|
set_acr2(ACR_W(0) |
|
||||||
ACR_SP(0) |
|
ACR_SP(0) |
|
||||||
ACR_CM(0) |
|
ACR_CM(0) |
|
||||||
ACR_CM(ACR_CM_CACHEABLE_WT) |
|
ACR_CM(ACR_CM_CACHE_INH_PRECISE) |
|
||||||
ACR_AMM(1) |
|
ACR_AMM(1) |
|
||||||
ACR_S(ACR_S_ALL) |
|
ACR_S(ACR_S_ALL) |
|
||||||
ACR_E(1) |
|
ACR_E(1) |
|
||||||
ACR_ADMSK(0x7) |
|
ACR_ADMSK(0x7) |
|
||||||
ACR_BA(0xe0000000));
|
ACR_BA(0xe0000000));
|
||||||
|
#endif /* _NOT_USED_ */
|
||||||
|
|
||||||
/* disable ACR3 */
|
set_acr1(0x0);
|
||||||
set_acr3(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 */
|
/* clear all MMU TLB entries */
|
||||||
MCF_MMU_MMUOR = MCF_MMU_MMUOR_CA;
|
MCF_MMU_MMUOR = MCF_MMU_MMUOR_CA;
|
||||||
|
|
||||||
/* create locked TLB entries */
|
/* create locked TLB entries */
|
||||||
|
|
||||||
flags.cache_mode = CACHE_COPYBACK;
|
/*
|
||||||
flags.protection = SV_USER;
|
* Map (locked) the second last MB of physical SDRAM (this is where BaS .data and .bss reside) to the same
|
||||||
flags.page_id = 0;
|
* virtual address. This is also used (completely) when BaS is in RAM
|
||||||
flags.access = ACCESS_READ | ACCESS_WRITE | ACCESS_EXECUTE;
|
*/
|
||||||
flags.locked = true;
|
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)
|
/*
|
||||||
/*
|
* Map (locked) the very last MB of physical SDRAM (this is where the driver buffers reside) to the same
|
||||||
* 0x00d0'0000 - 0x00df'ffff (last megabyte of ST RAM = Falcon video memory) locked ID = 6
|
* virtual address. Used uncached for drivers.
|
||||||
* mapped to physical address 0x60d0'0000 (FPGA video memory)
|
*/
|
||||||
* video RAM: read write execute normal write true
|
flags.cache_mode = CACHE_NOCACHE_PRECISE;
|
||||||
*/
|
flags.read = 1;
|
||||||
flags.cache_mode = CACHE_WRITETHROUGH;
|
flags.write = 1;
|
||||||
flags.protection = SV_USER;
|
flags.execute = 0;
|
||||||
flags.page_id = SCA_PAGE_ID;
|
flags.supervisor_protect = 1;
|
||||||
flags.access = ACCESS_READ | ACCESS_WRITE | ACCESS_EXECUTE;
|
flags.locked = 1;
|
||||||
flags.locked = true;
|
mmu_map_page(SDRAM_START + SDRAM_SIZE - 0x00100000, SDRAM_START + SDRAM_SIZE - 0x00100000, 0, MMU_PAGE_SIZE_1M, &flags);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
MCF_MMU_MMUCR = MCF_MMU_MMUCR_EN; /* MMU on */
|
||||||
.protection = SV_USER,
|
NOP(); /* force pipeline sync */
|
||||||
.page_id = 0,
|
}
|
||||||
.access = ACCESS_READ | ACCESS_WRITE | ACCESS_EXECUTE,
|
|
||||||
.locked = false
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
/* retrieve mapped page from MMU and make sure everything is correct */
|
||||||
// flush_and_invalidate_caches();
|
int ds;
|
||||||
|
|
||||||
switch (address)
|
ds = * (int *) address;
|
||||||
{
|
dbg("found 0x%08x at address\r\n", ds);
|
||||||
case keyctl:
|
}
|
||||||
case keybd:
|
#endif /* DBG_MMU */
|
||||||
/* do something to emulate the IKBD access */
|
|
||||||
dbg("IKBD access\r\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case midictl:
|
uint32_t mmutr_miss(uint32_t mmu_sr, uint32_t fault_address, uint32_t pc,
|
||||||
case midi:
|
uint32_t format_status)
|
||||||
/* do something to emulate MIDI access */
|
{
|
||||||
dbg("MIDI ACIA access\r\n");
|
uint32_t fault = format_status & 0x0c030000;
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
switch (fault)
|
||||||
/* add missed page to TLB */
|
{
|
||||||
mmu_map_page(address, address, MMU_PAGE_SIZE_1M, &flags);
|
/* if we have a real TLB miss, map the offending page */
|
||||||
dbg("DTLB: MCF_MMU_MMUOR = %08x\r\n", MCF_MMU_MMUOR);
|
|
||||||
dbg("ITLB: MCF_MMU_MMUOR = %08x\r\n\r\n", MCF_MMU_MMUOR);
|
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 */
|
/* set stack pointer to end of SRAM */
|
||||||
lea __SUP_SP,a7
|
lea __SUP_SP,a7
|
||||||
move.l #0,(sp)
|
move.l #0,(sp)
|
||||||
|
subq.l #4,sp
|
||||||
|
move.l #0,(sp)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the processor caches.
|
* Initialize the processor caches.
|
||||||
|
|||||||
@@ -61,148 +61,153 @@ static char snil[] = "(nil)";
|
|||||||
|
|
||||||
void xputchar(int c)
|
void xputchar(int c)
|
||||||
{
|
{
|
||||||
__asm__ __volatile__
|
__asm__ __volatile__
|
||||||
(
|
(
|
||||||
".extern printf_helper\n\t"
|
" .extern __MBAR \n\t"
|
||||||
"move.b %0,d0\n\t"
|
" move.b %0,d0 \n\t"
|
||||||
"bsr printf_helper\n\t"
|
".wait_txready: \n\t"
|
||||||
/* output */:
|
" move.w __MBAR + 0x8604,d2 \n\t" // PSCSCR0 status register
|
||||||
/* input */: "r" (c)
|
" btst #10,d2 \n\t" // space left in TX fifo?
|
||||||
/* clobber */: "d0","d2","a0","memory"
|
" 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)
|
static void doprnt(void (*addchar)(int), const char *sfmt, va_list ap)
|
||||||
{
|
{
|
||||||
char buf[128];
|
char buf[128];
|
||||||
char *bp;
|
char *bp;
|
||||||
const char *f;
|
const char *f;
|
||||||
float flt;
|
float flt;
|
||||||
long l;
|
long l;
|
||||||
unsigned long u;
|
unsigned long u;
|
||||||
int i;
|
int i;
|
||||||
int fmt;
|
int fmt;
|
||||||
unsigned char pad = ' ';
|
unsigned char pad = ' ';
|
||||||
int flush_left = 0;
|
int flush_left = 0;
|
||||||
int f_width = 0;
|
int f_width = 0;
|
||||||
int prec = INF;
|
int prec = INF;
|
||||||
int hash = 0;
|
int hash = 0;
|
||||||
int do_long = 0;
|
int do_long = 0;
|
||||||
int sign = 0;
|
int sign = 0;
|
||||||
int attributes = 0;
|
int attributes = 0;
|
||||||
|
|
||||||
f = sfmt;
|
f = sfmt;
|
||||||
for (; *f; f++)
|
for (; *f; f++)
|
||||||
{
|
{
|
||||||
if (*f != '%')
|
if (*f != '%')
|
||||||
{
|
{
|
||||||
/* then just out the char */
|
/* then just out the char */
|
||||||
(*addchar)((int) (((unsigned char) *f) | attributes));
|
(*addchar)((int) (((unsigned char) *f) | attributes));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
f++; /* skip the % */
|
f++; /* skip the % */
|
||||||
|
|
||||||
if (*f == '-')
|
if (*f == '-')
|
||||||
{ /* minus: flush left */
|
{ /* minus: flush left */
|
||||||
flush_left = 1;
|
flush_left = 1;
|
||||||
f++;
|
f++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*f == '0' || *f == '.')
|
if (*f == '0' || *f == '.')
|
||||||
{
|
{
|
||||||
/* padding with 0 rather than blank */
|
/* padding with 0 rather than blank */
|
||||||
pad = '0';
|
pad = '0';
|
||||||
f++;
|
f++;
|
||||||
}
|
}
|
||||||
if (*f == '*')
|
if (*f == '*')
|
||||||
{
|
{
|
||||||
/* field width */
|
/* field width */
|
||||||
f_width = va_arg(ap, int);
|
f_width = va_arg(ap, int);
|
||||||
f++;
|
f++;
|
||||||
}
|
}
|
||||||
else if (isdigit((unsigned char)*f))
|
else if (isdigit((unsigned char)*f))
|
||||||
{
|
{
|
||||||
f_width = atoi(f);
|
f_width = atoi(f);
|
||||||
while (isdigit((unsigned char)*f))
|
while (isdigit((unsigned char)*f))
|
||||||
f++; /* skip the digits */
|
f++; /* skip the digits */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*f == '.')
|
if (*f == '.')
|
||||||
{ /* precision */
|
{ /* precision */
|
||||||
f++;
|
f++;
|
||||||
if (*f == '*')
|
if (*f == '*')
|
||||||
{
|
{
|
||||||
prec = va_arg(ap, int);
|
prec = va_arg(ap, int);
|
||||||
f++;
|
f++;
|
||||||
}
|
}
|
||||||
else if (isdigit((unsigned char)*f))
|
else if (isdigit((unsigned char)*f))
|
||||||
{
|
{
|
||||||
prec = atoi(f);
|
prec = atoi(f);
|
||||||
while (isdigit((unsigned char)*f))
|
while (isdigit((unsigned char)*f))
|
||||||
f++; /* skip the digits */
|
f++; /* skip the digits */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*f == '#')
|
if (*f == '#')
|
||||||
{ /* alternate form */
|
{ /* alternate form */
|
||||||
hash = 1;
|
hash = 1;
|
||||||
f++;
|
f++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*f == 'l')
|
if (*f == 'l')
|
||||||
{ /* long format */
|
{ /* long format */
|
||||||
do_long++;
|
do_long++;
|
||||||
f++;
|
f++;
|
||||||
if (*f == 'l')
|
if (*f == 'l')
|
||||||
{
|
{
|
||||||
do_long++;
|
do_long++;
|
||||||
f++;
|
f++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt = (unsigned char) *f;
|
fmt = (unsigned char) *f;
|
||||||
if (fmt != 'S' && fmt != 'Q' && isupper(fmt))
|
if (fmt != 'S' && fmt != 'Q' && isupper(fmt))
|
||||||
{
|
{
|
||||||
do_long = 1;
|
do_long = 1;
|
||||||
fmt = tolower(fmt);
|
fmt = tolower(fmt);
|
||||||
}
|
}
|
||||||
bp = buf;
|
bp = buf;
|
||||||
switch (fmt)
|
switch (fmt)
|
||||||
{ /* do the format */
|
{ /* do the format */
|
||||||
case 'd':
|
case 'd':
|
||||||
switch (do_long)
|
switch (do_long)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
l = (long) (va_arg(ap, int));
|
l = (long) (va_arg(ap, int));
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
default:
|
default:
|
||||||
l = va_arg(ap, long);
|
l = va_arg(ap, long);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (l < 0)
|
if (l < 0)
|
||||||
{
|
{
|
||||||
sign = 1;
|
sign = 1;
|
||||||
l = -l;
|
l = -l;
|
||||||
}
|
}
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
*bp++ = (char) (l % 10) + '0';
|
*bp++ = (char) (l % 10) + '0';
|
||||||
} while ((l /= 10) > 0);
|
} while ((l /= 10) > 0);
|
||||||
if (sign)
|
if (sign)
|
||||||
*bp++ = '-';
|
*bp++ = '-';
|
||||||
f_width = f_width - (int) (bp - buf);
|
f_width = f_width - (int) (bp - buf);
|
||||||
if (!flush_left)
|
if (!flush_left)
|
||||||
while (f_width-- > 0)
|
while (f_width-- > 0)
|
||||||
(*addchar)((int) (pad | attributes));
|
(*addchar)((int) (pad | attributes));
|
||||||
for (bp--; bp >= buf; bp--)
|
for (bp--; bp >= buf; bp--)
|
||||||
(*addchar)((int) (((unsigned char) *bp) | attributes));
|
(*addchar)((int) (((unsigned char) *bp) | attributes));
|
||||||
if (flush_left)
|
if (flush_left)
|
||||||
while (f_width-- > 0)
|
while (f_width-- > 0)
|
||||||
(*addchar)((int) (' ' | attributes));
|
(*addchar)((int) (' ' | attributes));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'f':
|
case 'f':
|
||||||
/* this is actually more than stupid, but does work for now */
|
/* 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;
|
break;
|
||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
do_long = 1;
|
do_long = 1;
|
||||||
hash = 1;
|
hash = 1;
|
||||||
fmt = 'x';
|
fmt = 'x';
|
||||||
/* no break */
|
/* no break */
|
||||||
case 'o':
|
case 'o':
|
||||||
case 'x':
|
case 'x':
|
||||||
case 'u':
|
case 'u':
|
||||||
switch (do_long)
|
switch (do_long)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
u = (unsigned long) (va_arg(ap, unsigned int));
|
u = (unsigned long) (va_arg(ap, unsigned int));
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
default:
|
default:
|
||||||
u = va_arg(ap, unsigned long);
|
u = va_arg(ap, unsigned long);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (fmt == 'u')
|
if (fmt == 'u')
|
||||||
{ /* unsigned decimal */
|
{ /* unsigned decimal */
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
*bp++ = (char) (u % 10) + '0';
|
*bp++ = (char) (u % 10) + '0';
|
||||||
} while ((u /= 10) > 0);
|
} while ((u /= 10) > 0);
|
||||||
}
|
}
|
||||||
else if (fmt == 'o')
|
else if (fmt == 'o')
|
||||||
{ /* octal */
|
{ /* octal */
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
*bp++ = (char) (u % 8) + '0';
|
*bp++ = (char) (u % 8) + '0';
|
||||||
} while ((u /= 8) > 0);
|
} while ((u /= 8) > 0);
|
||||||
if (hash)
|
if (hash)
|
||||||
*bp++ = '0';
|
*bp++ = '0';
|
||||||
}
|
}
|
||||||
else if (fmt == 'x')
|
else if (fmt == 'x')
|
||||||
{ /* hex */
|
{ /* hex */
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
i = (int) (u % 16);
|
i = (int) (u % 16);
|
||||||
if (i < 10)
|
if (i < 10)
|
||||||
*bp++ = i + '0';
|
*bp++ = i + '0';
|
||||||
else
|
else
|
||||||
*bp++ = i - 10 + 'a';
|
*bp++ = i - 10 + 'a';
|
||||||
} while ((u /= 16) > 0);
|
} while ((u /= 16) > 0);
|
||||||
if (hash)
|
if (hash)
|
||||||
{
|
{
|
||||||
*bp++ = 'x';
|
*bp++ = 'x';
|
||||||
*bp++ = '0';
|
*bp++ = '0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i = f_width - (int) (bp - buf);
|
i = f_width - (int) (bp - buf);
|
||||||
if (!flush_left)
|
if (!flush_left)
|
||||||
while (i-- > 0)
|
while (i-- > 0)
|
||||||
(*addchar)((int) (pad | attributes));
|
(*addchar)((int) (pad | attributes));
|
||||||
for (bp--; bp >= buf; bp--)
|
for (bp--; bp >= buf; bp--)
|
||||||
(*addchar)((int) (((unsigned char) *bp) | attributes));
|
(*addchar)((int) (((unsigned char) *bp) | attributes));
|
||||||
if (flush_left)
|
if (flush_left)
|
||||||
while (i-- > 0)
|
while (i-- > 0)
|
||||||
(*addchar)((int) (' ' | attributes));
|
(*addchar)((int) (' ' | attributes));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'c':
|
case 'c':
|
||||||
i = va_arg(ap, int);
|
i = va_arg(ap, int);
|
||||||
(*addchar)((int) (i | attributes));
|
(*addchar)((int) (i | attributes));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'S':
|
case 'S':
|
||||||
case 'Q':
|
case 'Q':
|
||||||
case 's':
|
case 's':
|
||||||
case 'q':
|
case 'q':
|
||||||
bp = va_arg(ap, char *);
|
bp = va_arg(ap, char *);
|
||||||
if (!bp)
|
if (!bp)
|
||||||
bp = snil;
|
bp = snil;
|
||||||
f_width = f_width - strlen((char *) bp);
|
f_width = f_width - strlen((char *) bp);
|
||||||
if (!flush_left)
|
if (!flush_left)
|
||||||
while (f_width-- > 0)
|
while (f_width-- > 0)
|
||||||
(*addchar)((int) (pad | attributes));
|
(*addchar)((int) (pad | attributes));
|
||||||
for (i = 0; *bp && i < prec; i++)
|
for (i = 0; *bp && i < prec; i++)
|
||||||
{
|
{
|
||||||
if (fmt == 'q' && (*bp & QUOTE))
|
if (fmt == 'q' && (*bp & QUOTE))
|
||||||
(*addchar)((int) ('\\' | attributes));
|
(*addchar)((int) ('\\' | attributes));
|
||||||
(*addchar)(
|
(*addchar)(
|
||||||
(int) (((unsigned char) *bp & TRIM) | attributes));
|
(int) (((unsigned char) *bp & TRIM) | attributes));
|
||||||
bp++;
|
bp++;
|
||||||
}
|
}
|
||||||
if (flush_left)
|
if (flush_left)
|
||||||
while (f_width-- > 0)
|
while (f_width-- > 0)
|
||||||
(*addchar)((int) (' ' | attributes));
|
(*addchar)((int) (' ' | attributes));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'a':
|
case 'a':
|
||||||
attributes = va_arg(ap, int);
|
attributes = va_arg(ap, int);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '%':
|
case '%':
|
||||||
(*addchar)((int) ('%' | attributes));
|
(*addchar)((int) ('%' | attributes));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0;
|
flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0;
|
||||||
sign = 0;
|
sign = 0;
|
||||||
pad = ' ';
|
pad = ' ';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *xstring, *xestring;
|
static char *xstring, *xestring;
|
||||||
|
|
||||||
void xaddchar(int c)
|
void xaddchar(int c)
|
||||||
{
|
{
|
||||||
if (xestring == xstring)
|
if (xestring == xstring)
|
||||||
*xstring = '\0';
|
*xstring = '\0';
|
||||||
else
|
else
|
||||||
*xstring++ = (char) c;
|
*xstring++ = (char) c;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sprintf(char *str, const char *format, ...)
|
int sprintf(char *str, const char *format, ...)
|
||||||
{
|
{
|
||||||
va_list va;
|
va_list va;
|
||||||
va_start(va, format);
|
va_start(va, format);
|
||||||
|
|
||||||
xstring = str;
|
xstring = str;
|
||||||
|
|
||||||
doprnt(xaddchar, format, va);
|
doprnt(xaddchar, format, va);
|
||||||
va_end(va);
|
va_end(va);
|
||||||
*xstring++ = '\0';
|
*xstring++ = '\0';
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void xsnprintf(char *str, size_t size, const char *fmt, ...)
|
void xsnprintf(char *str, size_t size, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list va;
|
va_list va;
|
||||||
va_start(va, fmt);
|
va_start(va, fmt);
|
||||||
|
|
||||||
xstring = str;
|
xstring = str;
|
||||||
xestring = str + size - 1;
|
xestring = str + size - 1;
|
||||||
doprnt(xaddchar, fmt, va);
|
doprnt(xaddchar, fmt, va);
|
||||||
va_end(va);
|
va_end(va);
|
||||||
*xstring++ = '\0';
|
*xstring++ = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
void xprintf(const char *fmt, ...)
|
void xprintf(const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list va;
|
va_list va;
|
||||||
va_start(va, fmt);
|
va_start(va, fmt);
|
||||||
doprnt(xputchar, fmt, va);
|
doprnt(xputchar, fmt, va);
|
||||||
va_end(va);
|
va_end(va);
|
||||||
}
|
}
|
||||||
|
|
||||||
void xvprintf(const char *fmt, va_list 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)
|
void xvsnprintf(char *str, size_t size, const char *fmt, va_list va)
|
||||||
{
|
{
|
||||||
xstring = str;
|
xstring = str;
|
||||||
xestring = str + size - 1;
|
xestring = str + size - 1;
|
||||||
doprnt(xaddchar, fmt, va);
|
doprnt(xaddchar, fmt, va);
|
||||||
*xstring++ = '\0';
|
*xstring++ = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void display_progress()
|
void display_progress()
|
||||||
{
|
{
|
||||||
static int _progress_index;
|
static int _progress_index;
|
||||||
char progress_char[] = "|/-\\";
|
char progress_char[] = "|/-\\";
|
||||||
|
|
||||||
xputchar(progress_char[_progress_index++ % strlen(progress_char)]);
|
xputchar(progress_char[_progress_index++ % strlen(progress_char)]);
|
||||||
xputchar('\r');
|
xputchar('\r');
|
||||||
}
|
}
|
||||||
|
|
||||||
void hexdump(uint8_t buffer[], int size)
|
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