Fri, 12 Apr 2013 16:26:25 +0100
Don't set PS1 if there is a level-7 interrupt or bus error
PS1 should only be set if the page was originally present (PS1 or PS0 set). If
PS0 and PS1 are clear (page not present) then do NOT set PS1.
Once again the TRM is blatantly and spectacularly wrong...
philpem@40 | 1 | #ifndef _MEMORY_H |
philpem@40 | 2 | #define _MEMORY_H |
philpem@40 | 3 | |
philpem@40 | 4 | /*********************************** |
philpem@40 | 5 | * Array read/write utility macros |
philpem@40 | 6 | * "Don't Repeat Yourself" :) |
philpem@40 | 7 | ***********************************/ |
philpem@40 | 8 | |
philpem@40 | 9 | /// Array read, 32-bit |
philpem@40 | 10 | #define RD32(array, address, andmask) \ |
philpem@40 | 11 | (((uint32_t)array[(address + 0) & (andmask)] << 24) | \ |
philpem@40 | 12 | ((uint32_t)array[(address + 1) & (andmask)] << 16) | \ |
philpem@40 | 13 | ((uint32_t)array[(address + 2) & (andmask)] << 8) | \ |
philpem@40 | 14 | ((uint32_t)array[(address + 3) & (andmask)])) |
philpem@40 | 15 | |
philpem@40 | 16 | /// Array read, 16-bit |
philpem@40 | 17 | #define RD16(array, address, andmask) \ |
philpem@40 | 18 | (((uint32_t)array[(address + 0) & (andmask)] << 8) | \ |
philpem@40 | 19 | ((uint32_t)array[(address + 1) & (andmask)])) |
philpem@40 | 20 | |
philpem@40 | 21 | /// Array read, 8-bit |
philpem@40 | 22 | #define RD8(array, address, andmask) \ |
philpem@40 | 23 | ((uint32_t)array[(address + 0) & (andmask)]) |
philpem@40 | 24 | |
philpem@40 | 25 | /// Array write, 32-bit |
philpem@70 | 26 | #define WR32(array, address, andmask, value) do { \ |
philpem@40 | 27 | array[(address + 0) & (andmask)] = (value >> 24) & 0xff; \ |
philpem@40 | 28 | array[(address + 1) & (andmask)] = (value >> 16) & 0xff; \ |
philpem@40 | 29 | array[(address + 2) & (andmask)] = (value >> 8) & 0xff; \ |
philpem@40 | 30 | array[(address + 3) & (andmask)] = value & 0xff; \ |
philpem@70 | 31 | } while (0) |
philpem@40 | 32 | |
philpem@40 | 33 | /// Array write, 16-bit |
philpem@70 | 34 | #define WR16(array, address, andmask, value) do { \ |
philpem@40 | 35 | array[(address + 0) & (andmask)] = (value >> 8) & 0xff; \ |
philpem@40 | 36 | array[(address + 1) & (andmask)] = value & 0xff; \ |
philpem@70 | 37 | } while (0) |
philpem@40 | 38 | |
philpem@40 | 39 | /// Array write, 8-bit |
philpem@70 | 40 | #define WR8(array, address, andmask, value) do { \ |
philpem@70 | 41 | array[(address + 0) & (andmask)] = value & 0xff; \ |
philpem@70 | 42 | } while (0) |
philpem@40 | 43 | |
philpem@40 | 44 | /****************** |
philpem@40 | 45 | * Memory mapping |
philpem@40 | 46 | ******************/ |
philpem@40 | 47 | |
philpem@128 | 48 | /*** |
philpem@128 | 49 | * An entry in MAP RAM looks like this: |
philpem@128 | 50 | * |
philpem@128 | 51 | * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 |
philpem@128 | 52 | * +-----------------------------------------------+ |
philpem@128 | 53 | * | | | | | | | MA[21..12] ADDRESS BITS | |
philpem@128 | 54 | * +-----------------------------------------------+ |
philpem@128 | 55 | * |
philpem@128 | 56 | * Bits 0 thru 9: High 10 address bits (mapping) |
philpem@128 | 57 | * Bits 10 thru 15: Page bits |
philpem@128 | 58 | * B10: PS4 |
philpem@128 | 59 | * B11: PS3 |
philpem@128 | 60 | * B12: PS2 |
philpem@128 | 61 | * B13: PS0 |
philpem@128 | 62 | * B14: PS1 |
philpem@128 | 63 | * B15: WE+ |
philpem@128 | 64 | * |
philpem@128 | 65 | * Page bit meanings: |
philpem@128 | 66 | * PS4, 3 and 2 are unused. |
philpem@128 | 67 | * PS1:PS0: |
philpem@128 | 68 | * PS1 PS0 Meaning |
philpem@128 | 69 | * --- --- ------- |
philpem@128 | 70 | * 0 0 Page not present |
philpem@128 | 71 | * 0 1 Page present but has not been accessed |
philpem@128 | 72 | * 1 0 Page has been accessed but not written |
philpem@128 | 73 | * 1 1 Page has been accessed and written to (is dirty) |
philpem@128 | 74 | * |
philpem@128 | 75 | * WE+: Write Enable. Set to 1 if the page is writable. |
philpem@128 | 76 | * |
philpem@128 | 77 | * Each RAM page is 4096 bytes. |
philpem@128 | 78 | */ |
philpem@40 | 79 | |
philpem@128 | 80 | /// Known page bits and their values |
philpem@128 | 81 | enum { |
philpem@128 | 82 | PAGE_BIT_PS0 = 0x08, ///< PS0 page status bit |
philpem@128 | 83 | PAGE_BIT_PS1 = 0x10, ///< PS1 (page accessed) page bit |
philpem@128 | 84 | PAGE_BIT_WE = 0x20 ///< WE (write enable) page bit |
philpem@128 | 85 | }; |
philpem@128 | 86 | |
philpem@128 | 87 | /// Get the Map RAM entry for the specified page |
philpem@128 | 88 | #define MAPRAM(page) (((uint16_t)state.map[page*2] << 8) + ((uint16_t)state.map[(page*2)+1])) |
philpem@128 | 89 | /// Get the page number for a given address |
philpem@128 | 90 | #define MAP_ADDR_TO_PAGE(addr) (((addr) >> 12) & 0x3FF) |
philpem@128 | 91 | /// Get the Map RAM entry for the specified virtual address |
philpem@128 | 92 | #define MAPRAM_ADDR(addr) (MAPRAM(MAP_ADDR_TO_PAGE(addr))) |
philpem@128 | 93 | /// Map an address from CPU address space to physical memory |
philpem@128 | 94 | #define MAP_ADDR(addr) (((MAPRAM_ADDR(addr) & 0x3FF) << 12) | (addr & 0xFFF)) |
philpem@128 | 95 | /// Get the page bits associated with the mapping for a given physical memory address |
philpem@128 | 96 | #define MAP_PAGEBITS(addr) ((MAPRAM_ADDR(addr) >> 10) & 0x3F) |
philpem@128 | 97 | |
philpem@128 | 98 | #if 0 |
philpem@40 | 99 | /** |
philpem@40 | 100 | * @brief Check memory access permissions for a given address. |
philpem@40 | 101 | * @param addr Address. |
philpem@40 | 102 | * @param writing true if writing to memory, false if reading. |
philpem@40 | 103 | * @return One of the MEM_STATUS constants, specifying whether the access is |
philpem@40 | 104 | * permitted, or what error occurred. |
philpem@40 | 105 | */ |
philpem@40 | 106 | MEM_STATUS checkMemoryAccess(uint32_t addr, bool writing); |
philpem@40 | 107 | |
philpem@40 | 108 | /** |
philpem@112 | 109 | * @brief Check access flags for a DMA transfer and trigger an exception if |
philpem@112 | 110 | * the access is not permitted |
philpem@112 | 111 | * @param reading true if reading from memory, false if writing |
philpem@112 | 112 | */ |
philpem@112 | 113 | bool access_check_dma(int reading); |
philpem@128 | 114 | #endif |
philpem@128 | 115 | |
philpem@128 | 116 | |
philpem@128 | 117 | /** |
philpem@128 | 118 | * Check memory access permissions for a DMA operation. |
philpem@128 | 119 | * @return true if the access is permitted, false if not |
philpem@128 | 120 | */ |
philpem@128 | 121 | bool access_check_dma(void); |
philpem@112 | 122 | |
philpem@40 | 123 | #endif |