1 // license:BSD-3-Clause
2 // copyright-holders:Robbbert
3 
4 
5 #include "emu.h"
6 #include "includes/kaypro.h"
7 
8 
9 
10 
11 /***********************************************************
12 
13     PIO
14 
15     Port B is unused on both PIOs
16 
17 ************************************************************/
18 
WRITE_LINE_MEMBER(kaypro_state::write_centronics_busy)19 WRITE_LINE_MEMBER( kaypro_state::write_centronics_busy )
20 {
21 	m_centronics_busy = state;
22 }
23 
pio_system_r()24 u8 kaypro_state::pio_system_r()
25 {
26 	u8 data = 0;
27 
28 	/* centronics busy */
29 	data |= m_centronics_busy << 3;
30 
31 	/* PA7 is pulled high */
32 	data |= 0x80;
33 
34 	return data;
35 }
36 
kayproii_pio_system_w(u8 data)37 void kaypro_state::kayproii_pio_system_w(u8 data)
38 {
39 /*  d7 bank select
40     d6 disk drive motors - (0=on)
41     d5 double-density enable (0=double density)
42     d4 Centronics strobe
43     d2 side select (1=side 1)
44     d1 drive B
45     d0 drive A */
46 
47 	m_bankr->set_entry(BIT(data, 7));
48 	m_bankw->set_entry(BIT(data, 7));
49 	m_bank3->set_entry(BIT(data, 7));
50 	m_is_motor_off = BIT(data, 6);
51 
52 	m_floppy = nullptr;
53 	if (BIT(data, 0))
54 		m_floppy = m_floppy0->get_device();
55 	else
56 	if (BIT(data, 1))
57 		m_floppy = m_floppy1->get_device();
58 
59 	m_fdc->set_floppy(m_floppy);
60 	m_fdc->dden_w(BIT(data, 5));
61 
62 	if (m_floppy)
63 	{
64 		m_floppy->mon_w(BIT(data, 6)); // motor on
65 		m_floppy->ss_w(!BIT(data, 2)); // signal exists even though drives are single sided
66 	}
67 
68 	m_leds[0] = BIT(data, 0);     // LEDs in artwork
69 	m_leds[1] = BIT(data, 1);
70 
71 	m_centronics->write_strobe(BIT(data, 4));
72 
73 	m_system_port = data;
74 }
75 
kayproiv_pio_system_w(u8 data)76 void kaypro_state::kayproiv_pio_system_w(u8 data)
77 {
78 	kayproii_pio_system_w(data);
79 
80 	/* side select */
81 	if (m_floppy)
82 		m_floppy->ss_w(BIT(data, 2));
83 }
84 
85 /***********************************************************
86 
87     KAYPRO484 SYSTEM PORT
88 
89     The PIOs were replaced by a few standard 74xx chips
90 
91 ************************************************************/
92 
kaypro484_system_port_r()93 u8 kaypro_state::kaypro484_system_port_r()
94 {
95 	u8 data = m_centronics_busy << 6;
96 	return (m_system_port & 0xbf) | data;
97 }
98 
kaypro484_system_port_w(u8 data)99 void kaypro_state::kaypro484_system_port_w(u8 data)
100 {
101 /*  d7 bank select
102     d6 alternate character set (write only)
103     d5 double-density enable
104     d4 disk drive motors (1=on)
105     d3 Centronics strobe
106     d2 side select (appears that 0=side 1?)
107     d1 drive B
108     d0 drive A */
109 
110 	m_bankr->set_entry(BIT(data, 7));
111 	m_bankw->set_entry(BIT(data, 7));
112 	m_bank3->set_entry(BIT(data, 7));
113 	m_is_motor_off = !BIT(data, 4);
114 
115 	m_floppy = nullptr;
116 	if (!BIT(data, 0))
117 		m_floppy = m_floppy0->get_device();
118 	else
119 	if (m_floppy1 && (!BIT(data, 1)))
120 		m_floppy = m_floppy1->get_device();
121 
122 	m_fdc->set_floppy(m_floppy);
123 	m_fdc->dden_w(BIT(data, 5));
124 
125 	if (m_floppy)
126 	{
127 		m_floppy->mon_w(!BIT(data, 4)); // motor on
128 		m_floppy->ss_w(!BIT(data, 2));
129 	}
130 
131 	m_leds[0] = BIT(data, 0);     // LEDs in artwork
132 	m_leds[1] = BIT(data, 1);
133 
134 	m_centronics->write_strobe(BIT(data, 3));
135 
136 	m_system_port = data;
137 }
138 
139 
140 /***********************************************************************
141 
142     SIO
143 
144     On Kaypro484, Channel B on both SIOs is hardwired to 300 baud.
145 
146     Both devices on sio2 (printer and modem) are not emulated.
147 
148 ************************************************************************/
149 
150 /* Set baud rate. bits 0..3 Rx and Tx are tied together. Baud Rate Generator is a AY-5-8116, SMC8116, WD1943, etc.
151     00h    50
152     11h    75
153     22h    110
154     33h    134.5
155     44h    150
156     55h    300
157     66h    600
158     77h    1200
159     88h    1800
160     99h    2000
161     AAh    2400
162     BBh    3600
163     CCh    4800
164     DDh    7200
165     EEh    9600
166     FFh    19200 */
167 
168 
169 /*************************************************************************************
170 
171     Floppy Disk
172 
173     If DRQ or IRQ is set, and cpu is halted, the NMI goes low.
174     Since the HALT occurs last (and has no callback mechanism), we need to set
175     a short delay, to give time for the processor to execute the HALT before NMI
176     becomes active.
177 
178 *************************************************************************************/
179 
TIMER_DEVICE_CALLBACK_MEMBER(kaypro_state::floppy_timer)180 TIMER_DEVICE_CALLBACK_MEMBER(kaypro_state::floppy_timer)
181 {
182 	bool halt;
183 	halt = (bool)m_maincpu->state_int(Z80_HALT);
184 	if (m_is_motor_off)
185 	{
186 		m_floppy_timer->adjust(attotime::from_hz(10));
187 		return;
188 	}
189 
190 	if ((halt) && (m_fdc_rq & 3) && (m_fdc_rq < 0x80))
191 	{
192 		m_maincpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE);
193 		m_fdc_rq |= 0x80;
194 	}
195 	else
196 	if ((m_fdc_rq == 0x80) || ((!halt) && BIT(m_fdc_rq, 7)))
197 	{
198 		m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE);
199 		m_fdc_rq &= 0x7f;
200 	}
201 	m_floppy_timer->adjust(attotime::from_hz(1e5));
202 }
203 
204 
WRITE_LINE_MEMBER(kaypro_state::fdc_intrq_w)205 WRITE_LINE_MEMBER( kaypro_state::fdc_intrq_w )
206 {
207 	m_fdc_rq = (m_fdc_rq & 0x82) | state;
208 }
209 
WRITE_LINE_MEMBER(kaypro_state::fdc_drq_w)210 WRITE_LINE_MEMBER( kaypro_state::fdc_drq_w )
211 {
212 	m_fdc_rq = (m_fdc_rq & 0x81) | (state << 1);
213 }
214 
215 
216 /***********************************************************
217 
218     Machine
219 
220 ************************************************************/
machine_start()221 void kaypro_state::machine_start()
222 {
223 	if (m_pio_s)
224 		m_pio_s->strobe_a(0);
225 
226 	m_leds.resolve();
227 
228 	save_pointer(NAME(m_vram), 0x1000);
229 	save_pointer(NAME(m_ram),  0x4000);
230 
231 	save_item(NAME(m_mc6845_reg));
232 	save_item(NAME(m_mc6845_ind));
233 	save_item(NAME(m_framecnt));
234 	save_item(NAME(m_centronics_busy));
235 	save_item(NAME(m_is_motor_off));
236 	save_item(NAME(m_fdc_rq));
237 	save_item(NAME(m_system_port));
238 	save_item(NAME(m_mc6845_video_address));
239 }
240 
machine_reset()241 void kaypro_state::machine_reset()
242 {
243 	m_bankr->set_entry(1); // point at rom
244 	m_bankw->set_entry(1); // always write to ram
245 	m_bank3->set_entry(1); // point at video ram
246 	m_system_port = 0x80;
247 	m_fdc_rq = 0;
248 	m_maincpu->reset();
249 	m_floppy_timer->adjust(attotime::from_hz(1));   /* kick-start the nmi timer */
250 }
251 
252 
253 /***********************************************************
254 
255     Quickload
256 
257     This loads a .COM file to address 0x100 then jumps
258     there. Sometimes .COM has been renamed to .CPM to
259     prevent windows going ballistic. These can be loaded
260     as well.
261 
262 ************************************************************/
263 
QUICKLOAD_LOAD_MEMBER(kaypro_state::quickload_cb)264 QUICKLOAD_LOAD_MEMBER(kaypro_state::quickload_cb)
265 {
266 	m_bankr->set_entry(0);
267 	m_bankw->set_entry(0);
268 	m_bank3->set_entry(0);
269 
270 	address_space& prog_space = m_maincpu->space(AS_PROGRAM);
271 
272 	/* Avoid loading a program if CP/M-80 is not in memory */
273 	if ((prog_space.read_byte(0) != 0xc3) || (prog_space.read_byte(5) != 0xc3))
274 		return image_init_result::FAIL;
275 
276 	if (quickload_size >= 0xfd00)
277 		return image_init_result::FAIL;
278 
279 	/* Load image to the TPA (Transient Program Area) */
280 	for (u16 i = 0; i < quickload_size; i++)
281 	{
282 		u8 data;
283 		if (image.fread( &data, 1) != 1)
284 			return image_init_result::FAIL;
285 		prog_space.write_byte(i+0x100, data);
286 	}
287 
288 	prog_space.write_byte(0x80, 0);   prog_space.write_byte(0x81, 0);    // clear out command tail
289 
290 	m_maincpu->set_pc(0x100);    // start program
291 	m_maincpu->set_state_int(Z80_SP, 256 * prog_space.read_byte(7) - 300);   // put the stack a bit before BDOS
292 
293 	return image_init_result::PASS;
294 }
295