1 // license:BSD-3-Clause
2 // copyright-holders:Robbbert
3 //**************************************************************************************************************************
4 
5 #include "emu.h"
6 #include "includes/trs80m3.h"
7 
8 
9 #define IRQ_M4_RTC      0x04    /* RTC on Model 4 */
10 #define CASS_RISE       0x01    /* high speed cass on Model III/4) */
11 #define CASS_FALL       0x02    /* high speed cass on Model III/4) */
12 #define MODEL4_MASTER_CLOCK 20275200
13 
14 
TIMER_CALLBACK_MEMBER(trs80m3_state::cassette_data_callback)15 TIMER_CALLBACK_MEMBER(trs80m3_state::cassette_data_callback)
16 {
17 /* This does all baud rates. 250 baud (trs80), and 500 baud (all others) set bit 7 of "cassette_data".
18     1500 baud (trs80m3, trs80m4) is interrupt-driven and uses bit 0 of "cassette_data" */
19 
20 	double new_val = (m_cassette->input());
21 
22 	/* Check for HI-LO transition */
23 	if ( m_old_cassette_val > -0.2 && new_val < -0.2 )
24 	{
25 		m_cassette_data |= 0x80;        /* 500 baud */
26 		if (m_mask & CASS_FALL) /* see if 1500 baud */
27 		{
28 			m_cassette_data = 0;
29 			m_irq |= CASS_FALL;
30 			m_maincpu->set_input_line(0, HOLD_LINE);
31 		}
32 	}
33 	else
34 	if ( m_old_cassette_val < -0.2 && new_val > -0.2 )
35 	{
36 		if (m_mask & CASS_RISE) /* 1500 baud */
37 		{
38 			m_cassette_data = 1;
39 			m_irq |= CASS_RISE;
40 			m_maincpu->set_input_line(0, HOLD_LINE);
41 		}
42 	}
43 
44 	m_old_cassette_val = new_val;
45 }
46 
47 
48 /*************************************
49  *
50  *              Port handlers.
51  *
52  *************************************/
53 
54 
port_e0_r()55 uint8_t trs80m3_state::port_e0_r()
56 {
57 /* Indicates which devices are interrupting - d6..d3 not emulated.
58     Whenever an interrupt occurs, this port is immediately read
59     to find out which device requires service. Lowest-numbered
60     bit takes precedence. We take this opportunity to clear the
61     cpu INT line.
62 
63     d6 RS232 Error (Any of {FE, PE, OR} errors has occurred)
64     d5 RS232 Rcv (DAV indicates a char ready to be picked up from uart)
65     d4 RS232 Xmit (TBMT indicates ready to accept another char from cpu)
66     d3 I/O Bus
67     d2 RTC
68     d1 Cass 1500 baud Falling
69     d0 Cass 1500 baud Rising */
70 
71 	m_maincpu->set_input_line(0, CLEAR_LINE);
72 	return ~(m_mask & m_irq);
73 }
74 
port_e4_r()75 uint8_t trs80m3_state::port_e4_r()
76 {
77 /* Indicates which devices are interrupting - d6..d5 not emulated.
78     Whenever an NMI occurs, this port is immediately read
79     to find out which device requires service. Lowest-numbered
80     bit takes precedence. We take this opportunity to clear the
81     cpu NMI line.
82 
83     d7 status of FDC INTREQ (0=true)
84     d6 status of Motor Timeout (0=true)
85     d5 status of Reset signal (0=true - this will reboot the computer) */
86 
87 	m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE);
88 
89 	u8 data = m_nmi_data;
90 	m_nmi_data = 0;
91 	return ~(m_nmi_mask & data);
92 }
93 
port_e8_r()94 uint8_t trs80m3_state::port_e8_r()
95 {
96 /* not emulated
97     d7 Clear-to-Send (CTS), Pin 5
98     d6 Data-Set-Ready (DSR), pin 6
99     d5 Carrier Detect (CD), pin 8
100     d4 Ring Indicator (RI), pin 22
101     d3,d2,d0 Not used
102     d1 UART Receiver Input, pin 20 (pin 20 is also DTR) */
103 
104 	return 0;
105 }
106 
port_ea_r()107 uint8_t trs80m3_state::port_ea_r()
108 {
109 /* UART Status Register
110     d7 Data Received ('1'=condition true)
111     d6 Transmitter Holding Register empty ('1'=condition true)
112     d5 Overrun Error ('1'=condition true)
113     d4 Framing Error ('1'=condition true)
114     d3 Parity Error ('1'=condition true)
115     d2..d0 Not used */
116 
117 	uint8_t data=7;
118 	m_uart->write_swe(0);
119 	data |= m_uart->tbmt_r() ? 0x40 : 0;
120 	data |= m_uart->dav_r( ) ? 0x80 : 0;
121 	data |= m_uart->or_r(  ) ? 0x20 : 0;
122 	data |= m_uart->fe_r(  ) ? 0x10 : 0;
123 	data |= m_uart->pe_r(  ) ? 0x08 : 0;
124 	m_uart->write_swe(1);
125 
126 	return data;
127 }
128 
port_ec_r()129 uint8_t trs80m3_state::port_ec_r()
130 {
131 /* Reset the RTC interrupt */
132 	m_irq &= ~IRQ_M4_RTC;
133 	return 0;
134 }
135 
port_ff_r()136 uint8_t trs80m3_state::port_ff_r()
137 {
138 /* Return of cassette data stream from tape
139     d7 Low-speed data
140     d6..d1 info from write of port EC
141     d0 High-speed data */
142 
143 	m_irq &= 0xfc;  /* clear cassette interrupts */
144 
145 	return m_port_ec | m_cassette_data;
146 }
147 
cp500_port_f4_r()148 uint8_t trs80m3_state::cp500_port_f4_r()
149 {
150 	/* The A11 flipflop is used for enabling access to
151 	       the system monitor code at the EPROM address range 3800-3fff */
152 	uint8_t *rom = memregion("maincpu")->base();
153 	uint8_t *bootrom = memregion("bootrom")->base();
154 
155 	m_a11_flipflop ^= 1; //toggle the flip-flop at every read at io addresses 0xf4-f7
156 
157 	for (u8 block=0; block<8; block++)
158 		memcpy(&rom[block * 0x800], &bootrom[(block | m_a11_flipflop) * 0x800], 0x800);
159 
160 	return 0x00; //really?!
161 }
162 
163 
port_84_w(uint8_t data)164 void trs80m3_state::port_84_w(uint8_t data) // Model 4 & 4P only
165 {
166 /* Memory banking control, video mode control
167     d7 Video Page Control
168     d6 Despage (see p129 of service manual)
169     d5 Enable page mapping (1=enabled)
170     d4 Srcpage (see p129 of service manual)
171     d3 Invert Video
172     d2 80/64 width
173     d1 Select bit 1
174     d0 Select bit 0 */
175 
176 	if (!(m_model4 & 6)) // Model 3 leave now
177 		return;
178 
179 	m_mode = (m_mode & 0x73) | (data & 0x8c);
180 
181 	m_model4 &= 0xce;
182 	m_model4 |= (data & 3) << 4;
183 
184 	if (BIT(m_model4, 1)) // Model 4
185 	{
186 		if (m_mainram->size() >= (64 * 1024))
187 		{
188 			m_m4_bank->set_bank(data & 0x03);
189 			m_32kbanks[0]->set_entry((data >> 4) & 0x07);
190 			m_32kbanks[1]->set_entry((data >> 4) & 0x07);
191 			m_16kbank->set_entry((data >> 4) & 0x07);
192 		}
193 		m_vidbank->set_entry(BIT(data, 7));
194 		return;
195 	}
196 
197 	if (BIT(m_model4, 2)) // Model 4P
198 	{
199 		m_32kbanks[0]->set_entry((data >> 4) & 0x07);
200 		m_32kbanks[1]->set_entry((data >> 4) & 0x07);
201 		m_16kbank->set_entry((data >> 4) & 0x07);
202 		m_vidbank->set_entry(BIT(data, 7));
203 
204 		switch (data & 3)
205 		{
206 			case 0: /* normal operation */
207 				if (BIT(m_model4, 3))
208 					m_m4p_bank->set_bank(0);
209 				else
210 					m_m4p_bank->set_bank(4);
211 				break;
212 
213 			case 1: /* write-only ram backs up the rom */
214 				if (BIT(m_model4, 3))
215 					m_m4p_bank->set_bank(1);
216 				else
217 					m_m4p_bank->set_bank(5);
218 				break;
219 
220 			case 2: /* keyboard and video are moved to high memory, and the rest is ram */
221 				m_m4p_bank->set_bank(2);
222 				m_model4 |= 1;
223 				break;
224 
225 			case 3: /* 64k of ram */
226 				m_m4p_bank->set_bank(3);
227 				break;
228 		}
229 	}
230 }
231 
port_90_w(uint8_t data)232 void trs80m3_state::port_90_w(uint8_t data)
233 {
234 	m_speaker->level_w(!(BIT(data, 0)));
235 }
236 
port_9c_w(uint8_t data)237 void trs80m3_state::port_9c_w(uint8_t data)     /* model 4P only - swaps the ROM with read-only RAM */
238 {
239 	/* Meaning of model4 variable:
240 	    d5..d4 memory mode (as described in section above)
241 	    d3 rom switch (1=enabled) only effective in mode0 and 1
242 	    d2 this is a Model 4P
243 	    d1 this is a Model 4
244 	    d0 Video banking exists yes/no (1=not banked) */
245 
246 	if (!(BIT(m_model4, 2))) // If not Model 4P, leave now
247 		return;
248 
249 	m_model4 &= 0xf7;
250 	m_model4 |= (data << 3);
251 
252 	switch (m_model4 & 0x38)
253 	{
254 		case 0x00:
255 			m_m4p_bank->set_bank(4);
256 			break;
257 
258 		case 0x08:
259 			m_m4p_bank->set_bank(0);
260 			break;
261 
262 		case 0x10:
263 			m_m4p_bank->set_bank(5);
264 			break;
265 
266 		case 0x18:
267 			m_m4p_bank->set_bank(1);
268 			break;
269 
270 		default:
271 			break;
272 	}
273 }
274 
port_e0_w(uint8_t data)275 void trs80m3_state::port_e0_w(uint8_t data)
276 {
277 /* Interrupt settings - which devices are allowed to interrupt - bits align with read of E0
278     d6 Enable Rec Err
279     d5 Enable Rec Data
280     d4 Enable Xmit Emp
281     d3 Enable I/O int
282     d2 Enable RT int
283     d1 C fall Int
284     d0 C Rise Int */
285 
286 	m_mask = data;
287 }
288 
port_e4_w(uint8_t data)289 void trs80m3_state::port_e4_w(uint8_t data)
290 {
291 /* Disk to NMI interface
292     d7 1=enable disk INTRQ to generate NMI
293     d6 1=enable disk Motor Timeout to generate NMI */
294 
295 	m_nmi_mask = data;
296 }
297 
port_e8_w(uint8_t data)298 void trs80m3_state::port_e8_w(uint8_t data)
299 {
300 /* d1 when '1' enables control register load (see below) */
301 
302 	m_reg_load = BIT(data, 1);
303 }
304 
port_ea_w(uint8_t data)305 void trs80m3_state::port_ea_w(uint8_t data)
306 {
307 	if (m_reg_load)
308 
309 /* d2..d0 not emulated
310     d7 Even Parity Enable ('1'=even, '0'=odd)
311     d6='1',d5='1' for 8 bits
312     d6='0',d5='1' for 7 bits
313     d6='1',d5='0' for 6 bits
314     d6='0',d5='0' for 5 bits
315     d4 Stop Bit Select ('1'=two stop bits, '0'=one stop bit)
316     d3 Parity Inhibit ('1'=disable; No parity, '0'=parity enabled)
317     d2 Break ('0'=disable transmit data; continuous RS232 'SPACE' condition)
318     d1 Request-to-Send (RTS), pin 4
319     d0 Data-Terminal-Ready (DTR), pin 20 */
320 
321 	{
322 		m_uart->write_cs(0);
323 		m_uart->write_nb1(BIT(data, 6));
324 		m_uart->write_nb2(BIT(data, 5));
325 		m_uart->write_tsb(BIT(data, 4));
326 		m_uart->write_eps(BIT(data, 7));
327 		m_uart->write_np(BIT(data, 3));
328 		m_uart->write_cs(1);
329 	}
330 	else
331 	{
332 /* not emulated
333     d7,d6 Not used
334     d5 Secondary Unassigned, pin 18
335     d4 Secondary Transmit Data, pin 14
336     d3 Secondary Request-to-Send, pin 19
337     d2 Break ('0'=disable transmit data; continuous RS232 'SPACE' condition)
338     d1 Data-Terminal-Ready (DTR), pin 20
339     d0 Request-to-Send (RTS), pin 4 */
340 
341 	}
342 }
343 
port_ec_w(uint8_t data)344 void trs80m3_state::port_ec_w(uint8_t data)
345 {
346 /* Hardware settings - d5..d4 not emulated
347     d6 CPU fast (1=4MHz, 0=2MHz)
348     d5 1=Enable Video Wait
349     d4 1=Enable External I/O bus
350     d3 1=Enable Alternate Character Set
351     d2 Mode Select (0=64 chars, 1=32chars)
352     d1 Cassette Motor (1=On) */
353 
354 	m_maincpu->set_unscaled_clock(data & 0x40 ? MODEL4_MASTER_CLOCK/5 : MODEL4_MASTER_CLOCK/10);
355 
356 	m_mode = (m_mode & 0xde) | (BIT(data, 2) ? 1 : 0) | (BIT(data, 3) ? 0x20 : 0);
357 
358 	m_cassette->change_state(( data & 2 ) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR );
359 
360 	m_port_ec = data & 0x7e;
361 }
362 
363 /* Selection of drive and parameters - d6..d5 not emulated.
364  A write also causes the selected drive motor to turn on for about 3 seconds.
365  When the motor turns off, the drive is deselected.
366     d7 1=MFM, 0=FM
367     d6 1=Wait
368     d5 1=Write Precompensation enabled
369     d4 0=Side 0, 1=Side 1
370     d3 1=select drive 3
371     d2 1=select drive 2
372     d1 1=select drive 1
373     d0 1=select drive 0 */
port_f4_w(uint8_t data)374 void trs80m3_state::port_f4_w(uint8_t data)
375 {
376 	if (BIT(data, 6))
377 	{
378 		if (m_drq_off && m_intrq_off)
379 		{
380 			m_maincpu->set_input_line(Z80_INPUT_LINE_WAIT, ASSERT_LINE);
381 			m_wait = true;
382 		}
383 	}
384 	else
385 	{
386 		m_maincpu->set_input_line(Z80_INPUT_LINE_WAIT, CLEAR_LINE);
387 		m_wait = false;
388 	}
389 
390 	m_floppy = nullptr;
391 
392 	if (BIT(data, 0)) m_floppy = m_floppy0->get_device();
393 	if (BIT(data, 1)) m_floppy = m_floppy1->get_device();
394 
395 	m_fdc->set_floppy(m_floppy);
396 
397 	if (m_floppy)
398 	{
399 		m_floppy->mon_w(0);
400 		m_floppy->ss_w(BIT(data, 4));
401 		m_timeout = 1600;
402 	}
403 
404 	m_fdc->dden_w(!BIT(data, 7));
405 }
406 
port_ff_w(uint8_t data)407 void trs80m3_state::port_ff_w(uint8_t data)
408 {
409 /* Cassette port
410     d1, d0 Cassette output */
411 
412 	static const double levels[4] = { 0.0, 1.0, -1.0, 0.0 };
413 	m_cassette->output(levels[data & 3]);
414 	m_cassette_data &= ~0x80;
415 }
416 
417 
418 /*************************************
419  *
420  *      Interrupt handlers.
421  *
422  *************************************/
423 
INTERRUPT_GEN_MEMBER(trs80m3_state::rtc_interrupt)424 INTERRUPT_GEN_MEMBER(trs80m3_state::rtc_interrupt)
425 {
426 /* This enables the processing of interrupts for the clock and the flashing cursor.
427     The OS counts one tick for each interrupt. It is called 30 times per second. */
428 
429 	if (m_mask & IRQ_M4_RTC)
430 	{
431 		m_irq |= IRQ_M4_RTC;
432 		m_maincpu->set_input_line(0, HOLD_LINE);
433 	}
434 
435 	// While we're here, let's countdown the motor timeout too.
436 	if (m_timeout)
437 	{
438 		m_timeout--;
439 		if (m_timeout == 0)
440 			if (m_floppy)
441 				m_floppy->mon_w(1);  // motor off
442 	}
443 	// Also, if cpu is in wait, unlock it and trigger NMI
444 	// Don't, it breaks disk loading
445 //  if (m_wait)
446 //  {
447 //      m_wait = false;
448 //      m_maincpu->set_input_line(Z80_INPUT_LINE_WAIT, CLEAR_LINE);
449 //      if (BIT(m_nmi_mask, 6))
450 //      {
451 //          m_nmi_data |= 0x40;
452 //          m_maincpu->set_input_line(INPUT_LINE_NMI, HOLD_LINE);
453 //      }
454 //  }
455 }
456 
457 // The floppy sector has been read. Enable CPU and NMI.
WRITE_LINE_MEMBER(trs80m3_state::intrq_w)458 WRITE_LINE_MEMBER(trs80m3_state::intrq_w)
459 {
460 	m_intrq_off = state ? false : true;
461 	if (state)
462 	{
463 		m_maincpu->set_input_line(Z80_INPUT_LINE_WAIT, CLEAR_LINE);
464 		m_wait = false;
465 		if (BIT(m_nmi_mask, 7))
466 		{
467 			m_nmi_data |= 0x80;
468 			//m_maincpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero);
469 			m_maincpu->set_input_line(INPUT_LINE_NMI, HOLD_LINE);
470 		}
471 	}
472 }
473 
474 // The next byte from floppy is available. Enable CPU so it can get the byte.
WRITE_LINE_MEMBER(trs80m3_state::drq_w)475 WRITE_LINE_MEMBER(trs80m3_state::drq_w)
476 {
477 	m_drq_off = state ? false : true;
478 	if (state)
479 	{
480 		m_maincpu->set_input_line(Z80_INPUT_LINE_WAIT, CLEAR_LINE);
481 		m_wait = false;
482 	}
483 }
484 
485 
486 /*************************************
487  *                                   *
488  *      Memory handlers              *
489  *                                   *
490  *************************************/
491 
wd179x_r()492 uint8_t trs80m3_state::wd179x_r()
493 {
494 	uint8_t data = 0xff;
495 	if (BIT(m_io_config->read(), 7))
496 		data = m_fdc->status_r();
497 
498 	return data;
499 }
500 
printer_r()501 uint8_t trs80m3_state::printer_r()
502 {
503 	return m_cent_status_in->read();
504 }
505 
printer_w(uint8_t data)506 void trs80m3_state::printer_w(uint8_t data)
507 {
508 	m_cent_data_out->write(data);
509 	m_centronics->write_strobe(0);
510 	m_centronics->write_strobe(1);
511 }
512 
513 /*************************************
514  *      Keyboard                     *
515  *************************************/
keyboard_r(offs_t offset)516 uint8_t trs80m3_state::keyboard_r(offs_t offset)
517 {
518 	u8 i, result = 0;
519 
520 	for (i = 0; i < 8; i++)
521 		if (BIT(offset, i))
522 			result |= m_io_keyboard[i]->read();
523 
524 	return result;
525 }
526 
527 
528 /*************************************
529  *  Machine              *
530  *************************************/
531 
machine_start()532 void trs80m3_state::machine_start()
533 {
534 	save_item(NAME(m_model4));
535 	save_item(NAME(m_mode));
536 	save_item(NAME(m_irq));
537 	save_item(NAME(m_mask));
538 	save_item(NAME(m_nmi_mask));
539 	save_item(NAME(m_port_ec));
540 	save_item(NAME(m_reg_load));
541 	save_item(NAME(m_nmi_data));
542 	save_item(NAME(m_cassette_data));
543 	save_item(NAME(m_old_cassette_val));
544 	save_item(NAME(m_start_address));
545 	save_item(NAME(m_crtc_reg));
546 	save_item(NAME(m_size_store));
547 	save_item(NAME(m_a11_flipflop));
548 	save_item(NAME(m_timeout));
549 	save_item(NAME(m_wait));
550 	save_item(NAME(m_drq_off));
551 	save_item(NAME(m_intrq_off));
552 
553 	m_mode = 0;
554 	m_reg_load = 1;
555 	m_nmi_data = 0;
556 	m_timeout = 1;
557 	m_wait = 0;
558 
559 	m_cassette_data_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(trs80m3_state::cassette_data_callback),this));
560 	m_cassette_data_timer->adjust( attotime::zero, 0, attotime::from_hz(11025) );
561 	if (!(m_model4 & 6))   // Model 3 leave now
562 		return;
563 
564 	if (m_mainram->size() < (64 * 1024))
565 	{
566 		if (BIT(m_model4, 1))     // Model 4
567 		{
568 			m_m4_bank->set_stride(0x00000);
569 			m_m4_bank->space(0).unmap_readwrite(0x08000, 0x0ffff);
570 		}
571 		else
572 		if (BIT(m_model4, 2))     // Model 4P
573 		{
574 			m_m4p_bank->set_stride(0x00000);
575 			m_m4p_bank->space(0).unmap_readwrite(0x08000, 0x0ffff);
576 		}
577 		m_16kbank->configure_entries(0, 8, m_mainram->pointer() + 0x00000, 0x00000);
578 	}
579 	else
580 	if (m_mainram->size() < (128 * 1024))
581 	{
582 		m_32kbanks[0]->configure_entries(0, 8, m_mainram->pointer() + 0x00000, 0x00000);
583 		m_32kbanks[1]->configure_entries(0, 8, m_mainram->pointer() + 0x08000, 0x00000);
584 		m_16kbank->configure_entries(0, 8, m_mainram->pointer() + 0x04000, 0x00000);
585 	}
586 	else
587 	{
588 		m_32kbanks[0]->configure_entries(0, 4, m_mainram->pointer() + 0x00000, 0x00000);
589 		m_32kbanks[0]->configure_entries(4, 2, m_mainram->pointer() + 0x00000, 0x00000);
590 		m_32kbanks[0]->configure_entries(6, 2, m_mainram->pointer() + 0x10000, 0x08000);
591 
592 		m_32kbanks[1]->configure_entries(0, 2, m_mainram->pointer() + 0x08000, 0x00000);
593 		m_32kbanks[1]->configure_entries(2, 2, m_mainram->pointer() + 0x10000, 0x08000);
594 		m_32kbanks[1]->configure_entries(4, 4, m_mainram->pointer() + 0x08000, 0x00000);
595 
596 		m_16kbank->configure_entries(0, 4, m_mainram->pointer() + 0x04000, 0x00000);
597 		m_16kbank->configure_entries(4, 2, m_mainram->pointer() + 0x04000, 0x00000);
598 		m_16kbank->configure_entries(6, 2, m_mainram->pointer() + 0x14000, 0x08000);
599 	}
600 	m_vidbank->configure_entries(0, 2, &m_p_videoram[0], 0x0400);
601 }
602 
machine_reset()603 void trs80m3_state::machine_reset()
604 {
605 	m_a11_flipflop = 0; // for cp500
606 	m_cassette_data = 0;
607 	m_size_store = 0xff;
608 	m_drq_off = true;
609 	m_intrq_off = true;
610 
611 	if (m_model4 & 4)
612 		port_9c_w(1);    // 4P - enable rom
613 	if (m_model4 & 6)
614 		port_84_w(0);    // 4 & 4P - switch in devices
615 }
616 
617 
618 /***************************************************************************
619     PARAMETERS
620 ***************************************************************************/
621 
622 #define LOG 1
623 
624 #define CMD_TYPE_OBJECT_CODE                            0x01
625 #define CMD_TYPE_TRANSFER_ADDRESS                       0x02
626 #define CMD_TYPE_END_OF_PARTITIONED_DATA_SET_MEMBER     0x04
627 #define CMD_TYPE_LOAD_MODULE_HEADER                     0x05
628 #define CMD_TYPE_PARTITIONED_DATA_SET_HEADER            0x06
629 #define CMD_TYPE_PATCH_NAME_HEADER                      0x07
630 #define CMD_TYPE_ISAM_DIRECTORY_ENTRY                   0x08
631 #define CMD_TYPE_END_OF_ISAM_DIRECTORY_ENTRY            0x0a
632 #define CMD_TYPE_PDS_DIRECTORY_ENTRY                    0x0c
633 #define CMD_TYPE_END_OF_PDS_DIRECTORY_ENTRY             0x0e
634 #define CMD_TYPE_YANKED_LOAD_BLOCK                      0x10
635 #define CMD_TYPE_COPYRIGHT_BLOCK                        0x1f
636 
637 /***************************************************************************
638     IMPLEMENTATION
639 ***************************************************************************/
640 
QUICKLOAD_LOAD_MEMBER(trs80m3_state::quickload_cb)641 QUICKLOAD_LOAD_MEMBER(trs80m3_state::quickload_cb)
642 {
643 	address_space &program = m_maincpu->space(AS_PROGRAM);
644 
645 	uint8_t type, length;
646 	uint8_t data[0x100];
647 	uint8_t addr[2];
648 	void *ptr;
649 
650 	while (!image.image_feof())
651 	{
652 		image.fread( &type, 1);
653 		image.fread( &length, 1);
654 
655 		length -= 2;
656 		int block_length = length ? length : 256;
657 
658 		switch (type)
659 		{
660 		case CMD_TYPE_OBJECT_CODE:
661 			{
662 			image.fread( &addr, 2);
663 			uint16_t address = (addr[1] << 8) | addr[0];
664 			if (LOG) logerror("/CMD object code block: address %04x length %u\n", address, block_length);
665 			ptr = program.get_write_ptr(address);
666 			image.fread( ptr, block_length);
667 			}
668 			break;
669 
670 		case CMD_TYPE_TRANSFER_ADDRESS:
671 			{
672 			image.fread( &addr, 2);
673 			uint16_t address = (addr[1] << 8) | addr[0];
674 			if (LOG) logerror("/CMD transfer address %04x\n", address);
675 			m_maincpu->set_state_int(Z80_PC, address);
676 			}
677 			break;
678 
679 		case CMD_TYPE_LOAD_MODULE_HEADER:
680 			image.fread( &data, block_length);
681 			if (LOG) logerror("/CMD load module header '%s'\n", data);
682 			break;
683 
684 		case CMD_TYPE_COPYRIGHT_BLOCK:
685 			image.fread( &data, block_length);
686 			if (LOG) logerror("/CMD copyright block '%s'\n", data);
687 			break;
688 
689 		default:
690 			image.fread( &data, block_length);
691 			logerror("/CMD unsupported block type %u!\n", type);
692 		}
693 	}
694 
695 	return image_init_result::PASS;
696 }
697