1 // license:BSD-3-Clause
2 // copyright-holders:Nathan Woods
3 /***************************************************************************
4
5 6883sam.cpp
6
7 Motorola 6883 Synchronous Address Multiplexer
8
9 The Motorola 6883 SAM has 16 bits worth of state, but the state is changed
10 by writing into a 32 byte address space; odd bytes set bits and even bytes
11 clear bits. Here is the layout:
12
13 31 Set TY Map Type 0: RAM/ROM 1: All RAM
14 30 Clear TY Map Type
15 29 Set M1 Memory Size 00: 4K 10: 64K Dynamic
16 28 Clear M1 Memory Size 01: 16K 11: 64K Static
17 27 Set M0 Memory Size
18 26 Clear M0 Memory Size
19 25 Set R1 MPU Rate 00: Slow 10: Fast
20 24 Clear R1 MPU Rate 01: Dual 11: Fast
21 23 Set R0 MPU Rate
22 22 Clear R0 MPU Rate
23 21 Set P1 Page #1 0: Low 1: High
24 20 Clear P1 Page #1
25 19 Set F6 Display Offset
26 18 Clear F6 Display Offset
27 17 Set F5 Display Offset
28 16 Clear F5 Display Offset
29 15 Set F4 Display Offset
30 14 Clear F4 Display Offset
31 13 Set F3 Display Offset
32 12 Clear F3 Display Offset
33 11 Set F2 Display Offset
34 10 Clear F2 Display Offset
35 9 Set F1 Display Offset
36 8 Clear F1 Display Offset
37 7 Set F0 Display Offset
38 6 Clear F0 Display Offset
39 5 Set V2 VDG Mode
40 4 Clear V2 VDG Mode
41 3 Set V1 VDG Mode
42 2 Clear V1 VDG Mode
43 1 Set V0 VDG Mode
44 0 Clear V0 VDG Mode
45
46 All parts of the SAM are fully emulated except R1/R0 (the changes in the
47 MPU rate are approximated) and M1/M0
48
49 ***************************************************************************/
50
51
52 #include "emu.h"
53 #include "machine/6883sam.h"
54
55
56 //**************************************************************************
57 // CONSTANTS
58 //**************************************************************************
59
60 #define LOG_SAM 0
61
62 DEFINE_DEVICE_TYPE(SAM6883, sam6883_device, "sam6883", "MC6883 SAM")
63
64
65
66 //**************************************************************************
67 // DEVICE SETUP
68 //**************************************************************************
69
70 //-------------------------------------------------
71 // constructor
72 //-------------------------------------------------
73
sam6883_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)74 sam6883_device::sam6883_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
75 : device_t(mconfig, SAM6883, tag, owner, clock)
76 , device_memory_interface(mconfig, *this)
77 , sam6883_friend_device_interface(mconfig, *this, 4)
78 , m_ram_config("RAM", ENDIANNESS_BIG, 8, 16, 0)
79 , m_rom0_config("ROM0", ENDIANNESS_BIG, 8, 13, 0)
80 , m_rom1_config("ROM1", ENDIANNESS_BIG, 8, 13, 0)
81 , m_rom2_config("ROM2", ENDIANNESS_BIG, 8, 14, 0)
82 , m_io0_config("I/O0", ENDIANNESS_BIG, 8, 5, 0)
83 , m_io1_config("I/O1", ENDIANNESS_BIG, 8, 5, 0)
84 , m_io2_config("I/O2", ENDIANNESS_BIG, 8, 5, 0)
85 , m_boot_config("boot", ENDIANNESS_BIG, 8, 7, 0)
86 {
87 }
88
sam6883_friend_device_interface(const machine_config & mconfig,device_t & device,int divider)89 sam6883_friend_device_interface::sam6883_friend_device_interface(const machine_config &mconfig, device_t &device, int divider)
90 : device_interface(device, "sam6883")
91 , m_cpu(device, finder_base::DUMMY_TAG)
92 , m_sam_state(0x0000)
93 , m_divider(divider)
94 {
95 }
96
97
98 //-------------------------------------------------
99 // memory_space_config - return the configuration
100 // for the address spaces
101 //-------------------------------------------------
102
memory_space_config() const103 device_memory_interface::space_config_vector sam6883_device::memory_space_config() const
104 {
105 return space_config_vector {
106 std::make_pair(0, &m_ram_config),
107 std::make_pair(1, &m_rom0_config),
108 std::make_pair(2, &m_rom1_config),
109 std::make_pair(3, &m_rom2_config),
110 std::make_pair(4, &m_io0_config),
111 std::make_pair(5, &m_io1_config),
112 std::make_pair(6, &m_io2_config),
113 std::make_pair(7, &m_boot_config)
114 };
115 }
116
117
118 //-------------------------------------------------
119 // device_start - device-specific startup
120 //-------------------------------------------------
121
device_start()122 void sam6883_device::device_start()
123 {
124 // get spaces
125 space(0).cache(m_ram_space);
126 for (int i = 0; i < 3; i++)
127 space(i + 1).cache(m_rom_space[i]);
128 for (int i = 0; i < 3; i++)
129 space(i + 4).specific(m_io_space[i]);
130 space(7).cache(m_boot_space);
131
132 // save state support
133 save_item(NAME(m_sam_state));
134 save_item(NAME(m_counter));
135 save_item(NAME(m_counter_xdiv));
136 save_item(NAME(m_counter_ydiv));
137 }
138
139
140 //-------------------------------------------------
141 // read - read from one of the eight spaces
142 //-------------------------------------------------
143
read(offs_t offset)144 uint8_t sam6883_device::read(offs_t offset)
145 {
146 bool mode_64k = (m_sam_state & SAM_STATE_M1) == SAM_STATE_M1;
147 if (offset < (mode_64k && (m_sam_state & SAM_STATE_TY) ? 0xff00 : 0x8000))
148 {
149 // RAM reads: 0000–7FFF or 0000–FEFF
150 if (mode_64k && (m_sam_state & (SAM_STATE_TY|SAM_STATE_P1)) == SAM_STATE_P1)
151 offset |= 0x8000;
152 return m_ram_space.read_byte(offset);
153 }
154 else if (offset < 0xc000 || offset >= 0xffe0)
155 {
156 // ROM spaces: 8000–9FFF and A000–BFFF + FFE0–FFFF
157 return m_rom_space[BIT(offset, 13)].read_byte(offset & 0x1fff);
158 }
159 else if (offset < 0xff00)
160 {
161 // ROM2 space: C000–FEFF
162 return m_rom_space[2].read_byte(offset & 0x3fff);
163 }
164 else if (offset < 0xff60)
165 {
166 // I/O spaces: FF00–FF1F (slow), FF20–FF3F, FF40–FF5F
167 return m_io_space[BIT(offset, 5, 2)].read_byte(offset & 0x1f);
168 }
169 else
170 {
171 // FF60–FFDF
172 return m_boot_space.read_byte(offset - 0xff60);
173 }
174 }
175
176
177 //-------------------------------------------------
178 // write - write to RAM, I/O or internal register
179 //-------------------------------------------------
180
write(offs_t offset,uint8_t data)181 void sam6883_device::write(offs_t offset, uint8_t data)
182 {
183 bool mode_64k = (m_sam_state & SAM_STATE_M1) == SAM_STATE_M1;
184 if (offset < 0x8000)
185 {
186 // RAM write space: 0000–7FFF (nominally space 7)
187 if (mode_64k && (m_sam_state & (SAM_STATE_TY|SAM_STATE_P1)) == SAM_STATE_P1)
188 offset |= 0x8000;
189 m_ram_space.write_byte(offset, data);
190 }
191 else if (offset < 0xc000 || offset >= 0xffe0)
192 {
193 // ROM spaces: 8000–9FFF and A000–BFFF + FFE0–FFFF (may write through to RAM)
194 if (offset < 0xc000 && mode_64k && (m_sam_state & SAM_STATE_TY))
195 m_ram_space.write_byte(offset, data);
196 m_rom_space[BIT(offset, 13)].write_byte(offset & 0x1fff, data);
197 }
198 else if (offset < 0xff00)
199 {
200 // ROM2 space: C000–FEFF (may write through to RAM)
201 if (mode_64k && (m_sam_state & SAM_STATE_TY))
202 m_ram_space.write_byte(offset, data);
203 m_rom_space[2].write_byte(offset & 0x3fff, data);
204 }
205 else if (offset < 0xff60)
206 {
207 // I/O spaces: FF00–FF1F (slow), FF20–FF3F, FF40–FF5F
208 m_io_space[BIT(offset, 5, 2)].write_byte(offset & 0x1f, data);
209 }
210 else
211 {
212 // FF60–FFDF
213 m_boot_space.write_byte(offset - 0xff60, data);
214 if (offset >= 0xffc0)
215 internal_write(offset & 0x1f, data);
216 }
217 }
218
219
220 //-------------------------------------------------
221 // device_reset - device-specific reset
222 //-------------------------------------------------
223
device_reset()224 void sam6883_device::device_reset()
225 {
226 m_counter = 0;
227 m_counter_xdiv = 0;
228 m_counter_ydiv = 0;
229 m_sam_state = 0x0000;
230 update_state();
231 }
232
233
234
235 //-------------------------------------------------
236 // device_post_load - device-specific post load
237 //-------------------------------------------------
238
device_post_load()239 void sam6883_device::device_post_load()
240 {
241 device_t::device_post_load();
242 update_state();
243 }
244
245
246
247 //-------------------------------------------------
248 // update_state
249 //-------------------------------------------------
250
update_state()251 void sam6883_device::update_state()
252 {
253 update_memory();
254 update_cpu_clock();
255 }
256
257
258
259 //-------------------------------------------------
260 // update_memory
261 //-------------------------------------------------
262
update_memory()263 void sam6883_device::update_memory()
264 {
265 // Memory size - allowed restricting memory accesses to something less than
266 // 32k
267 //
268 // This was a SAM switch that occupied 4 addresses:
269 //
270 // $FFDD (set) R1
271 // $FFDC (clear) R1
272 // $FFDB (set) R0
273 // $FFDA (clear) R0
274 //
275 // R1:R0 formed the following states:
276 // 00 - 4k
277 // 01 - 16k
278 // 10 - 64k
279 // 11 - static RAM (??)
280 //
281 // If something less than 64k was set, the low RAM would be smaller and
282 // mirror the other parts of the RAM
283 //
284 // TODO: Find out what "static RAM" is
285 // TODO: This should affect _all_ memory accesses, not just video ram
286 // TODO: Verify that the CoCo 3 ignored this
287
288 // switch depending on the M1/M0 variables
289 switch(m_sam_state & (SAM_STATE_M1|SAM_STATE_M0))
290 {
291 case 0:
292 // 4K mode
293 m_counter_mask = 0x0FFF;
294 break;
295
296 case SAM_STATE_M0:
297 // 16K mode
298 m_counter_mask = 0x3FFF;
299 break;
300
301 case SAM_STATE_M1:
302 // 64k mode (dynamic)
303 case SAM_STATE_M1|SAM_STATE_M0:
304 // 64k mode (static)
305 if (m_sam_state & SAM_STATE_TY)
306 {
307 // full 64k RAM
308 m_counter_mask = 0xFFFF;
309 }
310 else
311 {
312 // ROM/RAM
313 m_counter_mask = 0x7FFF;
314 }
315 break;
316 }
317 }
318
319
320
321 //-------------------------------------------------
322 // update_cpu_clock - adjusts the speed of the CPU
323 // clock
324 //-------------------------------------------------
325
update_cpu_clock()326 void sam6883_friend_device_interface::update_cpu_clock()
327 {
328 // The infamous speed up poke.
329 //
330 // This was a SAM switch that occupied 4 addresses:
331 //
332 // $FFD9 (set) R1
333 // $FFD8 (clear) R1
334 // $FFD7 (set) R0
335 // $FFD6 (clear) R0
336 //
337 // R1:R0 formed the following states:
338 // 00 - slow 0.89 MHz
339 // 01 - dual speed ???
340 // 1x - fast 1.78 MHz
341 //
342 // R1 controlled whether the video addressing was speeded up and R0
343 // did the same for the CPU. On pre-CoCo 3 machines, setting R1 caused
344 // the screen to display garbage because the M6847 could not display
345 // fast enough.
346 //
347 // TODO: Make the overclock more accurate. In dual speed, ROM was a fast
348 // access but RAM was not. I don't know how to simulate this.
349
350 int speed = (m_sam_state & (SAM_STATE_R1|SAM_STATE_R0)) / SAM_STATE_R0;
351 m_cpu->owner()->set_unscaled_clock(device().clock() / (m_divider * (speed ? 2 : 4)));
352 }
353
354
355
356 //-------------------------------------------------
357 // internal_write
358 //-------------------------------------------------
359
internal_write(offs_t offset,uint8_t data)360 void sam6883_device::internal_write(offs_t offset, uint8_t data)
361 {
362 // data is ignored
363 (void)data;
364
365 // alter the SAM state
366 uint16_t xorval = alter_sam_state(offset);
367
368 // based on the mask, apply effects
369 if (xorval & (SAM_STATE_TY|SAM_STATE_M1|SAM_STATE_M0|SAM_STATE_P1))
370 update_memory();
371 if (xorval & (SAM_STATE_R1|SAM_STATE_R0))
372 update_cpu_clock();
373 }
374
375
376
377 //-------------------------------------------------
378 // horizontal_sync
379 //-------------------------------------------------
380
horizontal_sync()381 void sam6883_device::horizontal_sync()
382 {
383 bool carry;
384
385 // When horizontal sync occurs, bits B1-B3 or B1-B4 may be cleared (except in DMA mode). The catch
386 // is that the SAM's counter is a chain of flip-flops. Clearing the counter can cause carries to
387 // occur just as they can when the counter is bumped.
388 //
389 // This is critical in getting certain semigraphics modes to work correctly. Guardian uses this
390 // mode (see bug #1153). Special thanks to Ciaran Anscomb and Phill Harvey-Smith for figuring this
391 // out
392 switch((m_sam_state & (SAM_STATE_V2|SAM_STATE_V1|SAM_STATE_V0)) / SAM_STATE_V0)
393 {
394 case 0x01:
395 case 0x03:
396 case 0x05:
397 // these SAM modes clear bits B1-B3
398 carry = (m_counter & 0x0008) ? true : false;
399 m_counter &= ~0x000F;
400 if (carry)
401 counter_carry_bit3();
402 break;
403
404 case 0x00:
405 case 0x02:
406 case 0x04:
407 case 0x06:
408 // clear bits B1-B4
409 carry = (m_counter & 0x0010) ? true : false;
410 m_counter &= ~0x001F;
411 if (carry)
412 counter_carry_bit4();
413 break;
414
415 case 0x07:
416 // DMA mode - do nothing
417 break;
418
419 default:
420 fatalerror("Should not get here\n");
421 }
422 }
423
424
425
426 //-------------------------------------------------
427 // hs_w
428 //-------------------------------------------------
429
WRITE_LINE_MEMBER(sam6883_device::hs_w)430 WRITE_LINE_MEMBER( sam6883_device::hs_w )
431 {
432 if (state)
433 {
434 horizontal_sync();
435 }
436 }
437