1 // license:BSD-3-Clause
2 // copyright-holders:Miodrag Milanovic, AJR
3 /***************************************************************************
4 
5         PK-8020 driver by Miodrag Milanovic
6             based on work of Sergey Erokhin from pk8020.narod.ru
7 
8         18/07/2008 Preliminary driver.
9 
10 ****************************************************************************/
11 
12 
13 #include "emu.h"
14 #include "includes/pk8020.h"
15 
16 #define DESCRIBE_DECPLM 1
17 
18 
keyboard_r(offs_t offset)19 uint8_t pk8020_state::keyboard_r(offs_t offset)
20 {
21 	uint8_t result = 0xff;
22 
23 	if (BIT(offset, 8))
24 	{
25 		for (uint8_t line = 8; line < 16; line++)
26 			if (BIT(offset, line - 8))
27 				result &= m_io_port[line]->read();
28 	}
29 	else
30 	{
31 		for (uint8_t line = 0; line < 8; line++)
32 			if (BIT(offset, line))
33 				result &= m_io_port[line]->read();
34 	}
35 
36 	return result ^ 0xff;
37 }
38 
sysreg_w(offs_t offset,uint8_t data)39 void pk8020_state::sysreg_w(offs_t offset, uint8_t data)
40 {
41 	if (!BIT(offset, 7))
42 	{
43 		m_bank_select = data & 0xfc;
44 		logerror("%s: Bank select = %02X\n", machine().describe_context(), (data >> 2) & 0x1f);
45 	}
46 
47 	if (!BIT(offset, 6))
48 		color_w(data);
49 	if (!BIT(offset, 2))
50 		palette_w(data);
51 }
52 
memory_r(offs_t offset)53 uint8_t pk8020_state::memory_r(offs_t offset)
54 {
55 	uint8_t select = m_decplm->read(bitswap<13>((offset & 0xff00) | m_bank_select, 2, 5, 6, 4, 12, 3, 13, 8, 9, 11, 15, 10, 14) | 0x8000);
56 	uint8_t result = 0xff;
57 
58 	if (!BIT(select, 2))
59 		result &= m_region_maincpu->base()[offset & 0x1fff];
60 	if (!BIT(select, 3))
61 		result &= m_region_maincpu->base()[(offset & 0x1fff) | 0x2000];
62 	if (!BIT(select, 0))
63 		result &= m_region_maincpu->base()[(offset & 0x1fff) | 0x4000];
64 	if (!BIT(select, 1))
65 		result &= keyboard_r(offset);
66 	if (!BIT(select, 4))
67 		result &= m_devbank->read8(offset);
68 
69 	if ((select & 0xc0) == 0x00)
70 		result &= m_ram->pointer()[offset];
71 	else if ((select & 0xc0) == 0x40)
72 		result &= gzu_r(offset & 0x3fff);
73 	else if ((select & 0xc0) == 0x80)
74 		result &= text_r(offset & 0x3ff);
75 
76 	return result;
77 }
78 
memory_w(offs_t offset,uint8_t data)79 void pk8020_state::memory_w(offs_t offset, uint8_t data)
80 {
81 	uint8_t select = m_decplm->read(bitswap<13>((offset & 0xff00) | m_bank_select, 2, 5, 6, 4, 12, 3, 13, 8, 9, 11, 15, 10, 14) | 0x2000);
82 
83 	if (!BIT(select, 5))
84 		sysreg_w(offset, data);
85 	if (!BIT(select, 4))
86 		m_devbank->write8(offset, data);
87 
88 	if ((select & 0xc0) == 0x00)
89 		m_ram->pointer()[offset] = data;
90 	else if ((select & 0xc0) == 0x40)
91 		gzu_w(offset & 0x3fff, data);
92 	else if ((select & 0xc0) == 0x80)
93 		text_w(offset & 0x3ff, data);
94 }
95 
ppi_porta_r()96 uint8_t pk8020_state::ppi_porta_r()
97 {
98 	return 0xf0 | (m_takt <<1) | (m_text_attr<<3) | ((m_cass->input() > +0.04) ? 1 : 0);
99 }
100 
floppy_control_w(uint8_t data)101 void pk8020_state::floppy_control_w(uint8_t data)
102 {
103 	floppy_image_device *floppy = nullptr;
104 
105 	// Turn all motors off
106 	for (int n = 0; n < 4; n++)
107 		if (m_floppy[n]->get_device())
108 			m_floppy[n]->get_device()->mon_w(1);
109 
110 	for (int n = 0; n < 4; n++)
111 		if (BIT(data, n))
112 			floppy = m_floppy[n]->get_device();
113 
114 	m_fdc->set_floppy(floppy);
115 
116 	if (floppy)
117 	{
118 		floppy->mon_w(0);
119 		floppy->ss_w(BIT(data, 4));
120 	}
121 
122 	// todo: at least bit 5 and bit 7 is connected to something too...
123 }
124 
125 
ppi_2_portc_w(uint8_t data)126 void pk8020_state::ppi_2_portc_w(uint8_t data)
127 {
128 	static const double levels[4] = { 0.0, 1.0, -1.0, 0.0 };
129 	m_cass->output(levels[data & 3]);
130 
131 	m_sound_gate = BIT(data,3);
132 	m_speaker->level_w(m_sound_gate ? m_sound_level : 0);
133 
134 	m_printer->write_select(!BIT(data, 4));
135 	m_printer->write_strobe(!BIT(data, 5));
136 }
137 
WRITE_LINE_MEMBER(pk8020_state::pit_out0)138 WRITE_LINE_MEMBER(pk8020_state::pit_out0)
139 {
140 	m_sound_level = state;
141 
142 	m_speaker->level_w(m_sound_gate ? m_sound_level : 0);
143 }
144 
145 
plm_select_name(uint8_t data)146 const char *pk8020_state::plm_select_name(uint8_t data)
147 {
148 	switch (data)
149 	{
150 	case 0xfb:
151 	case 0xf7:
152 	case 0xfe:
153 		return "ROM";
154 
155 	case 0x3f:
156 		return "RAM";
157 
158 	case 0xfd:
159 		return "keyboard";
160 
161 	case 0xdf:
162 		return "system reg";
163 
164 	case 0xef:
165 		return "devices";
166 
167 	case 0xbf:
168 		return "text video memory";
169 
170 	case 0x7f:
171 		return "video RAM";
172 
173 	default:
174 		return "multiple/unknown";
175 	}
176 }
177 
log_bank_select(uint8_t bank,offs_t start,offs_t end,uint8_t rdecplm,uint8_t wdecplm)178 void pk8020_state::log_bank_select(uint8_t bank, offs_t start, offs_t end, uint8_t rdecplm, uint8_t wdecplm)
179 {
180 	if (rdecplm == wdecplm)
181 		logerror("Bank select %02X, %04X-%04Xh: read/write %s (%02X)\n", bank, start, end, plm_select_name(rdecplm), rdecplm);
182 	else
183 		logerror("Bank select %02X, %04X-%04Xh: read %s (%02X), write %s (%02X)\n", bank, start, end, plm_select_name(rdecplm), rdecplm, plm_select_name(wdecplm), wdecplm);
184 }
185 
machine_start()186 void pk8020_state::machine_start()
187 {
188 	m_ios[0]->write_cts(0);
189 	m_ios[1]->write_cts(0);
190 	m_ios[1]->write_dsr(0);
191 	m_takt = 0;
192 
193 	save_item(NAME(m_bank_select));
194 	save_item(NAME(m_takt));
195 	save_item(NAME(m_sound_gate));
196 	save_item(NAME(m_sound_level));
197 
198 	if (DESCRIBE_DECPLM)
199 	{
200 		for (uint8_t bank = 0; bank < 0x20; bank++)
201 		{
202 			uint8_t rdecplm = 0;
203 			uint8_t wdecplm = 0;
204 			offs_t start = 0x0000;
205 
206 			for (offs_t offset = 0x0000; offset < 0x10000; offset += 0x100)
207 			{
208 				uint8_t rdecplm_test = m_decplm->read(bitswap<13>((offset & 0xff00) | (bank << 2), 2, 5, 6, 4, 12, 3, 13, 8, 9, 11, 15, 10, 14) | 0x8000);
209 				uint8_t wdecplm_test = m_decplm->read(bitswap<13>((offset & 0xff00) | (bank << 2), 2, 5, 6, 4, 12, 3, 13, 8, 9, 11, 15, 10, 14) | 0x2000);
210 
211 				if (rdecplm != rdecplm_test || wdecplm != wdecplm_test)
212 				{
213 					if (offset != 0x0000)
214 						log_bank_select(bank, start, offset - 1, rdecplm, wdecplm);
215 					rdecplm = rdecplm_test;
216 					wdecplm = wdecplm_test;
217 					start = offset;
218 				}
219 			}
220 			log_bank_select(bank, start, 0xffff, rdecplm, wdecplm);
221 		}
222 	}
223 }
224 
machine_reset()225 void pk8020_state::machine_reset()
226 {
227 	m_bank_select = 0;
228 
229 	m_sound_gate = 0;
230 	m_sound_level = 0;
231 }
232 
INTERRUPT_GEN_MEMBER(pk8020_state::pk8020_interrupt)233 INTERRUPT_GEN_MEMBER(pk8020_state::pk8020_interrupt)
234 {
235 	m_takt ^= 1;
236 	m_inr->ir4_w(m_takt);
237 }
238