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