1 // license:BSD-3-Clause
2 // copyright-holders:Wilbert Pol
3 /*
4  * msx.c: MSX emulation
5  *
6  * Copyright (C) 2004 Sean Young
7  *
8  * Todo:
9  *
10  * - fix mouse support
11  * - cassette support doesn't work
12  * - Ensure changing cartridge after boot works
13  * - wd2793, nms8255
14  */
15 
16 #include "emu.h"
17 #include "includes/msx.h"
18 
19 #define VERBOSE 0
20 
21 
machine_reset()22 void msx_state::machine_reset()
23 {
24 	msx_memory_reset ();
25 	msx_memory_map_all ();
26 }
27 
28 
machine_start()29 void msx_state::machine_start()
30 {
31 	m_leds.resolve();
32 	m_port_c_old = 0xff;
33 }
34 
35 
machine_start()36 void msx2_state::machine_start()
37 {
38 	msx_state::machine_start();
39 
40 	for (device_t &device : device_iterator(*this))
41 	{
42 		msx_switched_interface *switched;
43 		if (device.interface(switched))
44 		{
45 			m_switched.push_back(switched);
46 		}
47 	}
48 
49 	save_item(NAME(m_rtc_latch));
50 }
51 
52 
53 static const uint8_t cc_op[0x100] = {
54 	4+1,10+1, 7+1, 6+1, 4+1, 4+1, 7+1, 4+1, 4+1,11+1, 7+1, 6+1, 4+1, 4+1, 7+1, 4+1,
55 	8+1,10+1, 7+1, 6+1, 4+1, 4+1, 7+1, 4+1,12+1,11+1, 7+1, 6+1, 4+1, 4+1, 7+1, 4+1,
56 	7+1,10+1,16+1, 6+1, 4+1, 4+1, 7+1, 4+1, 7+1,11+1,16+1, 6+1, 4+1, 4+1, 7+1, 4+1,
57 	7+1,10+1,13+1, 6+1,11+1,11+1,10+1, 4+1, 7+1,11+1,13+1, 6+1, 4+1, 4+1, 7+1, 4+1,
58 	4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
59 	4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
60 	4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
61 	7+1, 7+1, 7+1, 7+1, 7+1, 7+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
62 	4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
63 	4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
64 	4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
65 	4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
66 	5+1,10+1,10+1,10+1,10+1,11+1, 7+1,11+1, 5+1,10+1,10+1, 0  ,10+1,17+1, 7+1,11+1,
67 	5+1,10+1,10+1,11+1,10+1,11+1, 7+1,11+1, 5+1, 4+1,10+1,11+1,10+1, 0  , 7+1,11+1,
68 	5+1,10+1,10+1,19+1,10+1,11+1, 7+1,11+1, 5+1, 4+1,10+1, 4+1,10+1, 0  , 7+1,11+1,
69 	5+1,10+1,10+1, 4+1,10+1,11+1, 7+1,11+1, 5+1, 6+1,10+1, 4+1,10+1, 0  , 7+1,11+1
70 };
71 
72 static const uint8_t cc_cb[0x100] = {
73 	8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
74 	8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
75 	8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
76 	8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
77 	8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2,
78 	8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2,
79 	8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2,
80 	8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2,
81 	8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
82 	8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
83 	8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
84 	8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
85 	8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
86 	8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
87 	8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
88 	8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2
89 };
90 
91 static const uint8_t cc_ed[0x100] = {
92 	8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
93 	8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
94 	8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
95 	8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
96 12+2,12+2,15+2,20+2, 8+2,14+2, 8+2, 9+2,12+2,12+2,15+2,20+2, 8+2,14+2, 8+2, 9+2,
97 12+2,12+2,15+2,20+2, 8+2,14+2, 8+2, 9+2,12+2,12+2,15+2,20+2, 8+2,14+2, 8+2, 9+2,
98 12+2,12+2,15+2,20+2, 8+2,14+2, 8+2,18+2,12+2,12+2,15+2,20+2, 8+2,14+2, 8+2,18+2,
99 12+2,12+2,15+2,20+2, 8+2,14+2, 8+2, 8+2,12+2,12+2,15+2,20+2, 8+2,14+2, 8+2, 8+2,
100 	8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
101 	8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
102 16+2,16+2,16+2,16+2, 8+2, 8+2, 8+2, 8+2,16+2,16+2,16+2,16+2, 8+2, 8+2, 8+2, 8+2,
103 16+2,16+2,16+2,16+2, 8+2, 8+2, 8+2, 8+2,16+2,16+2,16+2,16+2, 8+2, 8+2, 8+2, 8+2,
104 	8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
105 	8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
106 	8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
107 	8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2
108 };
109 
110 static const uint8_t cc_xy[0x100] = {
111 	4+4+2,10+4+2, 7+4+2, 6+4+2, 4+4+2, 4+4+2, 7+4+2, 4+4+2, 4+4+2,11+4+2, 7+4+2, 6+4+2, 4+4+2, 4+4+2, 7+4+2, 4+4+2,
112 	8+4+2,10+4+2, 7+4+2, 6+4+2, 4+4+2, 4+4+2, 7+4+2, 4+4+2,12+4+2,11+4+2, 7+4+2, 6+4+2, 4+4+2, 4+4+2, 7+4+2, 4+4+2,
113 	7+4+2,10+4+2,16+4+2, 6+4+2, 4+4+2, 4+4+2, 7+4+2, 4+4+2, 7+4+2,11+4+2,16+4+2, 6+4+2, 4+4+2, 4+4+2, 7+4+2, 4+4+2,
114 	7+4+2,10+4+2,13+4+2, 6+4+2,23  +2,23  +2,19  +2, 4+4+2, 7+4+2,11+4+2,13+4+2, 6+4+2, 4+4+2, 4+4+2, 7+4+2, 4+4+2,
115 	4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2,19  +2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2,19  +2, 4+4+2,
116 	4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2,19  +2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2,19  +2, 4+4+2,
117 	4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2,19  +2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2,19  +2, 4+4+2,
118 19  +2,19  +2,19  +2,19  +2,19  +2,19  +2, 4+4+2,19  +2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2,19  +2, 4+4+2,
119 	4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2,19  +2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2,19  +2, 4+4+2,
120 	4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2,19  +2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2,19  +2, 4+4+2,
121 	4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2,19  +2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2,19  +2, 4+4+2,
122 	4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2,19  +2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2, 4+4+2,19  +2, 4+4+2,
123 	5+4+2,10+4+2,10+4+2,10+4+2,10+4+2,11+4+2, 7+4+2,11+4+2, 5+4+2,10+4+2,10+4+2, 0    ,10+4+2,17+4+2, 7+4+2,11+4+2,
124 	5+4+2,10+4+2,10+4+2,11+4+2,10+4+2,11+4+2, 7+4+2,11+4+2, 5+4+2, 4+4+2,10+4+2,11+4+2,10+4+2, 4  +1, 7+4+2,11+4+2,
125 	5+4+2,10+4+2,10+4+2,19+4+2,10+4+2,11+4+2, 7+4+2,11+4+2, 5+4+2, 4+4+2,10+4+2, 4+4+2,10+4+2, 4  +1, 7+4+2,11+4+2,
126 	5+4+2,10+4+2,10+4+2, 4+4+2,10+4+2,11+4+2, 7+4+2,11+4+2, 5+4+2, 6+4+2,10+4+2, 4+4+2,10+4+2, 4  +1, 7+4+2,11+4+2
127 };
128 
129 static const uint8_t cc_xycb[0x100] = {
130 23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
131 23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
132 23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
133 23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
134 20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,
135 20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,
136 20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,
137 20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,
138 23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
139 23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
140 23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
141 23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
142 23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
143 23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
144 23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
145 23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2
146 };
147 
148 /* extra cycles if jr/jp/call taken and 'interrupt latency' on rst 0-7 */
149 static const uint8_t cc_ex[0x100] = {
150 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
151 	5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* DJNZ */
152 	5, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, /* JR NZ/JR Z */
153 	5, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, /* JR NC/JR C */
154 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
155 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
156 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
157 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
158 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
159 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
160 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
161 	5, 5, 5, 5, 0, 0, 0, 0, 5, 5, 5, 5, 0, 0, 0, 0, /* LDIR/CPIR/INIR/OTIR LDDR/CPDR/INDR/OTDR */
162 	6, 0, 0, 0, 7, 0, 0, 2, 6, 0, 0, 0, 7, 0, 0, 2,
163 	6, 0, 0, 0, 7, 0, 0, 2, 6, 0, 0, 0, 7, 0, 0, 2,
164 	6, 0, 0, 0, 7, 0, 0, 2, 6, 0, 0, 0, 7, 0, 0, 2,
165 	6, 0, 0, 0, 7, 0, 0, 2, 6, 0, 0, 0, 7, 0, 0, 2+1
166 };
167 
168 
driver_start()169 void msx_state::driver_start()
170 {
171 	m_maincpu->set_input_line_vector(0, 0xff); // Z80
172 
173 	msx_memory_init();
174 
175 	m_maincpu->z80_set_cycle_tables( cc_op, cc_cb, cc_ed, cc_xy, cc_xycb, cc_ex );
176 
177 	save_item(NAME(m_psg_b));
178 	save_item(NAME(m_mouse));
179 	save_item(NAME(m_mouse_stat));
180 	save_item(NAME(m_kanji_latch));
181 	save_item(NAME(m_slot_expanded));
182 	save_item(NAME(m_primary_slot));
183 	save_item(NAME(m_secondary_slot));
184 	save_item(NAME(m_port_c_old));
185 	save_item(NAME(m_keylatch));
186 }
187 
device_post_load()188 void msx_state::device_post_load()
189 {
190 	for (int page = 0; page < 4; page++)
191 	{
192 		int slot_primary = (m_primary_slot >> (page * 2)) & 3;
193 		int slot_secondary = (m_secondary_slot[slot_primary] >> (page * 2)) & 3;
194 
195 		m_current_page[page] = m_all_slots[slot_primary][slot_secondary][page];
196 	}
197 }
198 
INTERRUPT_GEN_MEMBER(msx_state::msx_interrupt)199 INTERRUPT_GEN_MEMBER(msx_state::msx_interrupt)
200 {
201 	m_mouse[0] = m_io_mouse[0]->read();
202 	m_mouse_stat[0] = -1;
203 	m_mouse[1] = m_io_mouse[1]->read();
204 	m_mouse_stat[1] = -1;
205 }
206 
207 /*
208 ** The I/O functions
209 */
210 
211 
msx_psg_port_a_r()212 uint8_t msx_state::msx_psg_port_a_r()
213 {
214 	uint8_t data = (m_cassette->input() > 0.0038 ? 0x80 : 0);
215 
216 	if ( (m_psg_b ^ m_io_dsw->read() ) & 0x40)
217 	{
218 		/* game port 2 */
219 		uint8_t inp = m_io_joy[1]->read();
220 		if ( !(inp & 0x80) )
221 		{
222 			/* joystick */
223 			data |= ( inp & 0x7f );
224 		}
225 		else
226 		{
227 			/* mouse */
228 			data |= ( inp & 0x70 );
229 			if (m_mouse_stat[1] < 0)
230 				data |= 0xf;
231 			else
232 				data |= ~(m_mouse[1] >> (4*m_mouse_stat[1]) ) & 15;
233 		}
234 	}
235 	else
236 	{
237 		/* game port 1 */
238 		uint8_t inp = m_io_joy[0]->read();
239 		if ( !(inp & 0x80) )
240 		{
241 			/* joystick */
242 			data |= ( inp & 0x7f );
243 		}
244 		else
245 		{
246 			/* mouse */
247 			data |= ( inp & 0x70 );
248 			if (m_mouse_stat[0] < 0)
249 				data |= 0xf;
250 			else
251 				data |= ~(m_mouse[0] >> (4*m_mouse_stat[0]) ) & 15;
252 		}
253 	}
254 
255 	return data;
256 }
257 
msx_psg_port_b_r()258 uint8_t msx_state::msx_psg_port_b_r()
259 {
260 	return m_psg_b;
261 }
262 
msx_psg_port_a_w(uint8_t data)263 void msx_state::msx_psg_port_a_w(uint8_t data)
264 {
265 }
266 
msx_psg_port_b_w(uint8_t data)267 void msx_state::msx_psg_port_b_w(uint8_t data)
268 {
269 	/* Arabic or kana mode led */
270 	if ( (data ^ m_psg_b) & 0x80)
271 		m_leds[1] = BIT(~data, 7);
272 
273 	if ( (m_psg_b ^ data) & 0x10)
274 	{
275 		if (++m_mouse_stat[0] > 3) m_mouse_stat[0] = -1;
276 	}
277 	if ( (m_psg_b ^ data) & 0x20)
278 	{
279 		if (++m_mouse_stat[1] > 3) m_mouse_stat[1] = -1;
280 	}
281 
282 	m_psg_b = data;
283 }
284 
285 
286 /*
287 ** RTC functions
288 */
289 
msx_rtc_latch_w(uint8_t data)290 void msx2_state::msx_rtc_latch_w(uint8_t data)
291 {
292 	m_rtc_latch = data & 15;
293 }
294 
msx_rtc_reg_w(uint8_t data)295 void msx2_state::msx_rtc_reg_w(uint8_t data)
296 {
297 	m_rtc->write(m_rtc_latch, data);
298 }
299 
msx_rtc_reg_r()300 uint8_t msx2_state::msx_rtc_reg_r()
301 {
302 	return m_rtc->read(m_rtc_latch);
303 }
304 
305 
306 /*
307 ** The PPI functions
308 */
309 
msx_ppi_port_a_w(uint8_t data)310 void msx_state::msx_ppi_port_a_w(uint8_t data)
311 {
312 	m_primary_slot = data;
313 
314 	if (VERBOSE)
315 		logerror ("write to primary slot select: %02x\n", m_primary_slot);
316 	msx_memory_map_all ();
317 }
318 
msx_ppi_port_c_w(uint8_t data)319 void msx_state::msx_ppi_port_c_w(uint8_t data)
320 {
321 	m_keylatch = data & 0x0f;
322 
323 	/* caps lock */
324 	if ( BIT(m_port_c_old ^ data, 6) )
325 		m_leds[0] = BIT(~data, 6);
326 
327 	/* key click */
328 	if ( BIT(m_port_c_old ^ data, 7) )
329 		m_dac->write(BIT(data, 7));
330 
331 	/* cassette motor on/off */
332 	if ( BIT(m_port_c_old ^ data, 4) )
333 		m_cassette->change_state(BIT(data, 4) ? CASSETTE_MOTOR_DISABLED : CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR);
334 
335 	/* cassette signal write */
336 	if ( BIT(m_port_c_old ^ data, 5) )
337 		m_cassette->output(BIT(data, 5) ? -1.0 : 1.0);
338 
339 	m_port_c_old = data;
340 }
341 
msx_ppi_port_b_r()342 uint8_t msx_state::msx_ppi_port_b_r()
343 {
344 	uint8_t result = 0xff;
345 	int row, data;
346 
347 	row = m_keylatch;
348 	if (row <= 10)
349 	{
350 		data = m_io_key[row / 2]->read();
351 
352 		if (BIT(row, 0))
353 			data >>= 8;
354 		result = data & 0xff;
355 	}
356 	return result;
357 }
358 
359 /************************************************************************
360  *
361  * New memory emulation !!
362  *
363  ***********************************************************************/
364 
install_slot_pages(uint8_t prim,uint8_t sec,uint8_t page,uint8_t numpages,msx_internal_slot_interface & device)365 void msx_state::install_slot_pages(uint8_t prim, uint8_t sec, uint8_t page, uint8_t numpages, msx_internal_slot_interface &device)
366 {
367 	for ( int i = page; i < std::min(page + numpages, 4); i++ )
368 	{
369 		m_all_slots[prim][sec][i] = &device;
370 	}
371 	if ( sec )
372 	{
373 		m_slot_expanded[prim] = true;
374 	}
375 }
376 
msx_memory_init()377 void msx_state::msx_memory_init()
378 {
379 	int count_populated_pages = 0;
380 
381 	// Populate all unpopulated slots with the dummy interface
382 	for (auto & elem : m_all_slots)
383 	{
384 		for ( int sec = 0; sec < 4; sec++ )
385 		{
386 			for ( int page = 0; page < 4; page++ )
387 			{
388 				if ( elem[sec][page] == nullptr )
389 				{
390 					elem[sec][page] = &m_empty_slot;
391 				}
392 				else
393 				{
394 					count_populated_pages++;
395 				}
396 			}
397 		}
398 	}
399 
400 	if ( count_populated_pages == 0 ) {
401 		fatalerror("No msx slot layout defined for this system!\n");
402 	}
403 }
404 
msx_memory_reset()405 void msx_state::msx_memory_reset ()
406 {
407 	m_primary_slot = 0;
408 
409 	for (auto & elem : m_secondary_slot)
410 	{
411 		elem = 0;
412 	}
413 }
414 
msx_memory_map_page(uint8_t page)415 void msx_state::msx_memory_map_page (uint8_t page)
416 {
417 	int slot_primary = (m_primary_slot >> (page * 2)) & 3;
418 	int slot_secondary = (m_secondary_slot[slot_primary] >> (page * 2)) & 3;
419 
420 	m_current_page[page] = m_all_slots[slot_primary][slot_secondary][page];
421 }
422 
msx_memory_map_all()423 void msx_state::msx_memory_map_all ()
424 {
425 	for (uint8_t i=0; i<4; i++)
426 		msx_memory_map_page (i);
427 }
428 
msx_mem_read(offs_t offset)429 uint8_t msx_state::msx_mem_read(offs_t offset)
430 {
431 	return m_current_page[offset >> 14]->read(offset);
432 }
433 
msx_mem_write(offs_t offset,uint8_t data)434 void msx_state::msx_mem_write(offs_t offset, uint8_t data)
435 {
436 	m_current_page[offset >> 14]->write(offset, data);
437 }
438 
msx_sec_slot_w(uint8_t data)439 void msx_state::msx_sec_slot_w(uint8_t data)
440 {
441 	int slot = m_primary_slot >> 6;
442 	if (m_slot_expanded[slot])
443 	{
444 		if (VERBOSE)
445 			logerror ("write to secondary slot %d select: %02x\n", slot, data);
446 
447 		m_secondary_slot[slot] = data;
448 		msx_memory_map_all ();
449 	}
450 	else
451 		m_current_page[3]->write(0xffff, data);
452 }
453 
msx_sec_slot_r()454 uint8_t msx_state::msx_sec_slot_r()
455 {
456 	int slot = m_primary_slot >> 6;
457 
458 	if (m_slot_expanded[slot])
459 	{
460 		return ~m_secondary_slot[slot];
461 	}
462 	else
463 	{
464 		return m_current_page[3]->read(0xffff);
465 	}
466 }
467 
msx_kanji_r(offs_t offset)468 uint8_t msx_state::msx_kanji_r(offs_t offset)
469 {
470 	uint8_t result = 0xff;
471 
472 	if (offset && m_region_kanji)
473 	{
474 		int latch = m_kanji_latch;
475 		result = m_region_kanji->as_u8(latch++);
476 
477 		m_kanji_latch &= ~0x1f;
478 		m_kanji_latch |= latch & 0x1f;
479 	}
480 	return result;
481 }
482 
msx_kanji_w(offs_t offset,uint8_t data)483 void msx_state::msx_kanji_w(offs_t offset, uint8_t data)
484 {
485 	if (offset)
486 		m_kanji_latch = (m_kanji_latch & 0x007E0) | ((data & 0x3f) << 11);
487 	else
488 		m_kanji_latch = (m_kanji_latch & 0x1f800) | ((data & 0x3f) << 5);
489 }
490 
msx_switched_r(offs_t offset)491 uint8_t msx2_state::msx_switched_r(offs_t offset)
492 {
493 	uint8_t data = 0xff;
494 
495 	for (int i = 0; i < m_switched.size(); i++)
496 	{
497 		data &= m_switched[i]->switched_read(offset);
498 	}
499 
500 	return data;
501 }
502 
msx_switched_w(offs_t offset,uint8_t data)503 void msx2_state::msx_switched_w(offs_t offset, uint8_t data)
504 {
505 	for (int i = 0; i < m_switched.size(); i++)
506 	{
507 		m_switched[i]->switched_write(offset, data);
508 	}
509 }
510