diff --git a/Bas_gcc_mmu/Makefile b/Bas_gcc_mmu/Makefile index b8556f6..4ea50c2 100644 --- a/Bas_gcc_mmu/Makefile +++ b/Bas_gcc_mmu/Makefile @@ -143,7 +143,6 @@ CSRCS= \ ASRCS= \ startcf.S \ - printf_helper.S \ exceptions.S \ xhdi_vec.S \ pci_wrappers.S diff --git a/Bas_gcc_mmu/include/mmu.h b/Bas_gcc_mmu/include/mmu.h index 3a45c7f..4c1fcd9 100644 --- a/Bas_gcc_mmu/include/mmu.h +++ b/Bas_gcc_mmu/include/mmu.h @@ -92,7 +92,8 @@ enum mmu_cache_modes extern long video_tlb; extern long video_sbt; +extern void mmu_enable(void); extern void mmu_init(void); -extern int mmu_map_8k_page(uint32_t adr); +extern int mmu_map_8k_page(uint32_t adr, uint8_t asid); #endif /* _MMU_H_ */ diff --git a/Bas_gcc_mmu/sys/BaS.c b/Bas_gcc_mmu/sys/BaS.c index 4d0098e..b5979e9 100644 --- a/Bas_gcc_mmu/sys/BaS.c +++ b/Bas_gcc_mmu/sys/BaS.c @@ -307,8 +307,9 @@ void BaS(void) xprintf("finished\r\n"); xprintf("enable MMU: "); - MCF_MMU_MMUCR = MCF_MMU_MMUCR_EN; /* MMU on */ - NOP(); /* force pipeline sync */ + + mmu_enable(); /* force pipeline sync */ + xprintf("finished\r\n"); xprintf("initialize exception vector table: "); @@ -319,7 +320,7 @@ void BaS(void) flush_and_invalidate_caches(); xprintf("finished\r\n"); - #ifdef MACHINE_FIREBEE +#ifdef MACHINE_FIREBEE xprintf("IDE reset: "); /* IDE reset */ * (volatile uint8_t *) (0xffff8802 - 2) = 14; diff --git a/Bas_gcc_mmu/sys/exceptions.S b/Bas_gcc_mmu/sys/exceptions.S index 9c5e88b..8ff1ef3 100644 --- a/Bas_gcc_mmu/sys/exceptions.S +++ b/Bas_gcc_mmu/sys/exceptions.S @@ -45,22 +45,37 @@ .extern _irq5_handler .extern _irq7_handler -/* Register read/write macros */ - -#define MCF_EPORT_EPPAR __MBAR+0xF00 -#define MCF_EPORT_EPDDR __MBAR+0xF04 -#define MCF_EPORT_EPIER __MBAR+0xF05 -#define MCF_EPORT_EPDR __MBAR+0xF08 -#define MCF_EPORT_EPPDR __MBAR+0xF09 -#define MCF_EPORT_EPFR __MBAR+0xF0C - -#define MCF_GPIO_PODR_FEC1L __MBAR+0xA07 - -#define MCF_PSC0_PSCTB_8BIT __MBAR+0x860C - .global _vec_init - // interrupt sources + +/* Register read/write equates */ + + /* MMU */ + .equ MCF_MMU_MMUCR, __MMUBAR + .equ MCF_MMU_MMUOR, __MMUBAR+0x04 + .equ MCF_MMU_MMUSR, __MMUBAR+0x08 + .equ MCF_MMU_MMUAR, __MMUBAR+0x10 + .equ MCF_MMU_MMUTR, __MMUBAR+0x14 + .equ MCF_MMU_MMUDR, __MMUBAR+0x18 + + /* EPORT flag register */ + .equ MCF_EPORT_EPFR, __MBAR+0xf0c + + /* FEC1 port output data direction register */ + .equ MCF_GPIO_PODR_FEC1L, __MBAR+0xa07 + + /* PSC0 transmit buffer register */ + .equ MCF_PSC0_PSCTB_8BIT, __MBAR+0x860c + + /* GPT mode select register */ + .equ MCF_GPT0_GMS, __MBAR+0x800 + + /* Slice timer 0 count register */ + .equ MCF_SLT0_SCNT, __MBAR+0x908 + + +/* interrupt sources */ + .equ INT_SOURCE_EPORT_EPF1,1 // edge port flag 1 .equ INT_SOURCE_EPORT_EPF2,2 // edge port flag 2 .equ INT_SOURCE_EPORT_EPF3,3 // edge port flag 3 @@ -115,82 +130,12 @@ // Atari register equates (provided by FPGA) .equ vbasehi, 0xffff8201 -//mmu --------------------------------------------------- - -/* Register read/write macros */ -#define MCF_MMU_MMUCR __MMUBAR -#define MCF_MMU_MMUOR __MMUBAR + 0x04 -#define MCF_MMU_MMUSR __MMUBAR + 0x08 -#define MCF_MMU_MMUAR __MMUBAR + 0x10 -#define MCF_MMU_MMUTR __MMUBAR + 0x14 -#define MCF_MMU_MMUDR __MMUBAR + 0x18 -/* Bit definitions and macros for MCF_MMU_MMUCR */ -#define MCF_MMU_MMUCR_EN (0x1) -#define MCF_MMU_MMUCR_ASM (0x2) - -/* Bit definitions and macros for MCF_MMU_MMUOR */ -#define MCF_MMU_MMUOR_UAA (0x1) /* update allocation address, i.e. write to TLB */ -#define MCF_MMU_MMUOR_ACC (0x2) /* activate access to TLB */ -#define MCF_MMU_MMUOR_RW (0x4) /* read/write TLB */ -#define MCF_MMU_MMUOR_ADR (0x8) /* search by address/TLB address */ -#define MCF_MMU_MMUOR_ITLB (0x10) /* act on instruction/data TLBs */ -#define MCF_MMU_MMUOR_CAS (0x20) /* clear all unlocked TLBs with matching ASID */ -#define MCF_MMU_MMUOR_CNL (0x40) /* clear all unlocked TLBs regardless of ASID */ -#define MCF_MMU_MMUOR_CA (0x80) /* clear all TLBs */ -#define MCF_MMU_MMUOR_STLB (0x100) /* search TLBs */ -#define MCF_MMU_MMUOR_AA(x) (((x) & 0xFFFF) << 0x10) /* TLB allocation address */ - -/* Bit definitions and macros for MCF_MMU_MMUSR */ -#define MCF_MMU_MMUSR_HIT (0x2) /* last lookup had a hit in TLB */ -#define MCF_MMU_MMUSR_WF (0x8) /* indicate write fault */ -#define MCF_MMU_MMUSR_RF (0x10) /* indicate read fault */ -#define MCF_MMU_MMUSR_SPF (0x20) /* indicate supervisor protect fault */ - -/* Bit definitions and macros for MCF_MMU_MMUAR */ -#define MCF_MMU_MMUAR_FA(x) (((x) & 0xFFFFFFFF) << 0) - -/* Bit definitions and macros for MCF_MMU_MMUTR */ -#define MCF_MMU_MMUTR_V (0x1) /* valid bit for TLB */ -#define MCF_MMU_MMUTR_SG (0x2) /* set page as shared global */ -#define MCF_MMU_MMUTR_ID(x) (((x) & 0xFF) << 0x2) /* ASID (address space id) of page */ -#define MCF_MMU_MMUTR_VA(x) (((x) & 0x3FFFFF) << 0xA) /* virtual address of page */ - -/* Bit definitions and macros for MCF_MMU_MMUDR */ -#define MCF_MMU_MMUDR_LK (0x2) /* lock page */ -#define MCF_MMU_MMUDR_X (0x4) /* allow code execution in memory page */ -#define MCF_MMU_MMUDR_W (0x8) /* allow write to memory page */ -#define MCF_MMU_MMUDR_R (0x10) /* allow read from memory page */ -#define MCF_MMU_MMUDR_SP (0x20) /* supervisor protect memory page */ -#define MCF_MMU_MMUDR_CM(x) (((x) & 0x3) << 0x6) /* cache mode */ -#define MCF_MMU_MMUDR_SZ(x) (((x) & 0x3) << 0x8) /* page size */ -#define MCF_MMU_MMUDR_PA(x) (((x) & 0x3FFFFF) << 0xA) /* page physical address */ - -#define std_mmutr (MCF_MMU_MMUTR_SG | MCF_MMU_MMUTR_V) -#define writethrough_mmudr (MCF_MMU_MMUDR_SZ(00) | MCF_MMU_MMUDR_CM(00) | MCF_MMU_MMUDR_R | MCF_MMU_MMUDR_W | MCF_MMU_MMUDR_X) -#define copyback_mmudr (MCF_MMU_MMUDR_SZ(00) | MCF_MMU_MMUDR_CM(01) | MCF_MMU_MMUDR_R | MCF_MMU_MMUDR_W | MCF_MMU_MMUDR_X) /* - * - * General Purpose Timers (GPT) - * + * macros */ - -/* Register read/write macros */ -#define MCF_GPT0_GMS __MBAR+0x800 - -/* - * - * Slice Timers (SLT) - * - */ - -#define MCF_SLT0_SCNT __MBAR+0x908 - -/**********************************************************/ -// macros -/**********************************************************/ .altmacro .macro irq vector,int_mask,clr_int move.w #0x2700,sr // disable interrupt @@ -207,25 +152,6 @@ rts .endm -/* - * FIXME: this is a GNU gas kludge. Ugly, but I just can't come up with any smarter solution - * - * GNU as does not support multi-character constants. At least I don't know of any way it would. - * The following might look more than strange, but I considered the statement - * - * mchar move.l, 'T,'E,'S,'T,-(SP) - * - * somewhat more readable than - * - * move.l #1413829460,-(SP) - * - * If anybody knows of any better way on how to do this - please do! - * - */ - .macro mchar st,a,b,c,d,tgt - \st #\a << 24|\b<<16|\c<<8|\d,\tgt - .endm - .text _vec_init: move.l a2,-(sp) // Backup registers @@ -323,16 +249,17 @@ std_exc_vec: movem.l d0-d1/a0-a1,(sp) // save gcc scratch registers lsr.l #2,d0 // shift vector number in place - cmp.l #33,d0 - beq noprint - cmp.l #34,d0 + + cmp.l #33,d0 // do not debug-print various traps + beq noprint // this would slow down interrupt + cmp.l #34,d0 // processing enormously beq noprint cmp.l #45,d0 beq noprint cmp.l #46,d0 beq noprint move.l 4 * 4 + 8 + 4(sp),-(sp) // pc at exception - move.l d0,-(sp) // provide it to xprintf() + move.l d0,-(sp) // vector number pea exception_text jsr _xprintf // call xprintf() add.l #3*4,sp // adjust stack @@ -349,14 +276,15 @@ noprint: move.l 4(sp),a5 // restore a5 move.l d0,4(sp) // store exception routine address - //move.w 10(sp),d0 // restore original SR - //bset #13,d0 // set supervisor bit - //move.w d0,sr // + // FIXME: what does this do and why? + move.w 10(sp),d0 // restore original SR + bset #13,d0 // set supervisor bit + move.w d0,sr // move.l (sp)+,d0 // restore d0 rts // jump to exception routine exception_text: - .ascii "DEBUG: EXCEPTION %d caught at %p" + .ascii "DEBUG: EXCEPTION 0x%x caught at %p" .byte 13, 10, 0 .align 4 @@ -369,48 +297,27 @@ reset_vector: access: move.w #0x2700,sr // disable interrupts - move.l d0,-(sp) // ++ vr - move.w 4(sp),d0 // get format_status word from stack - andi.l #0x0c03,d0 // mask out fault status bits - cmpi.l #0x0401,d0 // TLB miss on opword of instruction fetch? - beq access_mmu // yes - cmpi.l #0x0402,d0 // TLB miss on extension word of instruction fetch? - beq access_mmu // yes - cmpi.l #0x0802,d0 // TLB miss on data write? - beq access_mmu // yes - cmpi.l #0x0c02,d0 // TLB miss on data read, or read-modify-write? - beq access_mmu // yes + link a6,#-4 * 4 // make room for gcc scratch registers + movem.l d0-d1/a0-a1,(sp) // and save them - bra bus_error // everything else is a classic bus error + move.l 4(a6),-(sp) // get format_status longword + move.l 8(a6),-(sp) // PC at exception + move.l MCF_MMU_MMUAR,-(sp) // fault address + move.l MCF_MMU_MMUSR,-(sp) // MMU status register + jsr _mmutr_miss + lea 4 * 4(sp),sp // adjust stack -access_mmu: - move.l MCF_MMU_MMUSR,d0 // did the last fault hit in TLB? - btst #1,d0 // yes, it did. So we already mapped that page - bne bus_error // and this must be a real bus error - - move.l MCF_MMU_MMUAR,d0 - cmp.l #__FASTRAM_END,d0 // above max User RAM area? - bge bus_error // -> bus error - - lea -3 * 4(sp),sp // save gcc scratch registers - movem.l d1/a0-a1,(sp) - - move.l 3 * 4 + 4 (sp),-(sp) // push exception stack frame - move.l 5 * 4 + 4 (sp),-(sp) // push program counter at exception - move.l d0,-(sp) // fault address - jsr _mmutr_miss // else we have an MMU TLB miss - add.l #3 * 4,sp // adjust stack - - movem.l (sp),d1/a0-a1 // restore gcc scratch registers - lea 3 * 4(sp),sp - - move.l (sp)+,d0 // restore register + tst.l d0 // exception handler signals bus error + bne bus_error + movem.l (sp),d0-d1/a0-a1 // restore stack + unlk a6 rte bus_error: - move.l (sp)+,d0 // restore register + movem.l (sp),d0-d1/a0-a1 + unlk a6 bra std_exc_vec zero_divide: @@ -587,10 +494,6 @@ acsi_dma: // atari dma move.l d1,-(sp) lea MCF_PSC0_PSCTB_8BIT,a1 // ++ vr - mchar move.l, 'D,'M','A,'\ ,(a1) - //move.l #"DMA ",(a1) - mchar move.l,'I,'N,'T,'!,(a1) - // move.l #'INT!',(a1) lea 0xf0020110,a5 // fifo daten acsi_dma_start: @@ -673,7 +576,10 @@ irq7: * * GPT0 is used as input trigger. It is connected to the TIN0 signal of * the FPGA and triggers everytime vbasehi is written to, i.e. - * when the video base address gets changed + * when the video base address gets changed. In the "MiNT-compatible MMU"-version this + * doesn't do anything, currently, but + * TODO: could be used for e.g. activating copyback cache mode on those ST-RAM pages + * that aren't video pages. */ diff --git a/Bas_gcc_mmu/sys/mmu.c b/Bas_gcc_mmu/sys/mmu.c index c2b3582..2949a3f 100644 --- a/Bas_gcc_mmu/sys/mmu.c +++ b/Bas_gcc_mmu/sys/mmu.c @@ -62,12 +62,12 @@ #error "unknown machine!" #endif /* MACHINE_FIREBEE */ -//#define DEBUG_MMU -#ifdef DEBUG_MMU +#define DBG_MMU +#ifdef DBG_MMU #define dbg(format, arg...) do { xprintf("DEBUG (%s()): " format, __FUNCTION__, ##arg);} while(0) #else #define dbg(format, arg...) do {;} while (0) -#endif /* DEBUG_MMU */ +#endif /* DBG_MMU */ #define err(format, arg...) do { xprintf("ERROR (%s()): " format, __FUNCTION__, ##arg); xprintf("system halted\r\n"); } while(0); while(1) @@ -84,7 +84,7 @@ inline uint32_t set_asid(uint32_t value) "movec %[value],ASID\n\t" : /* no output */ : [value] "r" (value) - : + : "memory" ); rt_asid = value; @@ -106,7 +106,7 @@ inline uint32_t set_acr0(uint32_t value) "movec %[value],ACR0\n\t" : /* not output */ : [value] "r" (value) - : + : "memory" ); rt_acr0 = value; @@ -126,7 +126,7 @@ inline uint32_t set_acr1(uint32_t value) "movec %[value],ACR1\n\t" : /* not output */ : [value] "r" (value) - : + : "memory" ); rt_acr1 = value; @@ -147,7 +147,7 @@ inline uint32_t set_acr2(uint32_t value) "movec %[value],ACR2\n\t" : /* not output */ : [value] "r" (value) - : + : "memory" ); rt_acr2 = value; @@ -167,7 +167,7 @@ inline uint32_t set_acr3(uint32_t value) "movec %[value],ACR3\n\t" : /* not output */ : [value] "r" (value) - : + : "memory" ); rt_acr3 = value; @@ -183,7 +183,7 @@ inline uint32_t set_mmubar(uint32_t value) "movec %[value],MMUBAR\n\t" : /* no output */ : [value] "r" (value) - : /* no clobber */ + : "memory" ); rt_mmubar = value; NOP(); @@ -206,10 +206,9 @@ 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 */ + { 0x00e00000, 0x00100000, 0x00000000 }, /* map TOS to SDRAM */ { 0x00f00000, 0x00100000, 0xff000000 }, /* map Falcon I/O area to FPGA */ - { 0x01000000, 0x10000000, 0x00000000 }, /* map rest of ram virt = phys */ - { 0x1fd00000, 0x01000000, 0x00000000 }, /* accessed by EmuTOS? */ + { 0x01000000, 0x1f000000, 0x00000000 }, /* map rest of ram virt = phys */ }; static int num_translations = sizeof(translation) / sizeof(struct virt_to_phys); @@ -225,6 +224,7 @@ static inline uint32_t lookup_phys(uint32_t virt) } } err("virtual address 0x%lx not found in translation table!\r\n", virt); + return -1; } struct page_descriptor @@ -252,45 +252,141 @@ static struct page_descriptor pages[65536]; /* 512 Mb RAM */ * * */ -int mmu_map_8k_page(uint32_t virt) +int mmu_map_8k_page(uint32_t virt, uint8_t asid) { - const int size_mask = 0xffffe000; /* 8k pagesize */ + static int num_calls = 0; + + 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 */ + register int sp asm("sp"); + uint32_t phys = lookup_phys(virt); /* virtual to physical translation of page */ + if (phys == -1) + return 0; + dbg("page_descriptor: 0x%02x, num_calls = %d ssp = 0x%08x\r\n", * (uint8_t *) page, num_calls++, sp); /* * add page to TLB */ - MCF_MMU_MMUTR = (virt & size_mask) | /* virtual address */ - MCF_MMU_MMUTR_ID(0x00) | /* address space id (ASID) */ - MCF_MMU_MMUTR_SG | /* shared global */ + 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 */ - NOP(); - MCF_MMU_MMUDR = (phys & size_mask) | /* physical address */ + MCF_MMU_MMUDR = (phys & 0xfffffc00) | /* physical address */ MCF_MMU_MMUDR_SZ(MMU_PAGE_SIZE_8K) | /* page size */ - MCF_MMU_MMUDR_CM(page->cache_mode) | + 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); - NOP(); + + 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 */ - NOP(); 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) +{ + static int num_calls = 0; + + 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 */ + + register int sp asm("sp"); + + uint32_t phys = lookup_phys(virt); /* virtual to physical translation of page */ + + if (phys == -1) + return 0; + dbg("page_descriptor: 0x%02x, num_calls = %d ssp = 0x%08x\r\n", * (uint8_t *) page, num_calls++, sp); + /* + * add page to TLB + */ + 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 */ - dbg("ITLB: MCF_MMU_MMUOR = %08x\r\n\r\n", MCF_MMU_MMUOR); + __asm__ __volatile("" : : : "memory"); /* MMU commands must be exactly in sequence */ + + 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) +{ + static int num_calls = 0; + + 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 */ + + register int sp asm("sp"); + + uint32_t phys = lookup_phys(virt); /* virtual to physical translation of page */ + + if (phys == -1) + return 0; + dbg("page_descriptor: 0x%02x, num_calls = %d ssp = 0x%08x\r\n", * (uint8_t *) page, num_calls++, sp); + /* + * 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_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; } @@ -373,13 +469,13 @@ void mmu_init(void) /* * clear all MMU TLB entries first */ - MCF_MMU_MMUOR = MCF_MMU_MMUOR_CA; + MCF_MMU_MMUOR = MCF_MMU_MMUOR_CA; /* clears _all_ TLBs (including locked ones) */ NOP(); /* * prelaminary initialization of page descriptor 0 (root) table */ - for (i = 0; i < sizeof(pages); i++) + for (i = 0; i < sizeof(pages) / sizeof(struct page_descriptor); i++) { uint32_t addr = i * DEFAULT_PAGE_SIZE; @@ -387,28 +483,36 @@ void mmu_init(void) { pages[i].cache_mode = CACHE_NOCACHE_PRECISE; pages[i].execute = 0; + pages[i].read = 1; + pages[i].write = 1; + pages[i].global = 1; pages[i].supervisor_protect = 1; } else if (addr >= 0x0 && addr < 0x00f00000) /* ST-RAM, potential video memory */ { - pages[i].cache_mode = CACHE_WRITETHROUGH; + pages[i].cache_mode = CACHE_NOCACHE_PRECISE; 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 { - pages[i].cache_mode = CACHE_COPYBACK; + pages[i].cache_mode = CACHE_NOCACHE_PRECISE; pages[i].execute = 1; + pages[i].read = 1; + pages[i].write = 1; pages[i].supervisor_protect = 0; + pages[i].global = 1; } - pages[i].global = 1; /* all pages global by default */ pages[i].locked = 0; /* not locked */ - pages[i].read = 1; /* readable, writable, executable */ - pages[i].write = 1; } 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 */ @@ -424,21 +528,23 @@ void mmu_init(void) ACR_BA(0x80000000)); #elif defined(MACHINE_M54455) ACR_ADMSK(0x7f) | - ACR_BA(0x80000000)); /* FIXME: not determined yet */ + ACR_BA(0x80000000)); /* FIXME: not determined yet for this machine */ #else #error unknown machine! #endif /* MACHINE_FIREBEE */ + +#ifdef _NOT_USED_ // set_acr1(0x601fc000); set_acr1(ACR_W(0) | ACR_SP(0) | ACR_CM(0) | #if defined(MACHINE_FIREBEE) - ACR_CM(ACR_CM_CACHEABLE_WT) | /* ST RAM on the Firebee */ + ACR_CM(ACR_CM_CACHE_INH_PRECISE) | /* ST RAM on the Firebee */ #elif defined(MACHINE_M5484LITE) ACR_CM(ACR_CM_CACHE_INH_PRECISE) | /* Compact Flash on the M548xLITE */ #elif defined(MACHINE_M54455) - ACR_CM(ACR_CM_CACHE_INH_PRECISE) | /* FIXME: not determined yet */ + ACR_CM(ACR_CM_CACHE_INH_PRECISE) | /* FIXME: not determined yet for this machine */ #else #error unknown machine! #endif /* MACHINE_FIREBEE */ @@ -454,13 +560,16 @@ void mmu_init(void) set_acr2(ACR_W(0) | ACR_SP(0) | ACR_CM(0) | - ACR_CM(ACR_CM_CACHEABLE_WT) | + ACR_CM(ACR_CM_CACHE_INH_PRECISE) | ACR_AMM(1) | ACR_S(ACR_S_ALL) | ACR_E(1) | ACR_ADMSK(0x7) | ACR_BA(0xe0000000)); +#endif /* _NOT_USED_ */ + set_acr1(0x0); + set_acr2(0x0); /* disable ACR3 */ set_acr3(0x0); @@ -475,7 +584,7 @@ void mmu_init(void) * 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.cache_mode = CACHE_NOCACHE_PRECISE; flags.read = 1; flags.write = 1; flags.execute = 1; @@ -490,7 +599,7 @@ void mmu_init(void) flags.write = 1; flags.execute = 1; flags.locked = 1; - mmu_map_page(0xe00000, 0xe00000, MMU_PAGE_SIZE_1M, 0, &flags); + //mmu_map_page(0xe00000, 0xe00000, MMU_PAGE_SIZE_1M, 0, &flags); /* * Map (locked) the very last MB of physical SDRAM (this is where the driver buffers reside) to the same @@ -505,43 +614,68 @@ void mmu_init(void) mmu_map_page(SDRAM_START + SDRAM_SIZE - 0x00100000, SDRAM_START + SDRAM_SIZE - 0x00100000, 0, MMU_PAGE_SIZE_1M, &flags); } - -void mmutr_miss(uint32_t address, uint32_t pc, uint32_t format_status) +/* + * enable the MMU. The Coldfire MMU can be used in two different modes + * ... FIXME: + */ +void mmu_enable(void) { - dbg("MMU TLB MISS accessing 0x%08x\r\nFS = 0x%08x\r\nPC = 0x%08x\r\n", address, format_status, pc); - //flush_and_invalidate_caches(); + MCF_MMU_MMUCR = MCF_MMU_MMUCR_EN; /* MMU on */ + NOP(); /* force pipeline sync */ +} -#ifdef _NOT_USED_ - // experimental; try to ensure that supervisor stack area stays in mmu TLBs - // guess what: doesn't work... - register uint32_t sp asm("sp"); - dbg("stack is at %p\r\n", sp); - if (sp < 0x02000000) - { - dbg("mapped stack at 0x%08x\r\n"); - mmu_map_8k_page(sp); - //flush_and_invalidate_caches(); - } -#endif /* _NOT_USED */ +#ifdef DBG_MMU +void verify_mapping(uint32_t address) +{ + /* retrieve mapped page from MMU and make sure everything is correct */ + int ds; - switch (address) + ds = * (int *) address; + dbg("found 0x%08x at address\r\n", ds); +} +#endif /* DBG_MMU */ + +uint32_t mmutr_miss(uint32_t mmu_sr, uint32_t fault_address, uint32_t pc, + uint32_t format_status) +{ + uint32_t fault = format_status & 0x0c030000; + + switch (fault) { - case keyctl: - case keybd: - /* do something to emulate the IKBD access */ - dbg("IKBD access\r\n"); + /* if we have a real TLB miss, map the offending page */ + + case 0x04010000: /* TLB miss on opword of instruction fetch */ + case 0x04020000: /* TLB miss on extension word of instruction fetch */ + dbg("MMU ITLB MISS accessing 0x%08x\r\n" + "FS = 0x%08x\r\n" + "MMUSR = 0x%08x\r\n" + "PC = 0x%08x\r\n", + fault_address, format_status, mmu_sr, pc); + dbg("fault = 0x%08x\r\n", fault); + mmu_map_8k_instruction_page(pc, 0); break; - case midictl: - case midi: - /* do something to emulate MIDI access */ - dbg("MIDI ACIA access\r\n"); + 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: - /* add missed page to TLB */ - mmu_map_8k_page(address); + 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 */ } diff --git a/Bas_gcc_mmu/util/bas_printf.c b/Bas_gcc_mmu/util/bas_printf.c index bfe67ac..b13c18f 100644 --- a/Bas_gcc_mmu/util/bas_printf.c +++ b/Bas_gcc_mmu/util/bas_printf.c @@ -61,148 +61,153 @@ static char snil[] = "(nil)"; void xputchar(int c) { - __asm__ __volatile__ - ( - ".extern printf_helper\n\t" - "move.b %0,d0\n\t" - "bsr printf_helper\n\t" - /* output */: - /* input */: "r" (c) - /* clobber */: "d0","d2","a0","memory" - ); + __asm__ __volatile__ + ( + " .extern __MBAR \n\t" + " move.b %0,d0 \n\t" + ".wait_txready: \n\t" + " move.w __MBAR + 0x8604,d2 \n\t" // PSCSCR0 status register + " btst #10,d2 \n\t" // space left in TX fifo? + " beq.s .wait_txready \n\t" // no, loop + " lea __MBAR + 0x860C,a0 \n\t" // PSCSTB0 transmitter buffer register + " move.b d0,(a0) \n\t" // send byte + /* output */: + /* input */: "r" (c) + /* clobber */: "d0","d2","a0","memory" + ); } static void doprnt(void (*addchar)(int), const char *sfmt, va_list ap) { - char buf[128]; - char *bp; - const char *f; - float flt; - long l; - unsigned long u; - int i; - int fmt; - unsigned char pad = ' '; - int flush_left = 0; - int f_width = 0; - int prec = INF; - int hash = 0; - int do_long = 0; - int sign = 0; - int attributes = 0; + char buf[128]; + char *bp; + const char *f; + float flt; + long l; + unsigned long u; + int i; + int fmt; + unsigned char pad = ' '; + int flush_left = 0; + int f_width = 0; + int prec = INF; + int hash = 0; + int do_long = 0; + int sign = 0; + int attributes = 0; - f = sfmt; - for (; *f; f++) - { - if (*f != '%') - { - /* then just out the char */ - (*addchar)((int) (((unsigned char) *f) | attributes)); - } - else - { - f++; /* skip the % */ + f = sfmt; + for (; *f; f++) + { + if (*f != '%') + { + /* then just out the char */ + (*addchar)((int) (((unsigned char) *f) | attributes)); + } + else + { + f++; /* skip the % */ - if (*f == '-') - { /* minus: flush left */ - flush_left = 1; - f++; - } + if (*f == '-') + { /* minus: flush left */ + flush_left = 1; + f++; + } - if (*f == '0' || *f == '.') - { - /* padding with 0 rather than blank */ - pad = '0'; - f++; - } - if (*f == '*') - { - /* field width */ - f_width = va_arg(ap, int); - f++; - } - else if (isdigit((unsigned char)*f)) - { - f_width = atoi(f); - while (isdigit((unsigned char)*f)) - f++; /* skip the digits */ - } + if (*f == '0' || *f == '.') + { + /* padding with 0 rather than blank */ + pad = '0'; + f++; + } + if (*f == '*') + { + /* field width */ + f_width = va_arg(ap, int); + f++; + } + else if (isdigit((unsigned char)*f)) + { + f_width = atoi(f); + while (isdigit((unsigned char)*f)) + f++; /* skip the digits */ + } - if (*f == '.') - { /* precision */ - f++; - if (*f == '*') - { - prec = va_arg(ap, int); - f++; - } - else if (isdigit((unsigned char)*f)) - { - prec = atoi(f); - while (isdigit((unsigned char)*f)) - f++; /* skip the digits */ - } - } + if (*f == '.') + { /* precision */ + f++; + if (*f == '*') + { + prec = va_arg(ap, int); + f++; + } + else if (isdigit((unsigned char)*f)) + { + prec = atoi(f); + while (isdigit((unsigned char)*f)) + f++; /* skip the digits */ + } + } - if (*f == '#') - { /* alternate form */ - hash = 1; - f++; - } + if (*f == '#') + { /* alternate form */ + hash = 1; + f++; + } - if (*f == 'l') - { /* long format */ - do_long++; - f++; - if (*f == 'l') - { - do_long++; - f++; - } - } + if (*f == 'l') + { /* long format */ + do_long++; + f++; + if (*f == 'l') + { + do_long++; + f++; + } + } - fmt = (unsigned char) *f; - if (fmt != 'S' && fmt != 'Q' && isupper(fmt)) - { - do_long = 1; - fmt = tolower(fmt); - } - bp = buf; - switch (fmt) - { /* do the format */ - case 'd': - switch (do_long) - { - case 0: - l = (long) (va_arg(ap, int)); - break; - case 1: - default: - l = va_arg(ap, long); - break; - } + fmt = (unsigned char) *f; + if (fmt != 'S' && fmt != 'Q' && isupper(fmt)) + { + do_long = 1; + fmt = tolower(fmt); + } + bp = buf; + switch (fmt) + { /* do the format */ + case 'd': + switch (do_long) + { + case 0: + l = (long) (va_arg(ap, int)); + break; + case 1: + default: + l = va_arg(ap, long); + break; + } - if (l < 0) - { - sign = 1; - l = -l; - } - do - { - *bp++ = (char) (l % 10) + '0'; - } while ((l /= 10) > 0); - if (sign) - *bp++ = '-'; - f_width = f_width - (int) (bp - buf); - if (!flush_left) - while (f_width-- > 0) - (*addchar)((int) (pad | attributes)); - for (bp--; bp >= buf; bp--) - (*addchar)((int) (((unsigned char) *bp) | attributes)); - if (flush_left) - while (f_width-- > 0) - (*addchar)((int) (' ' | attributes)); - break; + if (l < 0) + { + sign = 1; + l = -l; + } + do + { + *bp++ = (char) (l % 10) + '0'; + } while ((l /= 10) > 0); + if (sign) + *bp++ = '-'; + f_width = f_width - (int) (bp - buf); + if (!flush_left) + while (f_width-- > 0) + (*addchar)((int) (pad | attributes)); + for (bp--; bp >= buf; bp--) + (*addchar)((int) (((unsigned char) *bp) | attributes)); + if (flush_left) + while (f_width-- > 0) + (*addchar)((int) (' ' | attributes)); + break; case 'f': /* this is actually more than stupid, but does work for now */ @@ -242,179 +247,179 @@ static void doprnt(void (*addchar)(int), const char *sfmt, va_list ap) } break; - case 'p': - do_long = 1; - hash = 1; - fmt = 'x'; - /* no break */ - case 'o': - case 'x': - case 'u': - switch (do_long) - { - case 0: - u = (unsigned long) (va_arg(ap, unsigned int)); - break; - case 1: - default: - u = va_arg(ap, unsigned long); - break; - } - if (fmt == 'u') - { /* unsigned decimal */ - do - { - *bp++ = (char) (u % 10) + '0'; - } while ((u /= 10) > 0); - } - else if (fmt == 'o') - { /* octal */ - do - { - *bp++ = (char) (u % 8) + '0'; - } while ((u /= 8) > 0); - if (hash) - *bp++ = '0'; - } - else if (fmt == 'x') - { /* hex */ - do - { - i = (int) (u % 16); - if (i < 10) - *bp++ = i + '0'; - else - *bp++ = i - 10 + 'a'; - } while ((u /= 16) > 0); - if (hash) - { - *bp++ = 'x'; - *bp++ = '0'; - } - } - i = f_width - (int) (bp - buf); - if (!flush_left) - while (i-- > 0) - (*addchar)((int) (pad | attributes)); - for (bp--; bp >= buf; bp--) - (*addchar)((int) (((unsigned char) *bp) | attributes)); - if (flush_left) - while (i-- > 0) - (*addchar)((int) (' ' | attributes)); - break; + case 'p': + do_long = 1; + hash = 1; + fmt = 'x'; + /* no break */ + case 'o': + case 'x': + case 'u': + switch (do_long) + { + case 0: + u = (unsigned long) (va_arg(ap, unsigned int)); + break; + case 1: + default: + u = va_arg(ap, unsigned long); + break; + } + if (fmt == 'u') + { /* unsigned decimal */ + do + { + *bp++ = (char) (u % 10) + '0'; + } while ((u /= 10) > 0); + } + else if (fmt == 'o') + { /* octal */ + do + { + *bp++ = (char) (u % 8) + '0'; + } while ((u /= 8) > 0); + if (hash) + *bp++ = '0'; + } + else if (fmt == 'x') + { /* hex */ + do + { + i = (int) (u % 16); + if (i < 10) + *bp++ = i + '0'; + else + *bp++ = i - 10 + 'a'; + } while ((u /= 16) > 0); + if (hash) + { + *bp++ = 'x'; + *bp++ = '0'; + } + } + i = f_width - (int) (bp - buf); + if (!flush_left) + while (i-- > 0) + (*addchar)((int) (pad | attributes)); + for (bp--; bp >= buf; bp--) + (*addchar)((int) (((unsigned char) *bp) | attributes)); + if (flush_left) + while (i-- > 0) + (*addchar)((int) (' ' | attributes)); + break; - case 'c': - i = va_arg(ap, int); - (*addchar)((int) (i | attributes)); - break; + case 'c': + i = va_arg(ap, int); + (*addchar)((int) (i | attributes)); + break; - case 'S': - case 'Q': - case 's': - case 'q': - bp = va_arg(ap, char *); - if (!bp) - bp = snil; - f_width = f_width - strlen((char *) bp); - if (!flush_left) - while (f_width-- > 0) - (*addchar)((int) (pad | attributes)); - for (i = 0; *bp && i < prec; i++) - { - if (fmt == 'q' && (*bp & QUOTE)) - (*addchar)((int) ('\\' | attributes)); - (*addchar)( - (int) (((unsigned char) *bp & TRIM) | attributes)); - bp++; - } - if (flush_left) - while (f_width-- > 0) - (*addchar)((int) (' ' | attributes)); - break; + case 'S': + case 'Q': + case 's': + case 'q': + bp = va_arg(ap, char *); + if (!bp) + bp = snil; + f_width = f_width - strlen((char *) bp); + if (!flush_left) + while (f_width-- > 0) + (*addchar)((int) (pad | attributes)); + for (i = 0; *bp && i < prec; i++) + { + if (fmt == 'q' && (*bp & QUOTE)) + (*addchar)((int) ('\\' | attributes)); + (*addchar)( + (int) (((unsigned char) *bp & TRIM) | attributes)); + bp++; + } + if (flush_left) + while (f_width-- > 0) + (*addchar)((int) (' ' | attributes)); + break; - case 'a': - attributes = va_arg(ap, int); - break; + case 'a': + attributes = va_arg(ap, int); + break; - case '%': - (*addchar)((int) ('%' | attributes)); - break; + case '%': + (*addchar)((int) ('%' | attributes)); + break; - default: - break; - } - flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0; - sign = 0; - pad = ' '; - } - } + default: + break; + } + flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0; + sign = 0; + pad = ' '; + } + } } static char *xstring, *xestring; void xaddchar(int c) { - if (xestring == xstring) - *xstring = '\0'; - else - *xstring++ = (char) c; + if (xestring == xstring) + *xstring = '\0'; + else + *xstring++ = (char) c; } int sprintf(char *str, const char *format, ...) { - va_list va; - va_start(va, format); + va_list va; + va_start(va, format); - xstring = str; + xstring = str; - doprnt(xaddchar, format, va); - va_end(va); - *xstring++ = '\0'; + doprnt(xaddchar, format, va); + va_end(va); + *xstring++ = '\0'; - return 0; + return 0; } void xsnprintf(char *str, size_t size, const char *fmt, ...) { - va_list va; - va_start(va, fmt); + va_list va; + va_start(va, fmt); - xstring = str; - xestring = str + size - 1; - doprnt(xaddchar, fmt, va); - va_end(va); - *xstring++ = '\0'; + xstring = str; + xestring = str + size - 1; + doprnt(xaddchar, fmt, va); + va_end(va); + *xstring++ = '\0'; } void xprintf(const char *fmt, ...) { - va_list va; - va_start(va, fmt); - doprnt(xputchar, fmt, va); - va_end(va); + va_list va; + va_start(va, fmt); + doprnt(xputchar, fmt, va); + va_end(va); } void xvprintf(const char *fmt, va_list va) { - doprnt(xputchar, fmt, va); + doprnt(xputchar, fmt, va); } void xvsnprintf(char *str, size_t size, const char *fmt, va_list va) { - xstring = str; - xestring = str + size - 1; - doprnt(xaddchar, fmt, va); - *xstring++ = '\0'; + xstring = str; + xestring = str + size - 1; + doprnt(xaddchar, fmt, va); + *xstring++ = '\0'; } void display_progress() { - static int _progress_index; - char progress_char[] = "|/-\\"; + static int _progress_index; + char progress_char[] = "|/-\\"; - xputchar(progress_char[_progress_index++ % strlen(progress_char)]); - xputchar('\r'); + xputchar(progress_char[_progress_index++ % strlen(progress_char)]); + xputchar('\r'); } void hexdump(uint8_t buffer[], int size) diff --git a/Bas_gcc_mmu/util/printf_helper.S b/Bas_gcc_mmu/util/printf_helper.S deleted file mode 100644 index 7d8eec1..0000000 --- a/Bas_gcc_mmu/util/printf_helper.S +++ /dev/null @@ -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 . - * - * 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 :