1 /*
2 * piacore.c -- PIA chip emulation.
3 *
4 * Written by
5 * Jouko Valta <jopi@stekt.oulu.fi>
6 * Andre Fachat <fachat@physik.tu-chemnitz.de>
7 *
8 * This file is part of VICE, the Versatile Commodore Emulator.
9 * See README for copyright notice.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24 * 02111-1307 USA.
25 *
26 */
27
28 #include "monitor.h"
29 #include "snapshot.h"
30
31
32 static uint8_t pia_last_read = 0;
33
34 static unsigned int pia_int_num;
35
36
mypia_init(void)37 void mypia_init(void)
38 {
39 mypia_log = log_open(MYPIA_NAME);
40
41 pia_int_num = interrupt_cpu_status_int_new(mycpu_int_status, MYPIA_NAME);
42 }
43
mypia_reset(void)44 void mypia_reset(void)
45 {
46 /* clear _all_ internal registers */
47
48 mypia.ctrl_a = 0; /* PIA 1 Port A Control */
49 mypia.ctrl_b = 0; /* PIA 1 Port B Control */
50 mypia.ddr_a = 0; /* PIA 1 Port A DDR */
51 mypia.ddr_b = 0; /* PIA 1 Port B DDR */
52 mypia.port_a = 255; /* PIA 1 Port A input; nothing to read from keyboard */
53 mypia.port_b = 255; /* PIA 1 Port B input; nothing to read from keyboard */
54
55 pia_reset();
56
57 pia_set_ca2(1);
58 mypia.ca_state = 1;
59 pia_set_cb2(1);
60 mypia.cb_state = 1;
61
62 is_peek_access = 0;
63
64 my_set_int(pia_int_num, 0);
65 }
66
mypia_update_irq(void)67 static void mypia_update_irq(void)
68 {
69 if (0
70 || ((mypia.ctrl_a & 0x81) == 0x81)
71 || ((mypia.ctrl_a & 0x68) == 0x48)
72 || ((mypia.ctrl_b & 0x81) == 0x81)
73 || ((mypia.ctrl_b & 0x68) == 0x48)
74 ) {
75 my_set_int(pia_int_num, 1);
76 } else {
77 my_set_int(pia_int_num, 0);
78 }
79 }
80
81
82 /* control line flag support. Used for PET IRQ input.
83 * this currently relies on each edge being called only once,
84 * otherwise multiple IRQs could occur. */
85
mypia_signal(int line,int edge)86 void mypia_signal(int line, int edge)
87 {
88 switch (line) {
89 case PIA_SIG_CA1:
90 if (((mypia.ctrl_a & 0x02) ? PIA_SIG_RISE : PIA_SIG_FALL) == edge) {
91 mypia.ctrl_a |= 0x80;
92 mypia_update_irq();
93 if (IS_CA2_TOGGLE_MODE()) {
94 pia_set_ca2(1);
95 mypia.ca_state = 1;
96 }
97 }
98 break;
99 case PIA_SIG_CB1:
100 if (((mypia.ctrl_b & 0x02) ? PIA_SIG_RISE : PIA_SIG_FALL) == edge) {
101 mypia.ctrl_b |= 0x80;
102 mypia_update_irq();
103 if (IS_CB2_TOGGLE_MODE()) {
104 pia_set_cb2(1);
105 mypia.cb_state = 1;
106 }
107 }
108 break;
109 case PIA_SIG_CA2:
110 case PIA_SIG_CB2:
111 break;
112 }
113 }
114
115
116 /* ------------------------------------------------------------------------- */
117 /* PIA */
118
mypia_store(uint16_t addr,uint8_t byte)119 void mypia_store(uint16_t addr, uint8_t byte)
120 {
121 if (mycpu_rmw_flag) {
122 myclk--;
123 mycpu_rmw_flag = 0;
124 mypia_store(addr, pia_last_read);
125 myclk++;
126 }
127
128 addr &= 3;
129
130 switch (addr) {
131 case P_PORT_A: /* port A */
132 if (mypia.ctrl_a & 4) {
133 mypia.port_a = byte;
134 } else {
135 mypia.ddr_a = byte;
136 }
137 byte = mypia.port_a | ~mypia.ddr_a;
138 store_pa(byte);
139 break;
140
141 case P_PORT_B: /* port B */
142 if (mypia.ctrl_b & 4) {
143 mypia.port_b = byte;
144 } else {
145 mypia.ddr_b = byte;
146 }
147 byte = mypia.port_b | ~mypia.ddr_b;
148 store_pb(byte);
149 if (IS_CB2_HANDSHAKE()) {
150 pia_set_cb2(0);
151 mypia.cb_state = 0;
152 if (IS_CB2_PULSE_MODE()) {
153 pia_set_cb2(1);
154 mypia.cb_state = 1;
155 }
156 }
157 break;
158
159 /* Control */
160
161 case P_CTRL_A: /* Control A */
162 if ((byte & 0x38) == 0x30) { /* set output low */
163 pia_set_ca2(0);
164 mypia.ca_state = 0;
165 } else
166 if ((byte & 0x38) == 0x38) { /* set output high */
167 pia_set_ca2(1);
168 mypia.ca_state = 1;
169 } else /* change to toggle/pulse */
170 if ((mypia.ctrl_a & 0x30) == 0x30) {
171 pia_set_ca2(1);
172 mypia.ca_state = 1;
173 }
174
175 mypia.ctrl_a = (mypia.ctrl_a & 0xc0) | (byte & 0x3f);
176
177 if (mypia.ctrl_a & 0x20) {
178 mypia.ctrl_a &= 0xbf;
179 }
180
181 mypia_update_irq();
182
183 break;
184
185 case P_CTRL_B: /* Control B */
186 if ((byte & 0x38) == 0x30) { /* set output low */
187 pia_set_cb2(0);
188 mypia.cb_state = 0;
189 } else
190 if ((byte & 0x38) == 0x38) { /* set output high */
191 pia_set_cb2(1);
192 mypia.cb_state = 1;
193 } else /* change to toggle/pulse */
194 if ((mypia.ctrl_b & 0x30) == 0x30) {
195 pia_set_cb2(1);
196 mypia.cb_state = 1;
197 }
198
199 mypia.ctrl_b = (mypia.ctrl_b & 0xc0) | (byte & 0x3f);
200
201 if (mypia.ctrl_b & 0x20) {
202 mypia.ctrl_b &= 0xbf;
203 }
204
205 mypia_update_irq();
206
207 break;
208 } /* switch */
209 }
210
211
212 /* ------------------------------------------------------------------------- */
213
mypia_read(uint16_t addr)214 uint8_t mypia_read(uint16_t addr)
215 {
216 static uint8_t byte = 0xff;
217
218 addr &= 3;
219
220 switch (addr) {
221 case P_PORT_A: /* port A */
222 if (mypia.ctrl_a & 4) {
223 if (!is_peek_access) {
224 mypia.ctrl_a &= 0x3f; /* Clear CA1,CA2 IRQ */
225 mypia_update_irq();
226 }
227 /* WARNING: for output pins, this port reads the voltage of
228 * the output pins, not the ORA value as the other port.
229 * Value read might be different from what is expected due
230 * to excessive electrical load on the pin.
231 */
232 byte = read_pa();
233 pia_last_read = byte;
234 return byte;
235 }
236 pia_last_read = (mypia.ddr_a);
237 return pia_last_read;
238 break;
239
240 case P_PORT_B: /* port B */
241 if (mypia.ctrl_b & 4) {
242 if (!is_peek_access) {
243 mypia.ctrl_b &= 0x3f; /* Clear CB1,CB2 IRQ */
244 mypia_update_irq();
245 }
246
247 /* WARNING: this port reads the ORB for output pins, not
248 the voltage on the pins as the other port. */
249 byte = read_pb();
250 pia_last_read = (byte & ~mypia.ddr_b)
251 | (mypia.port_b & mypia.ddr_b);
252 return pia_last_read;
253 }
254 pia_last_read = (mypia.ddr_b);
255 return pia_last_read;
256 break;
257
258 /* Control */
259
260 case P_CTRL_A: /* Control A */
261 pia_last_read = (mypia.ctrl_a);
262 return pia_last_read;
263 break;
264
265 case P_CTRL_B: /* Control B */
266 pia_last_read = (mypia.ctrl_b);
267 return pia_last_read;
268 break;
269 } /* switch */
270
271 /* should never happen */
272 return (0xFF);
273 }
274
275
mypia_peek(uint16_t addr)276 uint8_t mypia_peek(uint16_t addr)
277 {
278 uint8_t t;
279
280 is_peek_access = 1;
281 t = mypia_read(addr);
282 is_peek_access = 0;
283
284 return t;
285 }
286
mypia_dump(void)287 int mypia_dump(void)
288 {
289 mon_out("port_a: %02x port_b: %02x (written bits only)\n", mypia.port_a, mypia.port_b);
290 mon_out(" ddr_a: %02x ddr_b: %02x (1 bits are outputs)\n", mypia.ddr_a, mypia.ddr_b);
291 mon_out("ctrl_a: %02x ctrl_b: %02x\n", mypia.ctrl_a, mypia.ctrl_b);
292 mon_out(" ca2: %2x cb2: %2x\n", mypia.ca_state, mypia.cb_state);
293 mon_out("CA1 active transition: %d\n", (mypia.ctrl_a & 0x80) >> 7);
294 mon_out("CA2 active transition: %d\n", (mypia.ctrl_a & 0x40) >> 6);
295
296 if (mypia.ctrl_a & 0x20) {
297 mon_out("CA2: out, ");
298 if (mypia.ctrl_a & 0x10) {
299 mon_out("manual, ");
300 if (mypia.ctrl_a & 0x08) {
301 mon_out("high\n");
302 } else {
303 mon_out("low\n");
304 }
305 } else {
306 mon_out("handshake ");
307 if (mypia.ctrl_a & 0x08) {
308 mon_out("pulse\n");
309 } else {
310 mon_out("on read (to 0)/CA1 (to 1)\n");
311 }
312 }
313 } else {
314 mon_out("CA2: in, ");
315 if (mypia.ctrl_a & 0x10) {
316 mon_out("active high, ");
317 } else {
318 mon_out("active low, ");
319 }
320 if (mypia.ctrl_a & 0x08) {
321 mon_out("IRQ on\n");
322 } else {
323 mon_out("IRQ off\n");
324 }
325 }
326 if (mypia.ctrl_a & 0x04) {
327 mon_out("IORA visible\n");
328 } else {
329 mon_out("DDRA visible\n");
330 }
331 if (mypia.ctrl_a & 0x02) {
332 mon_out("CA1: active high, ");
333 } else {
334 mon_out("CA1: active low, ");
335 }
336 if (mypia.ctrl_a & 0x01) {
337 mon_out("IRQ on\n");
338 } else {
339 mon_out("IRQ off\n");
340 }
341
342 mon_out("CB1 active transition: %d\n", (mypia.ctrl_b & 0x80) >> 7);
343 mon_out("CB2 active transition: %d\n", (mypia.ctrl_b & 0x40) >> 6);
344 if (mypia.ctrl_b & 0x20) {
345 mon_out("CB2: out, ");
346 if (mypia.ctrl_b & 0x10) {
347 mon_out("manual, ");
348 if (mypia.ctrl_b & 0x08) {
349 mon_out("high\n");
350 } else {
351 mon_out("low\n");
352 }
353 } else {
354 mon_out("handshake ");
355 if (mypia.ctrl_b & 0x08) {
356 mon_out("pulse\n");
357 } else {
358 mon_out("on write (to 0)/CB1 (to 1)\n");
359 }
360 }
361 } else {
362 mon_out("CB2: in, ");
363 if (mypia.ctrl_b & 0x10) {
364 mon_out("active high, ");
365 } else {
366 mon_out("active low, ");
367 }
368 if (mypia.ctrl_b & 0x08) {
369 mon_out("IRQ on\n");
370 } else {
371 mon_out("IRQ off\n");
372 }
373 }
374 if (mypia.ctrl_b & 0x04) {
375 mon_out("IORB visible\n");
376 } else {
377 mon_out("DDRB visible\n");
378 }
379 if (mypia.ctrl_b & 0x02) {
380 mon_out("CB1: active high, ");
381 } else {
382 mon_out("CB1: active low, ");
383 }
384 if (mypia.ctrl_b & 0x01) {
385 mon_out("IRQ on\n");
386 } else {
387 mon_out("IRQ off\n");
388 }
389
390 return 0;
391 }
392
393 /*------------------------------------------------------------------------*/
394
395 /* The dump format has a module header and the data generated by the
396 * chip...
397 *
398 * The version of this dump description is 0/0
399 */
400
401 #define PIA_DUMP_VER_MAJOR 1
402 #define PIA_DUMP_VER_MINOR 0
403
404 static char snap_module_name[] = MYPIA_NAME;
405
406 /*
407 * The dump data:
408 *
409 * UBYTE ORA
410 * UBYTE DDRA
411 * UBYTE CTRLA
412 * UBYTE ORB
413 * UBYTE DDRB
414 * UBYTE CTRLB
415 * UBYTE CABSTATE Bit 7 = state of CA2, Bit 6 = state of CB2
416 *
417 */
418
419 /* FIXME!!! Error check. */
420
mypia_snapshot_write_module(snapshot_t * p)421 int mypia_snapshot_write_module(snapshot_t * p)
422 {
423 snapshot_module_t *m;
424
425 m = snapshot_module_create(p, snap_module_name,
426 PIA_DUMP_VER_MAJOR, PIA_DUMP_VER_MINOR);
427 if (m == NULL) {
428 return -1;
429 }
430
431 SMW_B(m, mypia.port_a);
432 SMW_B(m, mypia.ddr_a);
433 SMW_B(m, mypia.ctrl_a);
434
435 SMW_B(m, mypia.port_b);
436 SMW_B(m, mypia.ddr_b);
437 SMW_B(m, mypia.ctrl_b);
438
439 SMW_B(m, (uint8_t)((mypia.ca_state ? 0x80 : 0) | (mypia.cb_state ? 0x40 : 0)));
440
441 snapshot_module_close(m);
442
443 return 0;
444 }
445
mypia_snapshot_read_module(snapshot_t * p)446 int mypia_snapshot_read_module(snapshot_t * p)
447 {
448 uint8_t vmajor, vminor;
449 uint8_t byte;
450 snapshot_module_t *m;
451
452 my_restore_int(pia_int_num, 0); /* just in case */
453
454 m = snapshot_module_open(p, snap_module_name, &vmajor, &vminor);
455 if (m == NULL) {
456 return -1;
457 }
458
459 if (vmajor != PIA_DUMP_VER_MAJOR) {
460 snapshot_module_close(m);
461 return -1;
462 }
463
464 SMR_B(m, &mypia.port_a);
465 SMR_B(m, &mypia.ddr_a);
466 SMR_B(m, &mypia.ctrl_a);
467
468 SMR_B(m, &mypia.port_b);
469 SMR_B(m, &mypia.ddr_b);
470 SMR_B(m, &mypia.ctrl_b);
471
472 SMR_B(m, &byte);
473 mypia.ca_state = (byte & 0x80) ? 1 : 0;
474 mypia.cb_state = (byte & 0x80) ? 1 : 0;
475
476 pia_set_ca2(mypia.ca_state);
477 pia_set_cb2(mypia.cb_state);
478
479 byte = mypia.port_a | ~mypia.ddr_a;
480 undump_pa(byte);
481
482 byte = mypia.port_b | ~mypia.ddr_b;
483 undump_pb(byte);
484
485 if (0
486 || ((mypia.ctrl_a & 0x81) == 0x81)
487 || ((mypia.ctrl_a & 0x68) == 0x48)
488 || ((mypia.ctrl_b & 0x81) == 0x81)
489 || ((mypia.ctrl_b & 0x68) == 0x48)
490 ) {
491 my_restore_int(pia_int_num, 1);
492 }
493
494 return snapshot_module_close(m);
495 }
496