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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
|
// license:BSD-3-Clause
// copyright-holders:Joakim Larsson Edstrom
/*
* vme.cpp
*
* The Versabus-E was standardized as the VME bus by VITA 1981 for Europe
* in the single or double Euroboard form factor. Several standard revs has
* been approved since then up until recently and the VME64 revision.
*
* This bus driver starts with Versabus and VME rev C.
* http://bitsavers.informatik.uni-stuttgart.de/pdf/motorola/versabus/M68KVBS_VERSAbus_Specification_Manual_Jul81.pdf
*
* Acronymes from the specification
* ---------------------------------
* BACKPLANE - A printed circuit board which provides the interconnection path
between other printed circuit cards.
SLOT - A single position at which a card may be inserted into the backplane.
One slot may consist of more than one edge connector.
BOARD/CARD - Interchangeable terms representing one printed circuit board capable
of being inserted into the backplane and containing a collection of
electronic components.
MODULE - A collection of electronic components with a single functional
purpose. More than one module may exist on the same card, but one
module should never be spread over multiple cards.
MASTER - A functional module capable of initiating data bus transfers.
REQUESTER - A functional module capable of requesting control of the data
transfer bus.
INTERRUPT - A functional module capable of detecting interrupt requests
HANDLER and initiating appropriate responses.
MASTER - The combination of a MASTER, REQUESTER, INTERRUPT HANDLER, and
SUB-SYSTEM (optionally) an INTERRUPTER, which function together and which
must be on the same card.
NOTE! All MASTERS, REQUESTERS, and INTERRUPT HANDLERS must be pieces of a
MASTER SUB-SYSTEM.
SLAVE - A functional module capable of responding to data transfer
operations generated by a MASTER.
INTERRUPTER - A functional module capable of requesting service from a MASTER
SUB-SYSTEM by generating an interrupt request.
SLAVE - The combination of a SLAVE and INTERRUPTER which function together
SUB-SYSTEM and which must be on the same card.
NOTE! All INTERRUPTERS must be part of either SLAVE SUB-SYSTEMS or MASTER
SUB-SYSTEMS. However, SLAVES may exist as stand-alone elements.
Such SLAVES will never be called SLAVE SUB-SYSTEMS.
CONTROLLER - The combination of modules used to provide utility and emergency
SUB-SYSTEM signals for the VERSAbus. There will always be one and only one
CONTROLLER SUB-SYSTEM. It can contain the following functional
modules:
a. Data Transfer Bus ARBITER
b. Emergency Data Transfer Bus REQUESTER
c. Power up/power down MASTER
d. System clock driver
e. System reset driver
f. System test controller
g. Power monitor (for AC clock and AC fail driver)
In any VERSAbus system, only one each of the above functional modules will exist.
The slot numbered Al is designated as the controller sub-system slot because the
user will typically provide modules a through d on the board residing in this
slot. System reset and the system test controller are typically connected to
an operator control panel and may be located elsewhere. The power monitor is
interfaced to the incoming AC power source and may also be located remotely.
*/
/*
* TODO:
* - bus arbitration
* - block, rmw and address-only cycles
* - utility bus (serial clock/data, acfail, sysreset, sysfail)
* - variants (16-bit backplanes, VME64)
* - location monitors
*/
#include "emu.h"
#include "vme.h"
#define VERBOSE 0
#include "logmacro.h"
DEFINE_DEVICE_TYPE(VME, vme_bus_device, "vme", "VME bus")
DEFINE_DEVICE_TYPE(VME_SLOT, vme_slot_device, "vme_slot", "VME slot")
vme_bus_device::vme_bus_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, u8 datawidth)
: device_t(mconfig, VME, tag, owner, clock)
, device_memory_interface(mconfig, *this)
, m_asc
{
{ "iack", ENDIANNESS_BIG, datawidth, 4, -2, address_map_constructor(FUNC(vme_bus_device::iack), this) },
{}, {}, {}, {}, {}, {}, {}, {},
{ "a32_09", ENDIANNESS_BIG, datawidth, 32, 0, address_map_constructor(FUNC(vme_bus_device::a32), this) },
{ "a32_0a", ENDIANNESS_BIG, datawidth, 32, 0, address_map_constructor(FUNC(vme_bus_device::a32), this) },
{ "a32_0b", ENDIANNESS_BIG, datawidth, 32, 0, address_map_constructor(FUNC(vme_bus_device::a32), this) },
{},
{ "a32_0d", ENDIANNESS_BIG, datawidth, 32, 0, address_map_constructor(FUNC(vme_bus_device::a32), this) },
{ "a32_0e", ENDIANNESS_BIG, datawidth, 32, 0, address_map_constructor(FUNC(vme_bus_device::a32), this) },
{ "a32_0f", ENDIANNESS_BIG, datawidth, 32, 0, address_map_constructor(FUNC(vme_bus_device::a32), this) },
{}, {}, {}, {}, {}, {}, {}, {},
{}, {}, {}, {}, {}, {}, {}, {},
{}, {}, {}, {}, {}, {}, {}, {},
{},
{ "a16_29", ENDIANNESS_BIG, datawidth, 16, 0, address_map_constructor(FUNC(vme_bus_device::a16), this) },
{}, {}, {},
{ "a16_2d", ENDIANNESS_BIG, datawidth, 16, 0, address_map_constructor(FUNC(vme_bus_device::a16), this) },
{}, {},
{}, {}, {}, {}, {}, {}, {}, {},
{},
{ "a24_39", ENDIANNESS_BIG, datawidth, 24, 0, address_map_constructor(FUNC(vme_bus_device::a24), this) },
{ "a24_3a", ENDIANNESS_BIG, datawidth, 24, 0, address_map_constructor(FUNC(vme_bus_device::a24), this) },
{ "a24_3b", ENDIANNESS_BIG, datawidth, 24, 0, address_map_constructor(FUNC(vme_bus_device::a24), this) },
{},
{ "a24_3d", ENDIANNESS_BIG, datawidth, 24, 0, address_map_constructor(FUNC(vme_bus_device::a24), this) },
{ "a24_3e", ENDIANNESS_BIG, datawidth, 24, 0, address_map_constructor(FUNC(vme_bus_device::a24), this) },
{ "a24_3f", ENDIANNESS_BIG, datawidth, 24, 0, address_map_constructor(FUNC(vme_bus_device::a24), this) },
}
, m_irq(*this)
, m_berr(*this)
, m_irq_count{}
, m_iack(false)
{
}
void vme_bus_device::device_start()
{
save_item(NAME(m_irq_count));
save_item(NAME(m_iack));
}
device_memory_interface::space_config_vector vme_bus_device::memory_space_config() const
{
return space_config_vector{
std::make_pair(vme::IACK, &m_asc[vme::IACK]),
std::make_pair(vme::AM_09, &m_asc[vme::AM_09]),
std::make_pair(vme::AM_0a, &m_asc[vme::AM_0a]),
std::make_pair(vme::AM_0b, &m_asc[vme::AM_0b]),
std::make_pair(vme::AM_0d, &m_asc[vme::AM_0d]),
std::make_pair(vme::AM_0e, &m_asc[vme::AM_0e]),
std::make_pair(vme::AM_0f, &m_asc[vme::AM_0f]),
std::make_pair(vme::AM_29, &m_asc[vme::AM_29]),
std::make_pair(vme::AM_2d, &m_asc[vme::AM_2d]),
std::make_pair(vme::AM_39, &m_asc[vme::AM_39]),
std::make_pair(vme::AM_3a, &m_asc[vme::AM_3a]),
std::make_pair(vme::AM_3b, &m_asc[vme::AM_3b]),
std::make_pair(vme::AM_3d, &m_asc[vme::AM_3d]),
std::make_pair(vme::AM_3e, &m_asc[vme::AM_3e]),
std::make_pair(vme::AM_3f, &m_asc[vme::AM_3f]),
};
}
u32 vme_bus_device::read_iack(address_space &space, offs_t offset, u32 mem_mask)
{
if (!device().machine().side_effects_disabled())
{
// decode the interrupt number from address lines A03-A01
unsigned const irq = BIT(offset, 1, 3);
LOG("read_iack 0x%08x mem_mask 0x%08x /IRQ%u /IACKIN asserted (%s)\n", offset, mem_mask, irq, machine().describe_context());
// enable interrupt acknowledge daisy chain
m_iack = true;
}
return space.unmap();
}
// generate bus errors on unmapped read cycles
u32 vme_bus_device::read_berr(address_space &space, offs_t offset, u32 mem_mask)
{
u32 const data = space.unmap();
if (!device().machine().side_effects_disabled())
{
LOG("read_berr %s 0x%08x data 0x%08x mem_mask 0x%08x /BERR asserted (%s)\n", space.name(), offset << 2, data, mem_mask, machine().describe_context());
m_berr(0);
}
return data;
}
// generate bus errors on unmapped write cycles
void vme_bus_device::write_berr(address_space &space, offs_t offset, u32 data, u32 mem_mask)
{
if (!device().machine().side_effects_disabled())
{
LOG("write_berr %s 0x%08x data 0x%08x mem_mask 0x%08x /BERR asserted (%s)\n", space.name(), offset << 2, data, mem_mask, machine().describe_context());
m_berr(0);
}
}
void vme_bus_device::iack(address_map &map)
{
map(0x0, 0xf).r(FUNC(vme_bus_device::read_iack));
}
void vme_bus_device::a16(address_map &map)
{
map(0x0000, 0xffff).rw(FUNC(vme_bus_device::read_berr), FUNC(vme_bus_device::write_berr));
}
void vme_bus_device::a24(address_map &map)
{
map(0x00'0000, 0xff'ffff).rw(FUNC(vme_bus_device::read_berr), FUNC(vme_bus_device::write_berr));
}
void vme_bus_device::a32(address_map &map)
{
map(0x0000'0000, 0xffff'ffff).rw(FUNC(vme_bus_device::read_berr), FUNC(vme_bus_device::write_berr));
}
template <unsigned I> void vme_bus_device::irq_w(int state)
{
bool const irq_active = m_irq_count[I - 1];
// count assertions
if (!state)
m_irq_count[I - 1]++;
else if (irq_active)
m_irq_count[I - 1]--;
// update line state
if (irq_active ^ bool(m_irq_count[I - 1]))
{
LOG("bus /IRQ%u %s\n", I, state ? "cleared" : "asserted");
m_irq[I - 1](state);
}
}
template void vme_bus_device::irq_w<1>(int state);
template void vme_bus_device::irq_w<2>(int state);
template void vme_bus_device::irq_w<3>(int state);
template void vme_bus_device::irq_w<4>(int state);
template void vme_bus_device::irq_w<5>(int state);
template void vme_bus_device::irq_w<6>(int state);
template void vme_bus_device::irq_w<7>(int state);
vme_slot_device::vme_slot_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
: device_t(mconfig, VME_SLOT, tag, owner, clock)
, device_slot_interface(mconfig, *this)
{
}
void vme_slot_device::device_config_complete()
{
device_vme_card_interface *const card(dynamic_cast<device_vme_card_interface *>(get_card_device()));
if (card && owner())
card->set_bus(*dynamic_cast<vme_bus_device *>(owner()));
}
void vme_slot_device::device_start()
{
}
#undef LOG_OUTPUT_FUNC
#define LOG_OUTPUT_FUNC device().logerror
device_vme_card_interface::device_vme_card_interface(machine_config const &mconfig, device_t &device)
: device_interface(device, "vme")
, m_bus(nullptr)
, m_berr(*this)
, m_irq(*this)
, m_iack(*this, 0)
, m_irq_active(0)
, m_master(false)
{
}
void device_vme_card_interface::interface_post_start()
{
device().save_item(NAME(m_irq_active));
device().save_item(NAME(m_master));
/*
* Install a read tap into the bus interrupt acknowledge address space,
* simulating a daisy chain and giving each card an opportunity to respond
* to the interrupt acknowledge cycle in slot sequence. Empty slots do not
* respond, acting as if they have /IACKIN jumpered to /IACKOUT.
*/
vme_space(vme::IACK).install_read_tap(0x0, 0xf, "iack",
[this](offs_t offset, u32 &data, u32 mem_mask)
{
// decode the interrupt number from address lines A03-A01
unsigned const irq = BIT(offset, 1, 3);
/*
* An interrupt acknowledge cycle is being asserted. This device
* will only respond if the upstream interrupt acknowledge daisy
* chain input (/IACKIN) is asserted and this device is asserting
* the interrupt number being acknowledged.
*/
if (!m_bus->iackin_r() && BIT(m_irq_active, irq))
{
// deassert interrupt acknowledge daisy chain output
m_bus->iackout_w(1);
// read and return the interrupting device status/ID
data = m_iack(irq);
LOG("vme iack irq %u status 0x%08x /IACKOUT deasserted (%s)\n", irq, data, device().machine().describe_context());
}
});
}
void device_vme_card_interface::set_bus(vme_bus_device &bus)
{
m_bus = &bus;
// route incoming bus errors to a card only when it is the bus master
m_bus->berr().append(
[this](int state)
{
if (m_master)
{
LOG("vme incoming /BERR %s\n", state ? "cleared" : "asserted");
m_berr(state);
}
});
// route incoming interrupt requests to all cards
m_bus->irq<1>().append([this](int state) { LOG("vme incoming /IRQ1 %s\n", state ? "cleared" : "asserted"); m_irq[0](state); });
m_bus->irq<2>().append([this](int state) { LOG("vme incoming /IRQ2 %s\n", state ? "cleared" : "asserted"); m_irq[1](state); });
m_bus->irq<3>().append([this](int state) { LOG("vme incoming /IRQ3 %s\n", state ? "cleared" : "asserted"); m_irq[2](state); });
m_bus->irq<4>().append([this](int state) { LOG("vme incoming /IRQ4 %s\n", state ? "cleared" : "asserted"); m_irq[3](state); });
m_bus->irq<5>().append([this](int state) { LOG("vme incoming /IRQ5 %s\n", state ? "cleared" : "asserted"); m_irq[4](state); });
m_bus->irq<6>().append([this](int state) { LOG("vme incoming /IRQ6 %s\n", state ? "cleared" : "asserted"); m_irq[5](state); });
m_bus->irq<7>().append([this](int state) { LOG("vme incoming /IRQ7 %s\n", state ? "cleared" : "asserted"); m_irq[6](state); });
}
template <unsigned I> void device_vme_card_interface::vme_irq_w(int state)
{
// check whether the interrupt state has changed
if (BIT(m_irq_active, I) == state)
{
LOG("vme_irq_w outgoing /IRQ%u %s\n", I, state ? "cleared" : "asserted");
// record device interrupt state
if (!state)
m_irq_active |= 1U << I;
else
m_irq_active &= ~(1U << I);
// update the bus irq state
m_bus->irq_w<I>(state);
}
}
template void device_vme_card_interface::vme_irq_w<1>(int state);
template void device_vme_card_interface::vme_irq_w<2>(int state);
template void device_vme_card_interface::vme_irq_w<3>(int state);
template void device_vme_card_interface::vme_irq_w<4>(int state);
template void device_vme_card_interface::vme_irq_w<5>(int state);
template void device_vme_card_interface::vme_irq_w<6>(int state);
template void device_vme_card_interface::vme_irq_w<7>(int state);
//--------------- P2 connector below--------------------------
/*
The VME P2 connector only specifies the mid row B of the connector
and leaves row A and C to be system specific. This has resulted in
a number of variants that has been more or less standardized:
- VMXbus was available on the first VME boards but not standardized hence
an almost compatible variant was developed by Motorola called MVMX32bus.
- VSBbus replaced VMX and MVMX32and was approved by IEEE in 1988
- SCSA is a P2 standardization for telephony voice and facsimile applications
- SkyChannel is packet switched P2 architecture from Sky Computers and standardized
through VITA/VSO.
- RACEway is a 40Mhz P2 bus allowing 480MBps throughput from Mercusry Computers and
standardized through VITA/VSO.
- VME64 adds two more rows, called 'z' and 'd', of user defined pins to the P2 connector
- P2CI adds a PCI bus onto a VME64 P2 connector
URL:s
http://rab.ict.pwr.wroc.pl/dydaktyka/supwa/vme/secbuses.html
http://www.interfacebus.com/Design_Connector_VME_P2_Buses.html
TODO: Figure out a good way to let all these variants coexist and interconnect in a VME system
*/
|