trunk/src/emu/memory.c
| r25385 | r25386 | |
| 178 | 178 | specify the share 'tag' will use its memory as backing for all |
| 179 | 179 | future buckets that specify AM_SHARE with the same 'tag'. |
| 180 | 180 | |
| 181 | AM_SETOFFSET(setoffset) |
| 182 | Specifies a handler for a 'set address' operation. The intended use case |
| 183 | for this operation is to emulate a split-phase memory access: The caller |
| 184 | (usually a CPU) sets the address bus lines using set_address. Some |
| 185 | component may then react, for instance, by asserting a control line |
| 186 | like WAIT before delivering the data on the data bus. The data bits are |
| 187 | then sampled on the read operation or delivered on the write operation |
| 188 | that must be called subsequently. |
| 189 | It is not checked whether the address of the set_address operation |
| 190 | matches the address of the subsequent read/write operation. |
| 191 | The address map translates the address to a bucket and an offset, |
| 192 | hence the name of the macro. If no handler is specified for a bucket, |
| 193 | a set_address operation hitting that bucket returns silently. |
| 194 | |
| 195 | AM_DEVSETOFFSET(tag, setoffset) |
| 196 | Specifies a handler for a set_address operation, bound to the device |
| 197 | specified by 'tag'. |
| 198 | |
| 199 | |
| 181 | 200 | ***************************************************************************/ |
| 182 | 201 | |
| 183 | 202 | #include <list> |
| r25385 | r25386 | |
| 521 | 540 | legacy_info m_sublegacy_info[8]; |
| 522 | 541 | }; |
| 523 | 542 | |
| 543 | // ======================> handler_entry_setoffset |
| 544 | // a setoffset-access-specific extension of handler_entry |
| 545 | class handler_entry_setoffset : public handler_entry |
| 546 | { |
| 547 | public: |
| 548 | // construction/destruction |
| 549 | handler_entry_setoffset() |
| 550 | : handler_entry(0, ENDIANNESS_LITTLE, NULL) |
| 551 | { |
| 552 | } |
| 553 | |
| 554 | const char *name() const { return m_setoffset.name(); } |
| 555 | const char *subunit_name(int entry) const { return "no subunit"; } |
| 556 | |
| 557 | // Call through only if the setoffset handler has been late-bound before |
| 558 | // (i.e. if it was declared in the address map) |
| 559 | void setoffset(address_space &space, offs_t offset) const { if (m_setoffset.has_object()) m_setoffset(space, offset); } |
| 560 | |
| 561 | // configure delegate callbacks |
| 562 | void set_delegate(setoffset_delegate delegate, UINT64 mask = 0) { m_setoffset = delegate; } |
| 563 | |
| 564 | private: |
| 565 | setoffset_delegate m_setoffset; |
| 566 | // We do not have subunits for setoffset |
| 567 | // Accordingly, we need not implement unused functions. |
| 568 | void remove_subunit(int entry) { } |
| 569 | }; |
| 570 | |
| 524 | 571 | // ======================> handler_entry_proxy |
| 525 | 572 | |
| 526 | 573 | // A proxy class that contains an handler_entry_read or _write and forwards the setter calls |
| r25385 | r25386 | |
| 823 | 870 | handler_entry_write * m_handlers[TOTAL_MEMORY_BANKS]; // array of user-installed handlers |
| 824 | 871 | }; |
| 825 | 872 | |
| 873 | // ======================> address_table_setoffset |
| 874 | // setoffset access-specific version of an address table |
| 875 | class address_table_setoffset : public address_table |
| 876 | { |
| 877 | public: |
| 878 | // construction/destruction |
| 879 | address_table_setoffset(address_space &space, bool large) |
| 880 | : address_table(space, large) |
| 881 | { |
| 882 | // allocate handlers for each entry, prepopulating the bankptrs for banks |
| 883 | for (int entrynum = 0; entrynum < ARRAY_LENGTH(m_handlers); entrynum++) |
| 884 | { |
| 885 | m_handlers[entrynum] = auto_alloc(space.machine(), handler_entry_setoffset()); |
| 886 | } |
| 826 | 887 | |
| 888 | // Watchpoints and unmap states do not make sense for setoffset |
| 889 | m_handlers[STATIC_NOP]->set_delegate(setoffset_delegate(FUNC(address_table_setoffset::nop_so), this)); |
| 890 | m_handlers[STATIC_NOP]->configure(0, space.bytemask(), ~0); |
| 891 | } |
| 892 | |
| 893 | ~address_table_setoffset() |
| 894 | { |
| 895 | for (int handnum = 0; handnum < ARRAY_LENGTH(m_handlers); handnum++) |
| 896 | auto_free(m_space.machine(), m_handlers[handnum]); |
| 897 | } |
| 898 | |
| 899 | handler_entry &handler(UINT32 index) const { assert(index < ARRAY_LENGTH(m_handlers)); return *m_handlers[index]; } |
| 900 | handler_entry_setoffset &handler_setoffset(UINT32 index) const { assert(index < ARRAY_LENGTH(m_handlers)); return *m_handlers[index]; } |
| 901 | |
| 902 | // range getter |
| 903 | handler_entry_proxy<handler_entry_setoffset> handler_map_range(offs_t bytestart, offs_t byteend, offs_t bytemask, offs_t bytemirror, UINT64 mask = 0) { |
| 904 | std::list<UINT32> entries; |
| 905 | setup_range(bytestart, byteend, bytemask, bytemirror, mask, entries); |
| 906 | std::list<handler_entry_setoffset *> handlers; |
| 907 | for (std::list<UINT32>::const_iterator i = entries.begin(); i != entries.end(); i++) |
| 908 | handlers.push_back(&handler_setoffset(*i)); |
| 909 | return handler_entry_proxy<handler_entry_setoffset>(handlers, mask); |
| 910 | } |
| 911 | |
| 912 | private: |
| 913 | // internal handlers |
| 914 | // Setoffset does not allow for watchpoints, since we assume that a |
| 915 | // corresponding read/write operation will follow, and the watchpoint will |
| 916 | // apply for that operation |
| 917 | // For the same reason it does not make sense to put a warning into the log |
| 918 | // for unmapped locations, as this will be done by the read/write operation |
| 919 | void nop_so(address_space &space, offs_t offset) |
| 920 | { |
| 921 | } |
| 922 | |
| 923 | // internal state |
| 924 | handler_entry_setoffset *m_handlers[TOTAL_MEMORY_BANKS]; // array of user-installed handlers |
| 925 | }; |
| 926 | |
| 927 | |
| 827 | 928 | // ======================> address_space_specific |
| 828 | 929 | |
| 829 | 930 | // this is a derived class of address_space with specific width, endianness, and table size |
| r25385 | r25386 | |
| 840 | 941 | // helpers to simplify core code |
| 841 | 942 | UINT32 read_lookup(offs_t byteaddress) const { return _Large ? m_read.lookup_live_large(byteaddress) : m_read.lookup_live_small(byteaddress); } |
| 842 | 943 | UINT32 write_lookup(offs_t byteaddress) const { return _Large ? m_write.lookup_live_large(byteaddress) : m_write.lookup_live_small(byteaddress); } |
| 944 | UINT32 setoffset_lookup(offs_t byteaddress) const { return _Large ? m_setoffset.lookup_live_large(byteaddress) : m_setoffset.lookup_live_small(byteaddress); } |
| 843 | 945 | |
| 844 | 946 | public: |
| 845 | 947 | // construction/destruction |
| 846 | 948 | address_space_specific(memory_manager &manager, device_memory_interface &memory, address_spacenum spacenum) |
| 847 | 949 | : address_space(manager, memory, spacenum, _Large), |
| 848 | 950 | m_read(*this, _Large), |
| 849 | | m_write(*this, _Large) |
| 951 | m_write(*this, _Large), |
| 952 | m_setoffset(*this, _Large) |
| 850 | 953 | { |
| 851 | 954 | #if (TEST_HANDLER) |
| 852 | 955 | // test code to verify the read/write handlers are touching the correct bits |
| r25385 | r25386 | |
| 988 | 1091 | // accessors |
| 989 | 1092 | virtual address_table_read &read() { return m_read; } |
| 990 | 1093 | virtual address_table_write &write() { return m_write; } |
| 1094 | virtual address_table_setoffset &setoffset() { return m_setoffset; } |
| 991 | 1095 | |
| 992 | 1096 | // watchpoint control |
| 993 | 1097 | virtual void enable_read_watchpoints(bool enable = true) { m_read.enable_watchpoints(enable); } |
| r25385 | r25386 | |
| 1385 | 1489 | } |
| 1386 | 1490 | } |
| 1387 | 1491 | |
| 1492 | // Allows to announce a pending read or write operation on this address. |
| 1493 | // The user of the address_space calls a set_address operation which leads |
| 1494 | // to some particular set_offset operation for an entry in the address map. |
| 1495 | void set_address(offs_t address) |
| 1496 | { |
| 1497 | offs_t byteaddress = address & m_bytemask; |
| 1498 | UINT32 entry = setoffset_lookup(byteaddress); |
| 1499 | const handler_entry_setoffset &handler = m_setoffset.handler_setoffset(entry); |
| 1500 | |
| 1501 | offs_t offset = handler.byteoffset(byteaddress); |
| 1502 | handler.setoffset(*this, offset / sizeof(_NativeType)); |
| 1503 | } |
| 1504 | |
| 1388 | 1505 | // virtual access to these functions |
| 1389 | 1506 | UINT8 read_byte(offs_t address) { return (NATIVE_BITS == 8) ? read_native(address & ~NATIVE_MASK) : read_direct<UINT8, true>(address, 0xff); } |
| 1390 | 1507 | UINT16 read_word(offs_t address) { return (NATIVE_BITS == 16) ? read_native(address & ~NATIVE_MASK) : read_direct<UINT16, true>(address, 0xffff); } |
| r25385 | r25386 | |
| 1432 | 1549 | |
| 1433 | 1550 | address_table_read m_read; // memory read lookup table |
| 1434 | 1551 | address_table_write m_write; // memory write lookup table |
| 1552 | address_table_setoffset m_setoffset; // memory setoffset lookup table |
| 1435 | 1553 | }; |
| 1436 | 1554 | |
| 1437 | 1555 | typedef address_space_specific<UINT8, ENDIANNESS_LITTLE, false> address_space_8le_small; |
| r25385 | r25386 | |
| 1890 | 2008 | // map both read and write halves |
| 1891 | 2009 | populate_map_entry(*entry, ROW_READ); |
| 1892 | 2010 | populate_map_entry(*entry, ROW_WRITE); |
| 2011 | populate_map_entry_setoffset(*entry); |
| 1893 | 2012 | } |
| 1894 | 2013 | } |
| 1895 | 2014 | |
| r25385 | r25386 | |
| 1984 | 2103 | } |
| 1985 | 2104 | } |
| 1986 | 2105 | |
| 2106 | //------------------------------------------------- |
| 2107 | // populate_map_entry_setoffset - special case for setoffset |
| 2108 | //------------------------------------------------- |
| 1987 | 2109 | |
| 2110 | void address_space::populate_map_entry_setoffset(const address_map_entry &entry) |
| 2111 | { |
| 2112 | install_setoffset_handler(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, |
| 2113 | entry.m_addrmirror, setoffset_delegate(entry.m_soproto, *entry.m_setoffsethd.m_devbase), entry.m_setoffsethd.m_mask); |
| 2114 | } |
| 2115 | |
| 1988 | 2116 | //------------------------------------------------- |
| 1989 | 2117 | // allocate_memory - determine all neighboring |
| 1990 | 2118 | // address ranges and allocate memory to back |
| r25385 | r25386 | |
| 2641 | 2769 | } |
| 2642 | 2770 | |
| 2643 | 2771 | |
| 2772 | //----------------------------------------------------------------------- |
| 2773 | // install_setoffset_handler - install set_offset delegate handlers for the space |
| 2774 | //----------------------------------------------------------------------- |
| 2644 | 2775 | |
| 2776 | void address_space::install_setoffset_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, setoffset_delegate handler, UINT64 unitmask) |
| 2777 | { |
| 2778 | VPRINTF(("address_space::install_setoffset_handler(%s-%s mask=%s mirror=%s, %s, %s)\n", |
| 2779 | core_i64_hex_format(addrstart, m_addrchars), core_i64_hex_format(addrend, m_addrchars), |
| 2780 | core_i64_hex_format(addrmask, m_addrchars), core_i64_hex_format(addrmirror, m_addrchars), |
| 2781 | handler.name(), core_i64_hex_format(unitmask, data_width() / 4))); |
| 2782 | |
| 2783 | setoffset().handler_map_range(addrstart, addrend, addrmask, addrmirror, unitmask).set_delegate(handler); |
| 2784 | } |
| 2785 | |
| 2645 | 2786 | //************************************************************************** |
| 2646 | 2787 | // MEMORY MAPPING HELPERS |
| 2647 | 2788 | //************************************************************************** |
trunk/src/emu/memory.h
| r25385 | r25386 | |
| 101 | 101 | class address_table; |
| 102 | 102 | class address_table_read; |
| 103 | 103 | class address_table_write; |
| 104 | class address_table_setoffset; |
| 104 | 105 | |
| 105 | 106 | |
| 106 | 107 | // offsets and addresses are 32-bit (for now...) |
| r25385 | r25386 | |
| 178 | 179 | typedef device_delegate<void (address_space &, offs_t, UINT32, UINT32)> write32_delegate; |
| 179 | 180 | typedef device_delegate<void (address_space &, offs_t, UINT64, UINT64)> write64_delegate; |
| 180 | 181 | |
| 182 | // ======================> setoffset_delegate |
| 181 | 183 | |
| 184 | typedef device_delegate<void (address_space &, offs_t)> setoffset_delegate; |
| 185 | |
| 186 | |
| 182 | 187 | // ======================> direct_read_data |
| 183 | 188 | |
| 184 | 189 | // direct_read_data contains state data for direct read access |
| r25385 | r25386 | |
| 304 | 309 | friend class address_table; |
| 305 | 310 | friend class address_table_read; |
| 306 | 311 | friend class address_table_write; |
| 312 | friend class address_table_setoffset; |
| 307 | 313 | friend class direct_read_data; |
| 308 | 314 | friend class simple_list<address_space>; |
| 309 | 315 | friend resource_pool_object<address_space>::~resource_pool_object(); |
| r25385 | r25386 | |
| 387 | 393 | virtual void write_qword_unaligned(offs_t byteaddress, UINT64 data) = 0; |
| 388 | 394 | virtual void write_qword_unaligned(offs_t byteaddress, UINT64 data, UINT64 mask) = 0; |
| 389 | 395 | |
| 396 | // Set address. This will invoke setoffset handlers for the respective entries. |
| 397 | virtual void set_address(offs_t byteaddress) = 0; |
| 398 | |
| 390 | 399 | // address-to-byte conversion helpers |
| 391 | 400 | offs_t address_to_byte(offs_t address) const { return m_config.addr2byte(address); } |
| 392 | 401 | offs_t address_to_byte_end(offs_t address) const { return m_config.addr2byte_end(address); } |
| r25385 | r25386 | |
| 446 | 455 | |
| 447 | 456 | void install_device_delegate(offs_t addrstart, offs_t addrend, device_t &device, address_map_delegate &map, int bits = 0, UINT64 unitmask = 0); |
| 448 | 457 | |
| 458 | // install setoffset handler |
| 459 | void install_setoffset_handler(offs_t addrstart, offs_t addrend, setoffset_delegate sohandler, UINT64 unitmask = 0) { return install_setoffset_handler(addrstart, addrend, 0, 0, sohandler, unitmask); } |
| 460 | void install_setoffset_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, setoffset_delegate sohandler, UINT64 unitmask = 0); |
| 461 | |
| 449 | 462 | // install new-style delegate handlers (short form) |
| 450 | 463 | UINT8 *install_read_handler(offs_t addrstart, offs_t addrend, read8_delegate rhandler, UINT64 unitmask = 0) { return install_read_handler(addrstart, addrend, 0, 0, rhandler, unitmask); } |
| 451 | 464 | UINT8 *install_write_handler(offs_t addrstart, offs_t addrend, write8_delegate whandler, UINT64 unitmask = 0) { return install_write_handler(addrstart, addrend, 0, 0, whandler, unitmask); } |
| r25385 | r25386 | |
| 540 | 553 | // internal helpers |
| 541 | 554 | virtual address_table_read &read() = 0; |
| 542 | 555 | virtual address_table_write &write() = 0; |
| 556 | virtual address_table_setoffset &setoffset() = 0; |
| 557 | |
| 543 | 558 | void populate_map_entry(const address_map_entry &entry, read_or_write readorwrite); |
| 559 | void populate_map_entry_setoffset(const address_map_entry &entry); |
| 544 | 560 | void unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read_or_write readorwrite, bool quiet); |
| 545 | 561 | void *install_ram_generic(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read_or_write readorwrite, void *baseptr); |
| 546 | 562 | void install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, const char *rtag, const char *wtag); |
| r25385 | r25386 | |
| 940 | 956 | #define DECLARE_READ64_MEMBER(name) UINT64 name(ATTR_UNUSED address_space &space, ATTR_UNUSED offs_t offset, ATTR_UNUSED UINT64 mem_mask = U64(0xffffffffffffffff)) |
| 941 | 957 | #define DECLARE_WRITE64_MEMBER(name) void name(ATTR_UNUSED address_space &space, ATTR_UNUSED offs_t offset, ATTR_UNUSED UINT64 data, ATTR_UNUSED UINT64 mem_mask = U64(0xffffffffffffffff)) |
| 942 | 958 | |
| 959 | #define SETOFFSET_MEMBER(name) void name(ATTR_UNUSED address_space &space, ATTR_UNUSED offs_t offset) |
| 960 | #define DECLARE_SETOFFSET_MEMBER(name) void name(ATTR_UNUSED address_space &space, ATTR_UNUSED offs_t offset) |
| 943 | 961 | |
| 944 | 962 | // device delegate macros |
| 945 | 963 | #define READ8_DELEGATE(_class, _member) read8_delegate(FUNC(_class::_member), this) |
trunk/src/emu/addrmap.h
| r25385 | r25386 | |
| 127 | 127 | void set_write_bank(device_t &device, const char *tag); |
| 128 | 128 | void set_readwrite_bank(device_t &device, const char *tag); |
| 129 | 129 | |
| 130 | // set offset handler (only one version, since there is no data width to consider) |
| 131 | void set_handler(device_t &device, setoffset_delegate func); |
| 132 | |
| 130 | 133 | // submap referencing |
| 131 | 134 | void set_submap(device_t &device, const char *tag, address_map_delegate func, int bits, UINT64 mask); |
| 132 | 135 | |
| r25385 | r25386 | |
| 142 | 145 | offs_t m_addrmask; // mask bits |
| 143 | 146 | map_handler_data m_read; // data for read handler |
| 144 | 147 | map_handler_data m_write; // data for write handler |
| 148 | map_handler_data m_setoffsethd; // data for setoffset handler |
| 145 | 149 | const char * m_share; // tag of a shared memory block |
| 146 | 150 | const char * m_region; // tag of region containing the memory backing this entry |
| 147 | 151 | offs_t m_rgnoffs; // offset within the region |
| r25385 | r25386 | |
| 164 | 168 | write32_space_func m_wspace32; // 32-bit legacy address space handler |
| 165 | 169 | write64_space_func m_wspace64; // 64-bit legacy address space handler |
| 166 | 170 | |
| 171 | setoffset_delegate m_soproto; // set offset proto-delegate |
| 167 | 172 | address_map_delegate m_submap_delegate; |
| 168 | 173 | int m_submap_bits; |
| 169 | 174 | |
| r25385 | r25386 | |
| 495 | 500 | #define AM_READWRITE32(_rhandler, _whandler, _unitmask) \ |
| 496 | 501 | curentry->set_handler(device, read32_delegate(&drivdata_class::_rhandler, "driver_data::" #_rhandler, DEVICE_SELF, (drivdata_class *)0), write32_delegate(&drivdata_class::_whandler, "driver_data::" #_whandler, DEVICE_SELF, (drivdata_class *)0), _unitmask); |
| 497 | 502 | |
| 503 | // driver set offset. Upcast to base class because there are no data width variants, |
| 504 | // and the compiler complains if we don't do it explicitly |
| 505 | #define AM_SETOFFSET(_handler) \ |
| 506 | ((address_map_entry*)curentry)->set_handler(device, setoffset_delegate(&drivdata_class::_handler, "driver_data::" #_handler, DEVICE_SELF, (drivdata_class *)0)); |
| 507 | |
| 498 | 508 | // device reads |
| 499 | 509 | #define AM_DEVREAD(_tag, _class, _handler) \ |
| 500 | 510 | curentry->set_handler(device, read_delegate(&_class::_handler, #_class "::" #_handler, _tag, (_class *)0)); |
| r25385 | r25386 | |
| 525 | 535 | #define AM_DEVREADWRITE32(_tag, _class, _rhandler, _whandler, _unitmask) \ |
| 526 | 536 | curentry->set_handler(device, read32_delegate(&_class::_rhandler, #_class "::" #_rhandler, _tag, (_class *)0), write32_delegate(&_class::_whandler, #_class "::" #_whandler, _tag, (_class *)0), _unitmask); |
| 527 | 537 | |
| 538 | // device set offset |
| 539 | #define AM_DEVSETOFFSET(_tag, _class, _handler) \ |
| 540 | ((address_map_entry*)curentry)->set_handler(device, setoffset_delegate(&_class::_handler, #_class "::" #_handler, _tag, (_class *)0)); |
| 541 | |
| 542 | |
| 528 | 543 | // device mapping |
| 529 | 544 | #define AM_DEVICE(_tag, _class, _handler) \ |
| 530 | 545 | curentry->set_submap(device, _tag, address_map_delegate(&_class::_handler, #_class "::" #_handler, (_class *)0), 0, 0); |