summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/drivers/r9751.cpp
blob: 6ad473ad72d042bfb0eb2b059eab3dcca613797b (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
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
// license:GPL-2.0+
// copyright-holders:Brandon Munger, Stephen Stair
/******************************************************************************
*
* Rolm CBX 9751 Driver
*
* This driver attempts to emulate the following models:
* * Model 10
* * Model 20
* * Model 40
* * Model 50
* * Model 70
*
* The following software releases are known:
* * 9004
* * 9005
*
* The basis of this driver was influenced by the zexall.c driver by
* Jonathan Gevaryahu and Robbbert.
*
*
* Special Thanks to:
* * Stephen Stair (sgstair)   - for help with reverse engineering,
*               programming, and emulation
* * Felipe Sanches (FSanches) - for help with MESS and emulation
* * Michael Zapf (mizapf)     - for building the HDC9234/HDC9224
*               driver that makes this driver possible
*
* Memory map:
* * 0x00000000 - 0x00ffffff : RAM 12MB to 16MB known, up to 128MB?
* * 0x08000000 - 0x0800ffff : PROM Region
* * 0x5ff00000 - 0x5fffffff : System boards
* * 0xff010000 - 0xfff8ffff : CPU board registers
*
* Working:
* * Floppy Disk IO (PDC device)
* * SMIOC terminal (preliminary)
*
* TODO:
* * Identify registers required for OS booting
* * Hard disk support
* * SMIOC ports (1-8)
* * Identify various LED registers for system boards
* * ROLMLink (RLI) board support
* * Analog Telephone Interface (ATI) board support
* * T1 (T1DN) board support
*
******************************************************************************/

/* Core includes */
#include "emu.h"
#include "cpu/m68000/m68000.h"
#include "machine/terminal.h"

#include "bus/scsi/scsi.h"
#include "machine/wd33c93.h"

#include "machine/pdc.h"
#include "machine/smioc.h"
#include "softlist.h"


/* Log defines */
#define TRACE_FDC 0
#define TRACE_HDC 0
#define TRACE_LED 0
#define TRACE_DMA 0

/* Trace accesses to other boards in the system */
#define ENABLE_TRACE_ALL_DEVICES 0

/* Trace accesses to 68k system board registers */
#define ENABLE_TRACE_SYSTEM 0
#define SYSTEM_TRACE_LEVEL 5





class r9751_state : public driver_device
{
public:
	r9751_state(const machine_config &mconfig, device_type type, const char *tag)
		: driver_device(mconfig, type, tag),
		m_maincpu(*this, "maincpu"),
		m_pdc(*this, "pdc"),
		m_smioc(*this, "smioc"),
		m_wd33c93(*this, "wd33c93"),
		m_main_ram(*this, "main_ram")
	{
		device_trace_init();
		system_trace_init();
	}
	~r9751_state()
	{
		device_trace_teardown();
		system_trace_teardown();
	}

	void r9751(machine_config &config);

	void init_r9751();

private:

	DECLARE_READ32_MEMBER(r9751_mmio_5ff_r);
	DECLARE_WRITE32_MEMBER(r9751_mmio_5ff_w);
	DECLARE_READ32_MEMBER(r9751_mmio_ff01_r);
	DECLARE_WRITE32_MEMBER(r9751_mmio_ff01_w);
	DECLARE_READ32_MEMBER(r9751_mmio_ff05_r);
	DECLARE_WRITE32_MEMBER(r9751_mmio_ff05_w);
	DECLARE_READ32_MEMBER(r9751_mmio_fff8_r);
	DECLARE_WRITE32_MEMBER(r9751_mmio_fff8_w);

	DECLARE_READ8_MEMBER(pdc_dma_r);
	DECLARE_WRITE8_MEMBER(pdc_dma_w);
	DECLARE_READ8_MEMBER(smioc_dma_r);
	DECLARE_WRITE8_MEMBER(smioc_dma_w);

	void r9751_mem(address_map &map);

	required_device<cpu_device> m_maincpu;
	required_device<pdc_device> m_pdc;
	required_device<smioc_device> m_smioc;
	required_device<wd33c93_device> m_wd33c93;
	required_shared_ptr<uint32_t> m_main_ram;

	m68000_base_device* ptr_m68000;

	// Begin registers
	uint32_t reg_ff050004;
	uint32_t reg_fff80040;
	uint32_t fdd_dest_address; // 5FF080B0
	uint32_t fdd_cmd_complete;
	uint32_t smioc_dma_bank;
	uint32_t fdd_dma_bank;
	attotime timer_32khz_last;
	// End registers

	address_space *m_mem;

	// functions
	uint32_t swap_uint32( uint32_t val );
	uint32_t debug_a6();
	uint32_t debug_a5();
	uint32_t debug_a5_20();
	void UnifiedTrace(u32 address, u32 data, const char* operation="Read", const char* Device="SMIOC", const char* RegisterName=nullptr, const char* extraText=nullptr);

	virtual void machine_reset() override;
	void trace_device(int address, int data, const char* direction);

	void system_trace_init();
	void system_trace_teardown();
	void trace_system(int table, int offset, int data, const char* direction);

	uint32_t m_device_trace_enable[2];
	//int m_trace_last_address[64];
	//int m_trace_last_data[64];
	//int m_trace_repeat_count[64];
	//char const * m_trace_last_direction[64];
	//char const * m_generic_command_names[256];
	//char const ** m_specific_command_tables[64];
	void device_trace_init();
	void device_trace_teardown();
	void device_trace_enable_all();
	void device_trace_disable(int device);

	void* system_trace_context;
};

#if ENABLE_TRACE_ALL_DEVICES
// Device tracing
static char const *const DeviceNames[] = {
	nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,"??", // 0x00-0x07
	"??","HDD",nullptr,nullptr,nullptr,nullptr,nullptr,nullptr, // 0x08-0x0F
	nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr, // 0x10-0x17
	nullptr,nullptr,nullptr,nullptr,"SMIOCb","SMIOCb?","SMIOCb?","SMIOCb?", // 0x18-0x1F - Unclear how wide the range is for the second SMIOC range.
	nullptr,nullptr,nullptr,nullptr,"SMIOCa","SMIOCa?","SMIOCa","SMIOCa", // 0x20-0x27 - 0x25 SMIOC we have not observed being used yet.
	"??",nullptr,nullptr,nullptr,"FDC",nullptr,nullptr,nullptr, // 0x28-0x2F
	"??",nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr, // 0x30-0x37
	"SMIOCc?",nullptr,"SMIOCd?",nullptr,nullptr,nullptr,nullptr,"??" // 0x38-0x3F
};

struct GenericCommandRecord {
	u32 AddressPattern;
	const char * Name;
};

static const GenericCommandRecord GenericCommands[] = {
	{ 0x200, "Clear Status" },
	{ 0x800, "Status" },
	{ 0x1000, "Word Count / Result" },
	{ 0x2800, "DMA Busy" },
	{ 0x3000, "Command Result" },
	{ 0x4000, "Command" },  // Also a write length.
	//{ 0x8000, "various" },  // Read address,
	//{ 0xC000, "various" },  // Write address, Read length
};

static const GenericCommandRecord SpecificCommands[] = {
	{ 0x5FF00198, "Special/reinit?" },
	{ 0x5FF08098, "Command Parameter" },
	{ 0x5FF0C098, "DMA Transmit Address" },
	{ 0x5FF0409C, "DMA Transmit Length" },
	{ 0x5FF0809C, "DMA Receive Address" },
	{ 0x5FF0C09C, "DMA Receive Length" },
	{ 0x5FF004B0, "Reset PDC" },
	{ 0x5FF010B0, "Clear result?" },
	{ 0x5FF041B0, "Old style Command" },
	{ 0x5FF080B0, "SCSI Command Address" },
	{ 0x5FF0C1B0, "DMA Receive Address" },
};


void r9751_state::device_trace_init()
{
	for (int i = 0; i < 64; i++)
	{
		m_trace_last_address[i] = -1;
		m_trace_last_data[i] = -1;
		m_trace_repeat_count[i] = 0;
		m_trace_last_direction[i] = nullptr;
		m_specific_command_tables[i] = nullptr;
	}
	for (int i = 0; i < 256; i++)
	{
		m_generic_command_names[i] = "?";
	}

	for (int i = 0; i < sizeof(GenericCommands) / sizeof(GenericCommands[0]); i++)
	{
		int index = (GenericCommands[i].AddressPattern & 0xFF00) >> 8;
		m_generic_command_names[index] = GenericCommands[i].Name;
	}

	for (int i = 0; i < sizeof(SpecificCommands) / sizeof(SpecificCommands[0]); i++)
	{
		int deviceIndex = (SpecificCommands[i].AddressPattern & 0xFC) >> 2;
		char const ** deviceTable = m_specific_command_tables[deviceIndex];
		if (deviceTable == nullptr)
		{
			deviceTable = new char const *[256];
			memset(deviceTable, 0, sizeof(*deviceTable) * 256);
			m_specific_command_tables[deviceIndex] = deviceTable;
		}

		int index = (SpecificCommands[i].AddressPattern & 0xFF00) >> 8;

		deviceTable[index] = SpecificCommands[i].Name;
	}
}
void r9751_state::device_trace_teardown()
{
	for (int i = 0; i < 64; i++)
	{
		delete[] m_specific_command_tables[i];
	}
}

void r9751_state::trace_device(int address, int data, const char* direction)
{
	int dev = (address & 0xFF) / 4;
	char const * devName = "?";
	char const * regName = "?";

	if (!(m_device_trace_enable[(dev >> 5)] & (1 << (dev & 31))))
	{
		// Device is not enabled for tracing.
		return;
	}

	if ((address == m_trace_last_address[dev]) && (data == m_trace_last_data[dev]) && (direction == m_trace_last_direction[dev]))
	{
		m_trace_repeat_count[dev]++;
		return;
	}
	// Compute Device and Register name
	if (DeviceNames[dev] != nullptr)
	{
		devName = DeviceNames[dev];
	}

	if (m_trace_repeat_count[dev] > 0)
	{
		regName = m_generic_command_names[(m_trace_last_address[dev] & 0xFF00) >> 8];
		logerror("Previous access on Device 0x%x (%s) to [%08x] (%s) repeated %d times\n", dev, devName, m_trace_last_address[dev], regName, m_trace_repeat_count[dev]);
	}
	m_trace_repeat_count[dev] = 0;
	m_trace_last_address[dev] = address;
	m_trace_last_data[dev] = data;
	m_trace_last_direction[dev] = direction;

	regName = m_generic_command_names[(address & 0xFF00) >> 8];
	if (m_specific_command_tables[dev] != nullptr)
	{
		int index = (address & 0xFF00) >> 8;
		if (m_specific_command_tables[dev][index] != nullptr)
		{
			regName = m_specific_command_tables[dev][index];
		}
	}


	u32 stacktrace[4];
	u32 basepointer[2];
	u32 reg_a6 = ptr_m68000->state_int(M68K_A6);

	for (int i = 0; i<4; i++)
		stacktrace[i] = 0;
	for (int i = 0; i<2; i++)
		basepointer[i] = 0;

	stacktrace[0] = m_maincpu->pc();
	if (reg_a6 + 4 < 0xFFFFFF) stacktrace[1] = m_maincpu->space(AS_PROGRAM).read_dword(reg_a6 + 4);
	if (reg_a6 < 0xFFFFFF && reg_a6 != 0) basepointer[0] = m_maincpu->space(AS_PROGRAM).read_dword(reg_a6);
	if (basepointer[0] + 4 < 0xFFFFFF && basepointer[0] != 0) stacktrace[2] = m_maincpu->space(AS_PROGRAM).read_dword(basepointer[0] + 4);
	if (basepointer[0] < 0xFFFFFF && basepointer[0] != 0) basepointer[1] = m_maincpu->space(AS_PROGRAM).read_dword(basepointer[0]);
	if (basepointer[1] + 4 < 0xFFFFFF && basepointer[1] != 0) stacktrace[3] = m_maincpu->space(AS_PROGRAM).read_dword(basepointer[1] + 4);

	logerror("%s Device 0x%x (%s) Register [%08X] (%s) %s %08X (%08X, %08X, %08X, %08X)\n", machine().time().as_string(), dev, devName, address, regName, direction, data, stacktrace[0], stacktrace[1], stacktrace[2], stacktrace[3]);

}

#else
void r9751_state::device_trace_init() {}
void r9751_state::device_trace_teardown() {}
void r9751_state::trace_device(int address, int data, const char* direction) {}
#endif

void r9751_state::device_trace_enable_all()
{
	for (int i = 0; i < sizeof(m_device_trace_enable) / sizeof(m_device_trace_enable[0]); i++)
	{
		m_device_trace_enable[i] = 0xFFFFFFFF;
	}
}
void r9751_state::device_trace_disable(int device)
{
	device = device & 0x3F;
	m_device_trace_enable[device >> 5] &= ~(1 << (device & 0x1F));
}


// System register tracing
struct SystemRegisterInfo {
	int VerboseLevel;
	u32 RegisterAddress;
	const char * RegisterName;
	const char * Description;
};

static const SystemRegisterInfo SystemRegisters[] = {
	{ 5, 0xff010000, "DB00" },{ 5, 0xff010004, "DB01" },{ 5, 0xff010008, "DB02" },{ 5, 0xff01000c, "DB03" },
	{ 5, 0xff010010, "DB04" },{ 5, 0xff010014, "DB05" },{ 5, 0xff010018, "DB06" },{ 5, 0xff01001c, "DB07" },
	{ 5, 0xff010020, "DB08" },{ 5, 0xff010024, "DB09" },{ 5, 0xff010028, "DB10" },{ 5, 0xff01002c, "DB11" },
	{ 5, 0xff010040, "DBVR" },{ 5, 0xff010044, "DTAR" },{ 5, 0xff010048, "DESR" },{ 5, 0xff01004c, "DVR" },
	{ 5, 0xff010050, "DRR" },{ 5, 0xff010054, "DDR" },{ 5, 0xff010060, "DMR" },{ 5, 0xff010064, "RCR" },
	{ 5, 0xff010068, "RESR" },{ 5, 0xff01006c, "RBSR" },{ 5, 0xff010070, "RBDR" },{ 5, 0xff010074, "RBAR" },
	{ 5, 0xff010078, "RIOB" },{ 5, 0xff01007c, "RPSR" },{ 5, 0xff010080, "PDR" },

	{ 5, 0xff020004, "ARSP" },{ 5, 0xff020008, "MEXC" },{ 5, 0xff02000c, "MADD" },{ 5, 0xff020010, "MDAT" },
	{ 5, 0xff020014, "ADIA" },{ 5, 0xff020018, "ECCD" },{ 5, 0xff02001c, "VPDS" },{ 5, 0xff020020, "HBRK" },
	{ 5, 0xff020024, "LBRK" },{ 5, 0xff020028, "REFS" },{ 5, 0xff02002c, "RCNT" },{ 5, 0xff020030, "RTMR" },

	{ 5, 0xff050004, "ROSR" },{ 5, 0xff050008, "BIVR" },{ 5, 0xff05000c, "RDDR", "LED - RAS Digit Display Register" },
	{ 5, 0xff050104, "AMR" },
	{ 5, 0xff050108, "MIVR" },{ 5, 0xff050200, "APCR" },{ 5, 0xff050204, "PESR" },{ 5, 0xff050208, "PEAR" },
	{ 5, 0xff05020c, "PEDR" },{ 5, 0xff050210, "PEST" },{ 5, 0xff050300, "RCID" },
	{ 2, 0xff050310, "APLT" }, // APLT is accessed heavily in background/timing processes.
	{ 2, 0xff050320, "WDT" }, // WDT use is particularly noisy
	{ 5, 0xff050400, "APT" },{ 5, 0xff050404, "AIVR" },{ 5, 0xff050408, "ASSR" },
	{ 5, 0xff050410, "STRU" },{ 5, 0xff050414, "STRL" },
	{ 5, 0xff050500, "EV00" },{ 5, 0xff050504, "EV01" },{ 5, 0xff050508, "EV02" },{ 5, 0xff05050c, "EV03" },
	{ 5, 0xff050510, "EV04" },{ 5, 0xff050514, "EV05" },{ 5, 0xff050518, "EV06" },{ 5, 0xff05051c, "EV07" },
	{ 5, 0xff050520, "EV08" },{ 5, 0xff050524, "EV09" },{ 5, 0xff050528, "EV10" },{ 5, 0xff05052c, "EV11" },
	{ 5, 0xff050530, "EV12" },{ 5, 0xff050534, "EV13" },{ 5, 0xff050538, "EV14" },{ 5, 0xff05053c, "EV15" },
	{ 5, 0xff050540, "EV16" },{ 5, 0xff050544, "EV17" },{ 5, 0xff050548, "EV18" },{ 5, 0xff05054c, "EV19" },
	{ 5, 0xff050550, "EV20" },{ 5, 0xff050554, "EV21" },{ 5, 0xff050558, "EV22" },{ 5, 0xff05055c, "EV23" },
	{ 5, 0xff050560, "EV24" },{ 5, 0xff050564, "EV25" },
	{ 5, 0xff050580, "PISR" },
	{ 2, 0xff050584, "PIMR" }, // PIMR use in the bios is noisy
	{ 5, 0xff050600, "CDMR" },{ 5, 0xff050604, "CDER" },
	{ 5, 0xff050610, "CIV0" },{ 5, 0xff050614, "CIV1" },{ 5, 0xff050618, "CIV2" },{ 5, 0xff05061c, "CIV3" },
	{ 5, 0xff050620, "CIV4" },{ 5, 0xff050624, "CIV5" },{ 5, 0xff050628, "CIV6" },{ 5, 0xff05062c, "CIV7" },
	{ 5, 0xff050630, "CCV0" },{ 5, 0xff050634, "CCV1" },{ 5, 0xff050638, "CCV2" },{ 5, 0xff05063c, "CCV3" },
	{ 5, 0xff050640, "CCV4" },{ 5, 0xff050644, "CCV5" },{ 5, 0xff050648, "CCV6" },{ 5, 0xff05064c, "CCV7" },

	{ 5, 0xff060014, "SCAS" },{ 5, 0xff060018, "SCRG" },{ 5, 0xff060020, "SDER" },{ 5, 0xff060024, "SDCR" },
	{ 5, 0xff060028, "SESR" },{ 5, 0xff06002c, "SBSR" },{ 5, 0xff060030, "SBDR" },{ 5, 0xff060034, "SBAR" },
	{ 5, 0xff060038, "SDAR" },{ 5, 0xff06003c, "SINT" },{ 5, 0xff060040, "SDXC" },{ 5, 0xff060044, "SOSR" },
	{ 5, 0xff060048, "SISR" },{ 5, 0xff06004c, "SIDR" },{ 5, 0xff060050, "SDSD" },

};


static constexpr int MaxSystemTables = 256; // FF00xxxx through FFFFxxxx
static constexpr int MaxSystemRegisters = 0x400; // FF0x0000 through FF0x0FFC
void r9751_state::system_trace_init()
{
	const SystemRegisterInfo*** trace_context;

	// Allocate tables for FF00 through FFFF
	trace_context = new const SystemRegisterInfo**[MaxSystemTables];
	memset(trace_context, 0, sizeof(void*)*MaxSystemTables);

	// Iterate over the system register info
	for (int i = 0; i < (sizeof(SystemRegisters) / sizeof(*SystemRegisters)); i++)
	{
		const SystemRegisterInfo* current = SystemRegisters + i;

		int table = (current->RegisterAddress & 0x00FF0000) >> 16;
		int regindex = (current->RegisterAddress & 0xFFFC) >> 2;

		if (table >= MaxSystemTables || regindex >= MaxSystemRegisters)
		{
			logerror("system_trace_init: Register out of range and cannot be traced: 0x%x %s\n", current->RegisterAddress, current->RegisterName);
			continue;
		}

		// Lookup the first tier table and create it if it doesn't exist
		const SystemRegisterInfo** firstTier = trace_context[table];
		if (firstTier == nullptr)
		{
			firstTier = new const SystemRegisterInfo*[MaxSystemRegisters];
			memset(firstTier, 0, sizeof(void*) * MaxSystemRegisters);
			trace_context[table] = firstTier;
		}

		// Set the content in the table
		firstTier[regindex] = current;

	}

	system_trace_context = trace_context;
}

void r9751_state::system_trace_teardown()
{
	for (int i = 0; i < MaxSystemTables; i++)
	{
		delete[] ((const SystemRegisterInfo***)system_trace_context)[i];
	}
	delete[] (const SystemRegisterInfo***)system_trace_context;
}

#if ENABLE_TRACE_SYSTEM
void r9751_state::trace_system(int table, int offset, int data, const char* direction)
{
	const SystemRegisterInfo*** trace_context = (const SystemRegisterInfo***)system_trace_context;

	const char* regName = "?";
	const char* regDescription = "?";
	int level = 10; // Undefined registers are level 10

	if (table < MaxSystemTables && offset < MaxSystemRegisters)
	{
		const SystemRegisterInfo** firstTier = trace_context[table];
		if (firstTier != nullptr)
		{
			const SystemRegisterInfo* current = firstTier[offset];
			if (current != nullptr)
			{
				regName = current->RegisterName;
				if (current->Description != nullptr) regDescription = current->Description;
				level = current->VerboseLevel;
			}
		}
	}

	if (level >= SYSTEM_TRACE_LEVEL)
	{
		u32 address = 0xFF000000 | (table << 16) | (offset << 2);
		logerror("%s System Register [%08X] (%s %s) %s %08X (PC=%08X)\n", machine().time().as_string(), address, regName, regDescription, direction, data, m_maincpu->pc());
	}

}
#else
void r9751_state::trace_system(int table, int offset, int data, const char* direction)
{
}
#endif


uint32_t r9751_state::swap_uint32( uint32_t val )
{
	val = ((val << 8) & 0xFF00FF00 ) | ((val >> 8) & 0xFF00FF );
	return (val << 16) | (val >> 16);
}

uint32_t r9751_state::debug_a6()
{
	return m_maincpu->space(AS_PROGRAM).read_dword(ptr_m68000->state_int(M68K_A6) + 4);
}

uint32_t r9751_state::debug_a5()
{
	return m_maincpu->space(AS_PROGRAM).read_dword(ptr_m68000->state_int(M68K_A5));
}

uint32_t r9751_state::debug_a5_20()
{
	return m_maincpu->space(AS_PROGRAM).read_dword(ptr_m68000->state_int(M68K_A5) + 0x20);
}

void r9751_state::UnifiedTrace(u32 address, u32 data, const char* operation, const char* Device, const char* RegisterName, const char* extraText)
{
	u32 stacktrace[4];
	u32 basepointer[2];
	u32 reg_a6 = ptr_m68000->state_int(M68K_A6);

	for(int i=0; i<4; i++)
		stacktrace[i] = 0;
	for(int i=0; i<2; i++)
		basepointer[i] = 0;

	stacktrace[0] = m_maincpu->pc();
	if(reg_a6 + 4 < 0xFFFFFF) stacktrace[1] = m_maincpu->space(AS_PROGRAM).read_dword(reg_a6 + 4);
	if(reg_a6 < 0xFFFFFF && reg_a6 != 0) basepointer[0] = m_maincpu->space(AS_PROGRAM).read_dword(reg_a6);
	if(basepointer[0] + 4 < 0xFFFFFF && basepointer[0] != 0) stacktrace[2] = m_maincpu->space(AS_PROGRAM).read_dword(basepointer[0] + 4);
	if(basepointer[0] < 0xFFFFFF && basepointer[0] != 0) basepointer[1] = m_maincpu->space(AS_PROGRAM).read_dword(basepointer[0]);
	if(basepointer[1] + 4 < 0xFFFFFF && basepointer[1] != 0) stacktrace[3] = m_maincpu->space(AS_PROGRAM).read_dword(basepointer[1] + 4);

	logerror("%s[%08X] => %08X (%s:%s) %s (%08X, %08X, %08X, %08X)\n", operation, address, data, Device, RegisterName==nullptr?"":RegisterName, extraText==nullptr?"":extraText, stacktrace[0], stacktrace[1], stacktrace[2], stacktrace[3]);
}

READ8_MEMBER(r9751_state::pdc_dma_r)
{
	/* This callback function takes the value written to 0xFF01000C as the bank offset */
	uint32_t address = (fdd_dma_bank & 0x7FFFF800) + (offset & 0x3FFFF);
	if (TRACE_DMA) logerror("DMA READ: %08X DATA: %08X\n", address, m_maincpu->space(AS_PROGRAM).read_byte(address));
	return m_maincpu->space(AS_PROGRAM).read_byte(address);
}

WRITE8_MEMBER(r9751_state::pdc_dma_w)
{
	/* This callback function takes the value written to 0xFF01000C as the bank offset */
	uint32_t address = (fdd_dma_bank & 0x7FFFF800) + (m_pdc->fdd_68k_dma_address & 0x3FFFF);
	m_maincpu->space(AS_PROGRAM).write_byte(address, data);
	if (TRACE_DMA) logerror("DMA WRITE: %08X DATA: %08X\n", address, data);
}

READ8_MEMBER(r9751_state::smioc_dma_r)
{
	/* This callback function takes the value written to 0xFF01000C as the bank offset */
	uint32_t address = (smioc_dma_bank & 0x7FFFF800) + (offset*2 & 0x3FFFF);
	u16 word = m_maincpu->space(AS_PROGRAM).read_word(address);
	char c = word & 0xFF;
	if (c < 32 || c > 127) c = ' ';
	if (TRACE_DMA) logerror("%s SMIOC DMA READ: %08X DATA: %04X (%c)\n", machine().time().as_string(), address, word, c);
	return m_maincpu->space(AS_PROGRAM).read_word(address) & 0x00FF;
}

WRITE8_MEMBER(r9751_state::smioc_dma_w)
{
	/* This callback function takes the value written to 0xFF01000C as the bank offset */
	uint32_t address = (smioc_dma_bank & 0x7FFFF800) + (offset*2 & 0x3FFFF);
	m_maincpu->space(AS_PROGRAM).write_word(address, data);
	char c = data & 0xFF;
	if (c < 32 || c > 127) c = ' ';
	if (TRACE_DMA) logerror("%s SMIOC DMA WRITE: %08X DATA: %08X (%c)\n", machine().time().as_string(), address, data, c);
}

void r9751_state::init_r9751()
{
	reg_ff050004 = 0;
	reg_fff80040 = 0;
	fdd_dest_address = 0;
	fdd_cmd_complete = 0;
	fdd_dma_bank = 0;
	smioc_dma_bank = 0;

	m_mem = &m_maincpu->space(AS_PROGRAM);

	m_maincpu->interface<m68000_base_device>(ptr_m68000);

	device_trace_enable_all();
	device_trace_disable(0x07);
	device_trace_disable(0x09);

	/* Save states */
	save_item(NAME(reg_ff050004));
	save_item(NAME(reg_fff80040));
	save_item(NAME(fdd_dest_address));
	save_item(NAME(fdd_cmd_complete));
	save_item(NAME(smioc_dma_bank));
	save_item(NAME(fdd_dma_bank));
	save_item(NAME(timer_32khz_last));

}

void r9751_state::machine_reset()
{
	uint8_t *rom = memregion("prom")->base();
	uint32_t *ram = m_main_ram;

	memcpy(ram, rom, 8);

	m_maincpu->reset();
	m_pdc->reset();
}

/******************************************************************************
 External board communication registers [0x5FF00000 - 0x5FFFFFFF]
******************************************************************************/
READ32_MEMBER( r9751_state::r9751_mmio_5ff_r )
{
	uint32_t data;
	switch(offset << 2)
	{
		/* PDC HDD region (0x24, device 9) */
		case 0x0824: /* HDD Command result code */
			data = 0x10;
			break;

		case 0x3024: /* HDD SCSI command completed successfully */
			data = 0x1;
			if(TRACE_HDC) logerror("SCSI HDD command completion status - Read: %08X, From: %08X, Register: %08X\n", data, m_maincpu->pc(), offset << 2 | 0x5FF00000);
			break;

		/* SMIOC region (0x98, device 0x26) */
		case 0x0898: /* Serial status or DMA status */
			data = m_smioc->GetStatus();
			break;

		case 0x0870: /* Serial status or DMA status 2 (0x70, device 0x24) */
			data = m_smioc->GetStatus2();
			break;
		/* SMIOC region (0x9C, device 0x27) */

		case 0x1098: /* Serial word count register */
			data = m_smioc->m_wordcount;
			m_smioc->ClearParameter();
			break;

		case 0x1070: /* Serial word count register (alternate) */
			data = m_smioc->m_wordcount2;
			m_smioc->ClearParameter2();
			break;

		case 0x2898: /* SMIOC DMA Busy register - nonzero = busy */
			data = m_smioc->m_deviceBusy;
			break;

		/* PDC FDD region (0xB0, device 44 */
		case 0x08B0: /* FDD Command result code */
			data = 0x10;
			break;

		case 0x10B0: /* Clear 5FF030B0 ?? */
			if(TRACE_FDC) logerror("--- FDD 0x5FF010B0 READ (0)\n");
			data = 0;
			break;

		case 0x1890: /* Device offset 0x90 (Bit 7 needs to be set) */
			data = 0x80;
			break;

		case 0x30B0: /* FDD command completion status */
			data = (m_pdc->reg_p5 << 8) + m_pdc->reg_p4;
			if(TRACE_FDC && data != 0) logerror("--- SCSI FDD command completion status - Read: %08X, From: %08X, Register: %08X\n", data, m_maincpu->pc(), offset << 2 | 0x5FF00000);
			break;

		default:
			data = 0;
			break;
	}
	trace_device(offset << 2 | 0x5FF00000, data, ">>");
	return data;
}

WRITE32_MEMBER( r9751_state::r9751_mmio_5ff_w )
{
	uint8_t data_b0, data_b1;

	trace_device(offset << 2 | 0x5FF00000, data, "<<");

	/* Unknown mask */
	if (mem_mask != 0xFFFFFFFF)
		logerror("Mask found: %08X Register: %08X PC: %08X\n", mem_mask, offset << 2 | 0x5FF00000, m_maincpu->pc());

	switch(offset << 2)
	{
		/* PDC HDD region (0x24, device 9) */

		/* SMIOC region (0x98, device 26) - Output */
		case 0x0298:
			m_smioc->ClearStatus();
			break;
		case 0x0270:
			m_smioc->ClearStatus2();
			break;
		case 0x4070: // SMIOC upper port command (ports 4-7)
			m_smioc->SendCommand2(data);
			break;
		case 0x8070: // SMIOC upper port parameter (ports 4-7)
			m_smioc->SetCommandParameter2(data);
			break;

		case 0x0198: // SMIOC soft reset?
			// It's not clear what exactly this register write does.
			//   It isn't a soft reset of the SMIOC because the 68k does not wait long enough for the SMIOC to finish rebooting.
			//   Also the 68k does this twice in succession, with a status clear in between.
			// The theory now is that a write to this register causes the status registers on the SMIOC to be
			//   set to the magic value 0x0100 (which is set after initialization is complete) - which serves as a trigger
			//   for the disktool software to reinitialize the SMIOC and proceed into a working state.
			// This probably isn't correct, but hopefully we will determine the correct approach in the future.

			m_smioc->m_status = 0x0140;
			m_smioc->m_status2 = 0x0140;
			break;

		case 0x4098: /* Serial DMA Command */
			m_smioc->SendCommand(data);
			break;
		case 0x8098: /* Command Parameter */
			m_smioc->SetCommandParameter(data);
			break;
		case 0xC098: /* Serial DMA Transmit data address */
			m_smioc->SetDmaParameter(smiocdma_sendaddress, data);
			break;

		/* SMIOC region (0x9C, device 27) - Input */
		case 0x409C: /* Serial DMA write length */
			m_smioc->SetDmaParameter(smiocdma_sendlength, data);
			break;
		case 0x809C: /* Serial DMA Receive data address */
			m_smioc->SetDmaParameter(smiocdma_recvaddress, data);
			break;
		case 0xC09C: /* Serial DMA read length */
			m_smioc->SetDmaParameter(smiocdma_recvlength, data);
			break;

		/* PDC FDD region (0xB0, device 44) */
		case 0x04B0: /* FDD RESET PDC */
			if(TRACE_FDC) logerror("PDC RESET, PC: %08X DATA: %08X\n", m_maincpu->pc(), data);
			m_pdc->reset();
			break;
		case 0x41B0: /* Unknown - Probably old style commands */
			if(TRACE_FDC) logerror("--- FDD Command: %08X, From: %08X, Register: %08X\n", data, m_maincpu->pc(), offset << 2 | 0x5FF00000);

			/* Clear FDD Command completion status 0x5FF030B0 (PDC 0x4, 0x5) */
			m_pdc->reg_p4 = 0;
			m_pdc->reg_p5 = 0;

			data_b0 = data & 0xFF;
			data_b1 = (data & 0xFF00) >> 8;
			m_pdc->reg_p0 = data_b0;
			m_pdc->reg_p1 = data_b1;
			m_pdc->reg_p38 |= 0x2; /* Set bit 1 on port 38 register, PDC polls this port looking for a command */
			if(TRACE_FDC) logerror("--- FDD Old Command: %02X and %02X\n", data_b0, data_b1);
			break;
		case 0xC0B0:
		case 0xC1B0: /* fdd_dest_address register */
			fdd_dest_address = data << 1;
			if(TRACE_FDC) logerror("--- FDD destination address: %08X PC: %08X Register: %08X (A6+4): %08X\n", (fdd_dma_bank & 0x7FFFF800) + (fdd_dest_address&0x3FFFF), m_maincpu->pc(), offset << 2 | 0x5FF00000, debug_a6());
			data_b0 = data & 0xFF;
			data_b1 = (data & 0xFF00) >> 8;
			m_pdc->reg_p6 = data_b0;
			m_pdc->reg_p7 = data_b1;
			m_pdc->reg_p38 |= 0x2; // Set bit 1 on port 38 register, PDC polls this port looking for a command
			if(TRACE_FDC)logerror("--- FDD SET PDC Port 38: %X\n",m_pdc->reg_p38);
			break;
		case 0x80B0: /* FDD command address register */
			uint32_t fdd_scsi_command;
			uint32_t fdd_scsi_command2;
			unsigned char c_fdd_scsi_command[8]; // Array for SCSI command
			int scsi_lba; // FDD LBA location here, extracted from command

			/* Clear FDD Command completion status 0x5FF030B0 (PDC 0x4, 0x5) */
			m_pdc->reg_p4 = 0;
			m_pdc->reg_p5 = 0;

			/* Send FDD SCSI command location address to PDC 0x2, 0x3 */
			if(TRACE_FDC) logerror("--- FDD command address: %08X PC: %08X Register: %08X (A6+4): %08X A4: %08X (A5): %08X (A5+20): %08X\n", (fdd_dma_bank & 0x7FFFF800) + ((data << 1)&0x3FFFF), m_maincpu->pc(), offset << 2 | 0x5FF00000, debug_a6(), ptr_m68000->state_int(M68K_A4), debug_a5(), debug_a5_20());
			data_b0 = data & 0xFF;
			data_b1 = (data & 0xFF00) >> 8;
			m_pdc->reg_p2 = data_b0;
			m_pdc->reg_p3 = data_b1;

			fdd_scsi_command = swap_uint32(m_mem->read_dword((fdd_dma_bank & 0x7FFFF800) + ((data << 1)&0x3FFFF)));
			fdd_scsi_command2 = swap_uint32(m_mem->read_dword(((fdd_dma_bank & 0x7FFFF800) + ((data << 1)&0x3FFFF))+4));

			memcpy(c_fdd_scsi_command,&fdd_scsi_command,4);
			memcpy(c_fdd_scsi_command+4,&fdd_scsi_command2,4);

			if(TRACE_FDC)
			{
				logerror("--- FDD SCSI Command: ");
				for(int i = 0; i < 8; i++)
					logerror("%02X ", c_fdd_scsi_command[i]);
				logerror("\n");
			}

			scsi_lba = c_fdd_scsi_command[3] | (c_fdd_scsi_command[2]<<8) | ((c_fdd_scsi_command[1]&0x1F)<<16);
			if(TRACE_FDC) logerror("--- FDD SCSI LBA: %i\n", scsi_lba);

			break;

		default:
			break;
	}
}

/******************************************************************************
 CPU board registers [0xFF010000 - 0xFF06FFFF]
******************************************************************************/
READ32_MEMBER( r9751_state::r9751_mmio_ff01_r )
{
	u32 data;
	switch(offset << 2)
	{
		default:
			data = 0;
	}
	trace_system(1, offset, data, ">>");
	return data;
}

WRITE32_MEMBER( r9751_state::r9751_mmio_ff01_w )
{
	/* Unknown mask */
	if (mem_mask != 0xFFFFFFFF)
		logerror("Mask found: %08X Register: %08X PC: %08X\n", mem_mask, offset << 2 | 0xFF010000, m_maincpu->pc());

	trace_system(1, offset, data, "<<");

	switch(offset << 2)
	{
		case 0x000C: /* FDD DMA Offset */
			fdd_dma_bank = data;
			if(TRACE_DMA) logerror("Banking register(FDD): %08X PC: %08X Data: %08X\n", offset << 2 | 0xFF010000, m_maincpu->pc(), data);
			return;
		case 0x0010: /* SMIOC DMA Offset */
			smioc_dma_bank = data;
			if(TRACE_DMA) logerror("Banking register(SMIOC): %08X PC: %08X Data: %08X\n", offset << 2 | 0xFF010000, m_maincpu->pc(), data);
			return;
		default:
			if(TRACE_DMA) logerror("Banking register(Unknown): %08X PC: %08X Data: %08X\n", offset << 2 | 0xFF010000, m_maincpu->pc(), data);
			return;
	}
}

READ32_MEMBER( r9751_state::r9751_mmio_ff05_r )
{
	uint32_t data;

	switch(offset << 2)
	{
		case 0x0004:
			data = reg_ff050004;
			break;
		case 0x0300:
			data = 0x1B | (1<<0x14);
			break;
		case 0x0320: /* Some type of counter */
			data = (machine().time() - timer_32khz_last).as_ticks(32768) & 0xFFFF;
			break;
		case 0x0584:
			data = 0;
			break;
		case 0x0610:
			data = 0xabacabac;
			break;
		case 0x0014:
			data = 0x80;
			break;
		default:
			data = 0;
			break;
	}
	trace_system(5, offset, data, "<<");
	return data;
}

WRITE32_MEMBER( r9751_state::r9751_mmio_ff05_w )
{
	/* Unknown mask */
	if (mem_mask != 0xFFFFFFFF)
		logerror("Mask found: %08X Register: %08X PC: %08X\n", mem_mask, offset << 2 | 0xFF050000, m_maincpu->pc());

	trace_system(5, offset, data, ">>");

	switch(offset << 2)
	{
		case 0x0004:
			reg_ff050004 = data;
			return;
		case 0x000C: /* CPU LED hex display indicator */
			if(TRACE_LED) logerror("\n*** LED: %02x, Instruction: %08x ***\n\n", data, m_maincpu->pc());
			return;
		case 0x0320:
			timer_32khz_last = machine().time();
			return;
		default:
			return;
	}
}

READ32_MEMBER( r9751_state::r9751_mmio_fff8_r )
{
	uint32_t data;

	switch(offset << 2)
	{
		case 0x0040:
			data = reg_fff80040;
			break;
		default:
			data = 0;
			break;
	}
	trace_system(5, offset, data, "<<");
	return data;
}

WRITE32_MEMBER( r9751_state::r9751_mmio_fff8_w )
{
	/* Unknown mask */
	if (mem_mask != 0xFFFFFFFF)
		logerror("Mask found: %08X Register: %08X PC: %08X\n", mem_mask, offset << 2 | 0xFFF80000, m_maincpu->pc());

	trace_system(5, offset, data, ">>");

	switch(offset << 2)
	{
		case 0x0040:
			reg_fff80040 = data;
			return;
		default:
			return;
	}
}

/******************************************************************************
 Address Maps
******************************************************************************/

void r9751_state::r9751_mem(address_map &map)
{
	//ADDRESS_MAP_UNMAP_HIGH
	map(0x00000000, 0x00ffffff).ram().share("main_ram"); // 16MB
	map(0x08000000, 0x0800ffff).rom().region("prom", 0);
	map(0x5FF00000, 0x5FFFFFFF).rw(FUNC(r9751_state::r9751_mmio_5ff_r), FUNC(r9751_state::r9751_mmio_5ff_w));
	map(0xFF010000, 0xFF01FFFF).rw(FUNC(r9751_state::r9751_mmio_ff01_r), FUNC(r9751_state::r9751_mmio_ff01_w));
	map(0xFF050000, 0xFF06FFFF).rw(FUNC(r9751_state::r9751_mmio_ff05_r), FUNC(r9751_state::r9751_mmio_ff05_w));
	map(0xFFF80000, 0xFFF8FFFF).rw(FUNC(r9751_state::r9751_mmio_fff8_r), FUNC(r9751_state::r9751_mmio_fff8_w));
	//AM_RANGE(0xffffff00,0xffffffff) AM_RAM // Unknown area
}

/******************************************************************************
 Input Ports
******************************************************************************/
static INPUT_PORTS_START( r9751 )
INPUT_PORTS_END

/******************************************************************************
 Machine Drivers
******************************************************************************/

MACHINE_CONFIG_START(r9751_state::r9751)
	/* basic machine hardware */
	MCFG_DEVICE_ADD("maincpu", M68030, 20000000)
	MCFG_DEVICE_PROGRAM_MAP(r9751_mem)
	MCFG_QUANTUM_TIME(attotime::from_hz(1000))

	/* i/o hardware */
	SMIOC(config, m_smioc, 0);
	m_smioc->m68k_r_callback().set(FUNC(r9751_state::smioc_dma_r));
	m_smioc->m68k_w_callback().set(FUNC(r9751_state::smioc_dma_w));

	/* disk hardware */
	PDC(config, m_pdc, 0);
	m_pdc->m68k_r_callback().set(FUNC(r9751_state::pdc_dma_r));
	m_pdc->m68k_w_callback().set(FUNC(r9751_state::pdc_dma_w));
	MCFG_DEVICE_ADD("scsi", SCSI_PORT, 0)
	WD33C93(config, m_wd33c93);
	m_wd33c93->set_scsi_port("scsi");

	/* software list */
	MCFG_SOFTWARE_LIST_ADD("flop_list","r9751")
MACHINE_CONFIG_END



/******************************************************************************
 ROM Definitions
******************************************************************************/

ROM_START(r9751)
	ROM_REGION32_BE(0x00010000, "prom", 0)
	ROM_SYSTEM_BIOS(0, "prom34",  "PROM Version 3.4")
	ROMX_LOAD( "p-n_98d4643__abaco_v3.4__=49fe7a=__j221.27512.bin", 0x0000, 0x10000, CRC(9fb19a85) SHA1(c861e15a2fc9a4ef689c2034c53fbb36f17f7da6), ROM_GROUPWORD | ROM_BIOS(0) ) // Label: "P/N 98D4643 // ABACO V3.4 // (49FE7A) // J221" 27512 @Unknown

	ROM_SYSTEM_BIOS(1, "prom42", "PROM Version 4.2")
	ROMX_LOAD( "98d5731__zebra_v4.2__4cd79d.u5", 0x0000, 0x10000, CRC(e640f8df) SHA1(a9e4fa271d7f2f3a134e2120932ec088d5b8b007), ROM_GROUPWORD | ROM_BIOS(1) ) // Label: 98D5731 // ZEBRA V4.2 // 4CD79D 27512 @Unknown
ROM_END



/******************************************************************************
 Drivers
******************************************************************************/

//    YEAR  NAME   PARENT  COMPAT  MACHINE  INPUT  CLASS        INIT        COMPANY               FULLNAME              FLAGS
COMP( 1988, r9751, 0,      0,      r9751,   r9751, r9751_state, init_r9751, "ROLM Systems, Inc.", "ROLM 9751 Model 10", MACHINE_NO_SOUND | MACHINE_NOT_WORKING )