src/memory.h

Fri, 12 Apr 2013 16:26:25 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Fri, 12 Apr 2013 16:26:25 +0100
branch
experimental_memory_mapper_v2
changeset 144
609707511166
parent 128
3246b74d96bc
permissions
-rw-r--r--

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