summaryrefslogtreecommitdiffstatshomepage
path: root/docs/source/techspecs/device_memory_interface.rst
blob: 1b338db94d8343405a325f5d5b25773b5e9222b1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
The device_memory_interface
===========================

1. Capabilities
---------------

The device memory interface provides devices with the capability of
creating address spaces, to which address maps can be associated.
It's used for any device that provides a (logically) address/data bus
other devices can be connected to.  It's mainly, but not only, cpus.

The interface allows for an unlimited set of address spaces, numbered
with small positive values.  The IDs should stay small because they
index vectors to keep the lookup fast.  Spaces number 0-3 have an
associated constant name:

+----+---------------+
| ID | Name          |
+====+===============+
| 0  | AS_PROGRAM    |
+----+---------------+
| 1  | AS_DATA       |
+----+---------------+
| 2  | AS_IO         |
+----+---------------+
| 3  | AS_OPCODES    |
+----+---------------+

Spaces 0 and 3, e.g. AS_PROGRAM and AS_OPCODE, are special for the
debugger and some CPUs.  AS_PROGRAM is use by the debugger and the
cpus as the space from with the cpu reads its instructions for the
disassembler.  When present, AS_OPCODE is used by the debugger and
some cpus to read the opcode part of the instruction.  What opcode
means is device-dependant, for instance for the z80 it's the initial
byte(s) which are read with the M1 signal asserted.  For the 68000 is
means every instruction word plus the PC-relative accesses.  The main,
but not only, use of AS_OPCODE is to implement hardware decrypting
instructions separately from the data.

2. Setup
--------

| std::vector<std::pair<int, const address_space_config *>>\ **memory_space_config**\ (int spacenum) const

The device must override that method to provide a vector of pairs
comprising of a space number and its associated
**address_space_config** describing its configuration.  Some examples
to look up when needed:
* Standard two-space vector: v60_device
* Conditional AS_OPCODE: z80_device
* Inherit config and add a space: m6801_device
* Inherit config and patch a space: tmpz84c011_device


| bool **has_configured_map**\ () const
| bool **has_configured_map**\ (int index) const

The **has_configured_map** method allows to test in the
**memory_space_config** method whether an **address_map** has been
associated with a given space.  That allows to implement optional
memory spaces, such as AS_OPCODES in certain cpu cores.  The
parameterless version tests for space 0.

3. Associating maps to spaces
-----------------------------
Associating maps to spaces is done at the machine config level, after the device declaration.

| **MCFG_DEVICE_ADDRESS_MAP**\ (_space, _map)
| **MCFG_DEVICE_PROGRAM_MAP**\ (_map)
| **MCFG_DEVICE_DATA_MAP**\ (_map)
| **MCFG_DEVICE_IO_MAP**\ (_map)
| **MCFG_DEVICE_DECRYPTED_OPCODES_MAP**\ (_map)

The generic macro and the four specific ones associate a map to a
given space. Address maps associated to non-existing spaces are
ignored (no warning given).  devcpu.h defines MCFG_CPU_*_MAP aliases
to the specific macros.

| **MCFG_DEVICE_REMOVE_ADDRESS_MAP**\ (_space)

That macro removes a memory map associated to a given space.  Useful
when removing a map for an optional space in a machine config
derivative.


4. Accessing the spaces
-----------------------

| address_space &\ **space**\ () const
| address_space &\ **space**\ (int index) const

Returns a given address space post-initialization.  The parameterless
version tests for AS_PROGRAM/AS_0.  Aborts if the space doesn't exist.

| bool **has_space**\ () const
| bool **has_space**\ (int index) const

Indicates whether a given space actually exists. The parameterless
version tests for AS_PROGRAM/AS_0.


5. MMU support for disassembler
-------------------------------

| int **translate**\ (int spacenum, int intention, offs_t &address)

Does a logical to physical address translation through the device's
MMU.  spacenum gives the space number, intention the type of the
future access (TRANSLATE_(READ|WRITE|FETCH)(|_USER|_DEBUG)) and
address is an inout parameter with the address to translate and its
translated version.  This returns the translated space number if
the translation went correctly, or AS_INVALID if the address is
unmapped.

Note that the device itself must override the virtual method
**memory_translate** with the same signature.


| u8 **read_byte**\ (int spacenum, offs_t address, int intention)

Returns a byte from the specified memory space, doing address
translation if requested. The intention must be specified as either
TRANSLATE_READ(|_USER|_DEBUG) or TRANSLATE_NONE.

| u16 **read_word**\ (int spacenum, offs_t address, int intention)

Returns a word from the specified memory space, doing address
translation if requested. The intention must be specified as either
TRANSLATE_READ(|_USER|_DEBUG) or TRANSLATE_NONE.

| u32 **read_dword**\ (int spacenum, offs_t address, int intention)

Returns a dword from the specified memory space, doing address
translation if requested. The intention must be specified as either
TRANSLATE_READ(|_USER|_DEBUG) or TRANSLATE_NONE.

| u64 **read_qword**\ (int spacenum, offs_t address, int intention)
Returns a qword from the specified memory space, doing address
translation if requested. The intention must be specified as either
TRANSLATE_READ(|_USER|_DEBUG) or TRANSLATE_NONE.

| u64 **read_memory**\ (int spacenum, offs_t address, int size, int intention)
Returns 1, 2, 4 or 8 bytes from the specified memory space, as per
**read_byte**, **read_word**, **read_dword** or **read_qword**.

| void **write_byte**\ (int spacenum, offs_t address, u8 data, int intention)
Writes a byte to the specified memory space, doing address
translation if requested. The intention must be specified as either
TRANSLATE_WRITE(|_USER|_DEBUG) or TRANSLATE_NONE.

| void **write_word**\ (int spacenum, offs_t address, u16 data, int intention)
Writes a word to the specified memory space, doing address
translation if requested. The intention must be specified as either
TRANSLATE_WRITE(|_USER|_DEBUG) or TRANSLATE_NONE.

| void **write_dword**\ (int spacenum, offs_t address, u32 data, int intention)
Writes a dword to the specified memory space, doing address
translation if requested. The intention must be specified as either
TRANSLATE_WRITE(|_USER|_DEBUG) or TRANSLATE_NONE.

| void **write_qword**\ (int spacenum, offs_t address, u64 data, int intention)
Writes a qword to the specified memory space, doing address
translation if requested. The intention must be specified as either
TRANSLATE_WRITE(|_USER|_DEBUG) or TRANSLATE_NONE.

| void **write_memory**\ (int spacenum, offs_t address, u64 data, int size, int intention)
Writes 1, 2, 4 or 8 bytes to the specified memory space, as per
**write_byte**, **write_word**, **write_dword** or **write_qword**.

| u64 read_opcode(int spacenum, offs_t offset, int size)
Reads 1, 2, 4 or 8 bytes at the given offset from the specified
opcode space. This calls **translate** with TRANSLATE_FETCH_DEBUG
as the intention.