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