summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/intellec4/insdatastor.cpp
blob: 81bbf713db72a23efce311dddfef6b2c341558b7 (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
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
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/*
imm4-22 Instruction/Data Storage Module

This card has four 4002 RAMs configured as a page, sockets for four
1702A or similar 256×8 PROMs configured as a ROM page, buffers for four
4-bit input ports, and latches for four 4-bit output ports.

The 4002 RAMs may be jumpered to be selected by CM-RAM1, CM-RAM2 or
CM-RAM3.  Note that the CM-RAM lines are not decoded, so the 4002 RAMs
will be mirrored.  (With two or more imm4-22 cards installed, the 4002
RAMs will fight for the bus if pages 4-7 are selected.)

The PROMs and I/O ports may be jumpered to be mapped at 0x04xx...0x07xx,
0x08xx...0x0bff or 0x0cff...0x0fff.  Additionally, the card may be
jumpered to enable the PROMs and I/O ports only when /ENABLE MON PROM is
asserted, or at all times.

This card may seem like a good way to expand three aspects of the system
at once, but in practice the PROMs are of limited use:
* If jumpered to enable the PROMs at all times, the PROMs will fight for
  the bus if console RAM card program storage is selected.
* If jumpered to enable the PROMs only when /ENABLE MON PROM is
  asserted, the PROMs become effectively inaccessible as the boot vector
  is in the onboard monitor PROM region, and the onboard monitor PROM
  program provides no way to jump to or read from arbitrary locations.

This card was probably most useful as the cheapest way to double RAM and
I/O ports.  Without PROMs installed, mapping I/O at 0x0400...0x07ff only
when /ENABLE MON PROM is asserted would be a convenient way to provide
the necessary connections for an imm4-90 high-speed paper tape reader.

Image file for the PROMs must be an exact multiple of 256 bytes.  PROMs
are assumed to be filled in order from lowest to highest address.
Jumper changes only take effect on hard reset.


P1 Universal Slot edge connector

                         1    2
                  GND    3    4  GND
                         5    6
                         7    8
                         9   10
                  MA0   11   12  MA1
                  MA2   13   14  MA3
                  MA4   15   16  MA5
                  MA6   17   18  MA7
                   C0   19   20  C1
                        21   22
                /MDI0   23   24
                /MDI1   25   26
                /MDI3   27   28
                /MDI2   29   30
                /MDI5   31   32
                /MDI4   33   34
                /MDI7   35   36
                /MDI6   37   38
                        39   40
                 /OUT   41   42  /ENABLE MON PROM
                 -10V   43   44  -10V
                        45   46
             /CM-RAM2   47   48  /CM-RAM3
                        49   50  /CM-RAM1
                I/O 1   51   52  I/O 0
                I/O 2   53   54  /IN
                        55   56  I/O 3
                        57   58
                        59   60
                        61   62
                        63   64
                        65   66
                        67   68
                        69   70
                        71   72  /D3
                        73   74
                        75   76  /D2
                        77   78
                /SYNC   79   80  /D1
                        81   82
                  /D0   83   84
                        85   86
                        87   88  /RESET-4002
                        89   90
                        91   92
              /CM-ROM   93   94  C3
                        95   96  C2
              PHASE 2   97   98  PHASE 1
                  +5V   99  100  +5V


P1 inputs (40-pin IDC)

       ROM 4/8/12 IN0    1    2  ROM 4/8/12 IN1
       ROM 4/8/12 IN2    3    4  ROM 4/8/12 IN3
                  GND    5    6  ROM 5/9/13 IN0
       ROM 5/9/13 IN1    7    8  ROM 5/9/13 IN2
       ROM 5/9/13 IN3    9   10  GND
      ROM 6/10/14 IN0   11   12  ROM 6/10/14 IN1
      ROM 6/10/14 IN2   13   14  ROM 6/10/14 IN3
                  GND   15   16  ROM 7/11/15 IN0
      ROM 7/11/15 IN1   17   18  ROM 7/11/15 IN2
      ROM 7/11/15 IN3   19   20  GND
                        21   22
                        23   24
                        25   26
                        27   28
                        29   30
                        31   32
                        33   34
                        35   36
                        37   38
                        39   40


P2 outputs (40-pin IDC)

      ROM 4/8/12 OUT0    1    2  ROM 4/8/12 OUT1
      ROM 4/8/12 OUT2    3    4  ROM 4/8/12 OUT3
                  GND    5    6  ROM 5/9/13 OUT0
      ROM 5/9/13 OUT1    7    8  ROM 5/9/13 OUT2
      ROM 5/9/13 OUT3    9   10  GND
     ROM 6/10/14 OUT0   11   12  ROM 6/10/14 OUT1
     ROM 6/10/14 OUT2   13   14  ROM 6/10/14 OUT3
                  GND   15   16  ROM 7/11/15 OUT0
     ROM 7/11/15 OUT1   17   18  ROM 7/11/15 OUT2
     ROM 7/11/15 OUT3   19   20  GND
      RAM 4/8/12 OUT0   21   22  RAM 4/8/12 OUT1
      RAM 4/8/12 OUT2   23   24  RAM 4/8/12 OUT3
                  GND   25   26  RAM 5/9/13 OUT0
      RAM 5/9/13 OUT1   27   28  RAM 5/9/13 OUT2
      RAM 5/9/13 OUT3   29   30  GND
     RAM 6/10/14 OUT0   31   32  RAM 6/10/14 OUT1
     RAM 6/10/14 OUT2   33   34  RAM 6/10/14 OUT3
                  GND   35   36  RAM 7/11/15 OUT0
     RAM 7/11/15 OUT1   37   38  RAM 7/11/15 OUT2
     RAM 7/11/15 OUT3   39   40  GND
*/

#include "emu.h"
#include "insdatastor.h"


namespace {

INPUT_PORTS_START(imm4_22)
	PORT_START("JUMPERS")
	PORT_CONFNAME( 0x03, 0x01, "4002 RAM page" )
	PORT_CONFSETTING(    0x01, "1" )
	PORT_CONFSETTING(    0x02, "2" )
	PORT_CONFSETTING(    0x03, "3" )
	PORT_CONFNAME( 0x0c, 0x04, "PROM/GPIO page" )
	PORT_CONFSETTING(    0x04, "0x400-0x7FF" )
	PORT_CONFSETTING(    0x08, "0x800-0xBFF" )
	PORT_CONFSETTING(    0x0c, "0xC00-0xFFF" )
	PORT_CONFNAME( 0x10, 0x00, "PROM/GPIO mode" )
	PORT_CONFSETTING(    0x00, "All" )
	PORT_CONFSETTING(    0x10, "MON only" )
INPUT_PORTS_END


class imm4_22_device
		: public device_t
		, public bus::intellec4::device_univ_card_interface
		, public device_image_interface
{
public:
	imm4_22_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);

	virtual image_init_result call_load() override;
	virtual void call_unload() override;

	virtual bool        is_readable()                   const noexcept override { return true; }
	virtual bool        is_writeable()                  const noexcept override { return false; }
	virtual bool        is_creatable()                  const noexcept override { return false; }
	virtual bool        is_reset_on_load()              const noexcept override { return false; }
	virtual char const *file_extensions()               const noexcept override { return "rom,bin"; }
	virtual char const *image_type_name()               const noexcept override { return "promimage"; }
	virtual char const *image_brief_type_name()         const noexcept override { return "prom"; }

protected:
	virtual ioport_constructor device_input_ports() const override;
	virtual void device_start() override;
	virtual void device_reset() override;

	virtual DECLARE_WRITE_LINE_MEMBER(reset_4002_in) override;

private:
	void ram_out(offs_t offset, u8 data);
	void rom_out(offs_t offset, u8 data);
	u8 rom_in(offs_t offset);

	void allocate();
	void map_ram_io();
	void map_prom();
	void unmap_prom();

	required_ioport m_jumpers;

	bool    m_ram_io_mapped;

	u8      m_ram_page, m_rom_page;
	bool    m_rom_mirror;

	u8                      m_memory[256], m_status[64];
	std::unique_ptr<u8 []>  m_prom;
};


imm4_22_device::imm4_22_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
	: device_t(mconfig, INTELLEC4_INST_DATA_STORAGE, tag, owner, clock)
	, bus::intellec4::device_univ_card_interface(mconfig, *this)
	, device_image_interface(mconfig, *this)
	, m_jumpers(*this, "JUMPERS")
	, m_ram_io_mapped(false)
	, m_ram_page(0U), m_rom_page(0U), m_rom_mirror(false)
	, m_prom()
{
	std::fill(std::begin(m_memory), std::end(m_memory), 0U);
	std::fill(std::begin(m_status), std::end(m_status), 0U);
}


image_init_result imm4_22_device::call_load()
{
	if ((length() > 1024U) || (length() % 256U))
		return image_init_result::FAIL;

	allocate();
	if (fread(m_prom.get(), length()) != length())
		return image_init_result::FAIL;

	map_prom();

	return image_init_result::PASS;
}

void imm4_22_device::call_unload()
{
	unmap_prom();
}


ioport_constructor imm4_22_device::device_input_ports() const
{
	return INPUT_PORTS_NAME(imm4_22);
}

void imm4_22_device::device_start()
{
	m_ram_io_mapped = false;

	allocate();

	save_item(NAME(m_ram_page));
	save_item(NAME(m_rom_page));
	save_item(NAME(m_rom_mirror));
	save_item(NAME(m_memory));
	save_item(NAME(m_status));
	save_pointer(NAME(m_prom), 1024U);
}

void imm4_22_device::device_reset()
{
	map_ram_io();
}


WRITE_LINE_MEMBER(imm4_22_device::reset_4002_in)
{
	// FIXME: this takes several cycles to actually erase everything, and prevents writes while asserted
	if (!state)
	{
		std::fill(std::begin(m_memory), std::end(m_memory), 0U);
		std::fill(std::begin(m_status), std::end(m_status), 0U);
	}
}


void imm4_22_device::ram_out(offs_t offset, u8 data)
{
	// GPIO write - hooking this up would be a pain with MAME as it is
	logerror("4002 A%u out %X\n", 13U + (offset & 0x03U), data & 0x0fU);
}

void imm4_22_device::rom_out(offs_t offset, u8 data)
{
	// GPIO write - hooking this up would be a pain with MAME as it is
	logerror("ROM %u out %X\n", (m_rom_page << 2) | ((offset >> 4) & 0x03U), data & 0x0fU);
}

u8 imm4_22_device::rom_in(offs_t offset)
{
	// GPIO read - hooking this up would be a pain with MAME as it is
	if (!machine().side_effects_disabled())
		logerror("ROM %u in\n", (m_rom_page << 2) | ((offset >> 4) & 0x03U));
	return 0x0fU;
}


void imm4_22_device::allocate()
{
	if (!m_prom)
	{
		m_prom = std::make_unique<u8 []>(1024U);
		std::fill(m_prom.get(), m_prom.get() + 1024U, 0U);
	}
}

void imm4_22_device::map_ram_io()
{
	if (!m_ram_io_mapped)
	{
		static constexpr offs_t ram_start[3][4] = {
				{ 0x01U, 0x04U, 0x05U, 0x07U },
				{ 0x02U, 0x04U, 0x06U, 0x07U },
				{ 0x03U, 0x05U, 0x06U, 0x07U } };

		m_ram_io_mapped = true;

		ioport_value const jumpers(m_jumpers->read());
		m_ram_page = jumpers & 0x03U;
		m_rom_page = (jumpers >> 2) & 0x03U;
		m_rom_mirror = BIT(~jumpers, 4);

		if ((1U > m_ram_page) || (3U < m_ram_page))
			throw emu_fatalerror("imm4_22_device: invalid RAM page %u", m_ram_page);
		if ((1U > m_rom_page) || (3U < m_rom_page))
			throw emu_fatalerror("imm4_22_device: invalid PROM/GPIO page %u", m_rom_page);

		for (offs_t const start : ram_start[m_ram_page - 1U])
		{
			memory_space().install_ram(start << 8, (start << 8) | 0x00ffU, m_memory);
			status_space().install_ram(start << 6, (start << 6) | 0x003fU, m_status);
			ram_ports_space().install_write_handler(start << 2, (start << 2) | 0x03U, write8sm_delegate(*this, FUNC(imm4_22_device::ram_out)));
		}

		offs_t const rom_ports_start(offs_t(m_rom_page) << 6);
		offs_t const rom_ports_end(rom_ports_start | 0x003fU);
		offs_t const rom_ports_mirror(m_rom_mirror ? 0x1f00U : 0x0700U);
		rom_ports_space().install_readwrite_handler(
				rom_ports_start, rom_ports_end, 0U, rom_ports_mirror, 0U,
				read8sm_delegate(*this, FUNC(imm4_22_device::rom_in)), write8sm_delegate(*this, FUNC(imm4_22_device::rom_out)));

		if (is_loaded())
			map_prom();
	}
}

void imm4_22_device::map_prom()
{
	if (m_ram_io_mapped)
	{
		// FIXME: gimme a cookie!
		// FIXME: if mirror is on, this will fight console RAM for the bus in 0x2000 region and also appear in the "two switches" 0x3000 region
		rom_space().install_rom(
				offs_t(m_rom_page) << 10, offs_t((offs_t(m_rom_page) << 10) | length()), m_rom_mirror ? 0x1000U : 0x0000U,
				m_prom.get());
	}
}

void imm4_22_device::unmap_prom()
{
	// FIXME: where's my magic cookie?
	rom_space().unmap_read(offs_t(m_rom_page) << 10, (offs_t(m_rom_page) << 10) | 0x03ffU, m_rom_mirror ? 0x1000U : 0x0000U);
}

} // anonymous namespace


DEFINE_DEVICE_TYPE_PRIVATE(INTELLEC4_INST_DATA_STORAGE, bus::intellec4::device_univ_card_interface, imm4_22_device, "intlc4_imm4_22", "Intel imm4-22 Instruction/Data Storage Module")