1 /*
2 * viacore.c - Core functions for VIA emulation.
3 *
4 * Written by
5 * Andre Fachat <fachat@physik.tu-chemnitz.de>
6 * Andreas Boose <viceteam@t-online.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 "vice.h"
29
30 #include <stdio.h>
31 #include <string.h>
32
33 #include "alarm.h"
34 #include "clkguard.h"
35 #include "interrupt.h"
36 #include "lib.h"
37 #include "log.h"
38 #include "monitor.h"
39 #include "snapshot.h"
40 #include "types.h"
41 #include "via.h"
42
43
44 /*
45 * 24jan97 a.fachat
46 * new interrupt handling, hopefully according to the specs now.
47 * All interrupts (note: not timer events (i.e. alarms) are put
48 * into one interrupt flag.
49 * if an interrupt condition changes, the function (i.e. cpp macro)
50 * update_myviairq() id called, that checks the IRQ line state.
51 * This is now possible, as ettore has decoupled A_* alarm events
52 * from interrupts for performance reasons.
53 *
54 * A new function for signaling rising/falling edges on the
55 * control lines is introduced:
56 * myvia_signal(VIA_SIG_[CA1|CA2|CB1|CB2], VIA_SIG_[RISE|FALL])
57 * which signals the corresponding edge to the VIA. The constants
58 * are defined in via.h.
59 *
60 * Except for shift register and input latching everything should be ok now.
61 */
62
63 /* Timer debugging */
64 /*#define MYVIA_TIMER_DEBUG */
65 /* when PB7 is really used, set this
66 to enable pulse output from the timer.
67 Otherwise PB7 state is computed only
68 when port B is read -
69 not yet implemented */
70 #define MYVIA_NEED_PB7
71 /* When you really need latching, define this.
72 It implies additional READ_PR* when
73 writing the snapshot. When latching is
74 enabled: it reads the port when enabling,
75 and when an active C*1 transition occurs.
76 It does not read the port when reading the
77 port register. Side-effects beware! */
78 /* FIXME: this doesnt even work anymore */
79 /* #define MYVIA_NEED_LATCHING */
80
81 /*
82 * local functions
83 */
84
85 #define IS_CA2_OUTPUT() ((via_context->via[VIA_PCR] & 0x0c) == 0x0c)
86 #define IS_CA2_INDINPUT() ((via_context->via[VIA_PCR] & 0x0a) == 0x02)
87 #define IS_CA2_HANDSHAKE() ((via_context->via[VIA_PCR] & 0x0c) == 0x08)
88 #define IS_CA2_PULSE_MODE() ((via_context->via[VIA_PCR] & 0x0e) == 0x09)
89 #define IS_CA2_TOGGLE_MODE() ((via_context->via[VIA_PCR] & 0x0e) == 0x08)
90
91 #define IS_CB2_OUTPUT() ((via_context->via[VIA_PCR] & 0xc0) == 0xc0)
92 #define IS_CB2_INDINPUT() ((via_context->via[VIA_PCR] & 0xa0) == 0x20)
93 #define IS_CB2_HANDSHAKE() ((via_context->via[VIA_PCR] & 0xc0) == 0x80)
94 #define IS_CB2_PULSE_MODE() ((via_context->via[VIA_PCR] & 0xe0) == 0x90)
95 #define IS_CB2_TOGGLE_MODE() ((via_context->via[VIA_PCR] & 0xe0) == 0x80)
96
97 #define IS_PA_INPUT_LATCH() (via_context->via[VIA_ACR] & 0x01)
98 #define IS_PB_INPUT_LATCH() (via_context->via[VIA_ACR] & 0x02)
99
100 /*
101 * 01apr98 a.fachat
102 *
103 * One-shot Timing (partly from 6522-VIA.txt):
104
105 +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+
106 02 --+ +-+ +-+ +-+ +-+ +-+ +-#-+ +-+ +-+ +-+ +-+ +-+ +-
107 | | |
108 +---+ |
109 WRITE T1C-H ----+ +-----------------#-------------------------
110 ___ | |
111 IRQ OUTPUT --------------------------#---------+
112 | +---------------
113 | |
114 PB7 OUTPUT --------+ +---------------
115 +-----------------#---------+
116 T1 | N |N-1|N-2|N-3| | 0 | -1|N |N-1|N-2|
117 T2 | N |N-1|N-2|N-3| | 0 | -1| -2| -3| -4|
118 | |
119 |<---- N + 1.5 CYCLES ----->|<--- N + 2 cycles --->
120 +---+
121 myviat*u* clk ------------------------------------------+ +--------
122 |
123 |
124 call of
125 int_myvia*
126 here
127
128 real myviatau value = myviatau* + TAUOFFSET
129 myviatbu = myviatbu* + 0
130
131 *
132 * IRQ and PB7 are set/toggled at the low-high transition of Phi2,
133 * but int_* is called a half-cycle before that. Does that matter?
134 *
135 * PB7 output is still to be implemented
136 */
137
138 /* timer values do not depend on a certain value here, but PB7 does... */
139 #define TAUOFFSET (-1)
140
141
142 static void viacore_intt1(CLOCK offset, void *data);
143 static void viacore_intt2(CLOCK offset, void *data);
144
145
via_restore_int(via_context_t * via_context,int value)146 static void via_restore_int(via_context_t *via_context, int value)
147 {
148 (via_context->restore_int)(via_context, via_context->int_num, value);
149 }
150
update_myviairq(via_context_t * via_context)151 inline static void update_myviairq(via_context_t *via_context)
152 {
153 (via_context->set_int)(via_context, via_context->int_num,
154 (via_context->ifr & via_context->ier & 0x7f)
155 ? via_context->irq_line : 0, *(via_context->clk_ptr));
156 }
157
update_myviairq_rclk(via_context_t * via_context,CLOCK rclk)158 inline static void update_myviairq_rclk(via_context_t *via_context, CLOCK rclk)
159 {
160 (via_context->set_int)(via_context, via_context->int_num,
161 (via_context->ifr & via_context->ier & 0x7f)
162 ? via_context->irq_line : 0, rclk);
163 }
164
165 /* the next two are used in myvia_read() */
166
myviata(via_context_t * via_context)167 inline static CLOCK myviata(via_context_t *via_context)
168 {
169 if (*(via_context->clk_ptr) < via_context->tau - TAUOFFSET) {
170 return via_context->tau - TAUOFFSET - *(via_context->clk_ptr) - 2;
171 } else {
172 return (via_context->tal - (*(via_context->clk_ptr) - via_context->tau
173 + TAUOFFSET) % (via_context->tal + 2));
174 }
175 }
176
myviatb(via_context_t * via_context)177 inline static CLOCK myviatb(via_context_t *via_context)
178 {
179 CLOCK t2;
180
181 if (via_context->via[VIA_ACR] & 0x20) {
182 t2 = (via_context->t2ch << 8) | via_context->t2cl;
183 } else {
184 t2 = via_context->tbu - *(via_context->clk_ptr) - 2;
185
186 if (via_context->tbi) {
187 uint8_t t2hi = via_context->t2ch;
188
189 if (*(via_context->clk_ptr) == via_context->tbi + 1) {
190 t2hi--;
191 }
192
193 t2 = (t2hi << 8) | (t2 & 0xff);
194 }
195 }
196
197 return t2;
198 }
199
update_myviatal(via_context_t * via_context,CLOCK rclk)200 inline static void update_myviatal(via_context_t *via_context, CLOCK rclk)
201 {
202 via_context->pb7x = 0;
203 via_context->pb7xx = 0;
204
205 if (rclk > via_context->tau) {
206 int nuf = (via_context->tal + 1 + rclk - via_context->tau)
207 / (via_context->tal + 2);
208
209 if (!(via_context->via[VIA_ACR] & 0x40)) {
210 /* one shot mode */
211 if (((nuf - via_context->pb7sx) > 1) || (!(via_context->pb7))) {
212 via_context->pb7o = 1;
213 via_context->pb7sx = 0;
214 }
215 }
216 via_context->pb7 ^= (nuf & 1);
217
218 via_context->tau = TAUOFFSET + via_context->tal + 2
219 + (rclk - (rclk - via_context->tau + TAUOFFSET)
220 % (via_context->tal + 2));
221 if (rclk == via_context->tau - via_context->tal - 1) {
222 via_context->pb7xx = 1;
223 }
224 }
225
226 if (via_context->tau == rclk) {
227 via_context->pb7x = 1;
228 }
229
230 via_context->tal = via_context->via[VIA_T1LL]
231 + (via_context->via[VIA_T1LH] << 8);
232 }
233
234 /* ------------------------------------------------------------------------- */
viacore_disable(via_context_t * via_context)235 void viacore_disable(via_context_t *via_context)
236 {
237 alarm_unset(via_context->t1_alarm);
238 alarm_unset(via_context->t2_alarm);
239 alarm_unset(via_context->sr_alarm);
240 via_context->enabled = 0;
241 }
242
243 /*
244 * according to Rockwell, all internal registers are cleared, except
245 * for the Timer (1 and 2, counter and latches) and the shift register.
246 */
viacore_reset(via_context_t * via_context)247 void viacore_reset(via_context_t *via_context)
248 {
249 int i;
250
251 /* port data/ddr */
252 for (i = 0; i < 4; i++) {
253 via_context->via[i] = 0;
254 }
255 /* timer 1/2 counter/latches */
256 #if 0
257 for (i = 4; i < 10; i++) {
258 via_context->via[i] = 0xff;
259 }
260 #endif
261 /* omit shift register (10) */
262 for (i = 11; i < 16; i++) {
263 via_context->via[i] = 0;
264 }
265
266 via_context->tal = 0xffff;
267 via_context->t2cl = 0xff;
268 via_context->t2ch = 0xff;
269 via_context->tau = *(via_context->clk_ptr);
270 via_context->tbu = *(via_context->clk_ptr);
271
272 via_context->read_clk = 0;
273
274 via_context->ier = 0;
275 via_context->ifr = 0;
276
277 via_context->pb7 = 0;
278 via_context->pb7x = 0;
279 via_context->pb7o = 0;
280 via_context->pb7xx = 0;
281 via_context->pb7sx = 0;
282
283 via_context->shift_state = 0;
284
285 /* disable vice interrupts */
286 via_context->tai = 0;
287 via_context->tbi = 0;
288 alarm_unset(via_context->t1_alarm);
289 alarm_unset(via_context->t2_alarm);
290 alarm_unset(via_context->sr_alarm);
291 update_myviairq(via_context);
292
293 via_context->oldpa = 0;
294 via_context->oldpb = 0;
295
296 via_context->ca2_state = 1;
297 via_context->cb2_state = 1;
298 (via_context->set_ca2)(via_context, via_context->ca2_state); /* input = high */
299 (via_context->set_cb2)(via_context, via_context->cb2_state); /* input = high */
300
301 if (via_context && via_context->reset) {
302 (via_context->reset)(via_context);
303 }
304
305 via_context->enabled = 1;
306 }
307
viacore_signal(via_context_t * via_context,int line,int edge)308 void viacore_signal(via_context_t *via_context, int line, int edge)
309 {
310 switch (line) {
311 case VIA_SIG_CA1:
312 if ((edge ? 1 : 0) == (via_context->via[VIA_PCR] & 0x01)) {
313 if (IS_CA2_TOGGLE_MODE() && !(via_context->ca2_state)) {
314 via_context->ca2_state = 1;
315 (via_context->set_ca2)(via_context, via_context->ca2_state);
316 }
317 via_context->ifr |= VIA_IM_CA1;
318 update_myviairq(via_context);
319 #ifdef MYVIA_NEED_LATCHING
320 if (IS_PA_INPUT_LATCH()) {
321 via_context->ila = (via_context->read_pra)(via_context, VIA_PRA);
322 }
323 #endif
324 }
325 break;
326 case VIA_SIG_CA2:
327 if (!(via_context->via[VIA_PCR] & 0x08)) {
328 via_context->ifr |= (((edge << 2)
329 ^ via_context->via[VIA_PCR]) & 0x04) ?
330 0 : VIA_IM_CA2;
331 update_myviairq(via_context);
332 }
333 break;
334 case VIA_SIG_CB1:
335 if ((edge ? 0x10 : 0) == (via_context->via[VIA_PCR] & 0x10)) {
336 if (IS_CB2_TOGGLE_MODE() && !(via_context->cb2_state)) {
337 via_context->cb2_state = 1;
338 (via_context->set_cb2)(via_context, via_context->cb2_state);
339 }
340 via_context->ifr |= VIA_IM_CB1;
341 update_myviairq(via_context);
342 #ifdef MYVIA_NEED_LATCHING
343 if (IS_PB_INPUT_LATCH()) {
344 via_context->ilb = (via_context->read_prb)(via_context);
345 }
346 #endif
347 }
348 break;
349 case VIA_SIG_CB2:
350 if (!(via_context->via[VIA_PCR] & 0x80)) {
351 via_context->ifr |= (((edge << 6)
352 ^ via_context->via[VIA_PCR]) & 0x40) ?
353 0 : VIA_IM_CB2;
354 update_myviairq(via_context);
355 }
356 break;
357 }
358 }
359
viacore_store(via_context_t * via_context,uint16_t addr,uint8_t byte)360 void viacore_store(via_context_t *via_context, uint16_t addr, uint8_t byte)
361 {
362 CLOCK rclk;
363
364 if (*(via_context->rmw_flag)) {
365 (*(via_context->clk_ptr))--;
366 *(via_context->rmw_flag) = 0;
367 viacore_store(via_context, addr, via_context->last_read);
368 (*(via_context->clk_ptr))++;
369 }
370
371 /* stores have a one-cycle offset if CLK++ happens before store */
372 rclk = *(via_context->clk_ptr) - via_context->write_offset;
373
374 addr &= 0xf;
375
376 switch (addr) {
377 /* these are done with saving the value */
378 case VIA_PRA: /* port A */
379 via_context->ifr &= ~VIA_IM_CA1;
380 if (!IS_CA2_INDINPUT()) {
381 via_context->ifr &= ~VIA_IM_CA2;
382 }
383 if (IS_CA2_HANDSHAKE()) {
384 via_context->ca2_state = 0;
385 (via_context->set_ca2)(via_context, via_context->ca2_state);
386 if (IS_CA2_PULSE_MODE()) {
387 via_context->ca2_state = 1;
388 (via_context->set_ca2)(via_context, via_context->ca2_state);
389 }
390 }
391 if (via_context->ier & (VIA_IM_CA1 | VIA_IM_CA2)) {
392 update_myviairq(via_context);
393 }
394 /* fall through */
395
396 case VIA_PRA_NHS: /* port A, no handshake */
397 via_context->via[VIA_PRA_NHS] = byte;
398 addr = VIA_PRA;
399 /* fall through */
400
401 case VIA_DDRA:
402 via_context->via[addr] = byte;
403 byte = via_context->via[VIA_PRA] | ~(via_context->via[VIA_DDRA]);
404 (via_context->store_pra)(via_context, byte, via_context->oldpa, addr);
405 via_context->oldpa = byte;
406 break;
407
408 case VIA_PRB: /* port B */
409 via_context->ifr &= ~VIA_IM_CB1;
410 if ((via_context->via[VIA_PCR] & 0xa0) != 0x20) {
411 via_context->ifr &= ~VIA_IM_CB2;
412 }
413 if (IS_CB2_HANDSHAKE()) {
414 via_context->cb2_state = 0;
415 (via_context->set_cb2)(via_context, via_context->cb2_state);
416 if (IS_CB2_PULSE_MODE()) {
417 via_context->cb2_state = 1;
418 (via_context->set_cb2)(via_context, via_context->cb2_state);
419 }
420 }
421 if (via_context->ier & (VIA_IM_CB1 | VIA_IM_CB2)) {
422 update_myviairq(via_context);
423 }
424 /* fall through */
425
426 case VIA_DDRB:
427 via_context->via[addr] = byte;
428 byte = via_context->via[VIA_PRB] | ~(via_context->via[VIA_DDRB]);
429 (via_context->store_prb)(via_context, byte, via_context->oldpb, addr);
430 via_context->oldpb = byte;
431 break;
432
433 case VIA_SR: /* Serial Port output buffer */
434 via_context->via[addr] = byte;
435 /* shift state can only be reset once 8 bits are complete */
436 if (via_context->ifr & VIA_IM_SR) {
437 via_context->ifr &= ~VIA_IM_SR;
438 update_myviairq(via_context);
439 via_context->shift_state = 0;
440 }
441
442 (via_context->store_sr)(via_context, byte);
443 break;
444
445 /* Timers */
446
447 case VIA_T1CL:
448 case VIA_T1LL:
449 via_context->via[VIA_T1LL] = byte;
450 update_myviatal(via_context, rclk);
451 break;
452
453 case VIA_T1CH: /* Write timer A high */
454 via_context->via[VIA_T1LH] = byte;
455 update_myviatal(via_context, rclk);
456 /* load counter with latch value */
457 via_context->tau = rclk + via_context->tal + 3 + TAUOFFSET;
458 via_context->tai = rclk + via_context->tal + 2;
459 alarm_set(via_context->t1_alarm, via_context->tai);
460
461 /* set pb7 state */
462 via_context->pb7 = 0;
463 via_context->pb7o = 0;
464
465 /* Clear T1 interrupt */
466 via_context->ifr &= ~VIA_IM_T1;
467 update_myviairq(via_context);
468 break;
469
470 case VIA_T1LH: /* Write timer A high order latch */
471 via_context->via[addr] = byte;
472 update_myviatal(via_context, rclk);
473
474 /* CAUTION: according to the synertek notes, writing to T1LH does
475 NOT change the interrupt flags. however, not doing so breaks eg
476 the VIC20 game "bandits". also in a seperare test program it was
477 verified that indeed writing to the high order latch clears the
478 interrupt flag, also on synertek VIAs. (see via_t1irqack) */
479
480 /* Clear T1 interrupt */
481 via_context->ifr &= ~VIA_IM_T1;
482 update_myviairq(via_context);
483 break;
484
485 case VIA_T2LL: /* Write timer 2 low latch */
486 via_context->via[VIA_T2LL] = byte;
487 (via_context->store_t2l)(via_context, byte);
488 break;
489
490 case VIA_T2CH: /* Write timer 2 high counter/latch */
491 /* update counter and latch values */
492 via_context->via[VIA_T2LH] = byte;
493 via_context->t2cl = via_context->via[VIA_T2LL];
494 via_context->t2ch = byte;
495
496 /* start T2 only in timer mode, leave unchanged in pulse counting mode */
497 if (!(via_context->via[VIA_ACR] & 0x20)) {
498 /* set the next alarm to the low latch value as timer cascading mode change
499 matters at each underflow of the T2 low counter */
500 via_context->tbu = rclk + via_context->t2cl + 3;
501 via_context->tbi = rclk + via_context->t2cl + 1;
502 alarm_set(via_context->t2_alarm, via_context->tbi);
503 }
504
505 /* Clear T2 interrupt */
506 via_context->ifr &= ~VIA_IM_T2;
507 update_myviairq(via_context);
508 break;
509
510 /* Interrupts */
511
512 case VIA_IFR: /* 6522 Interrupt Flag Register */
513 via_context->ifr &= ~byte;
514 update_myviairq(via_context);
515
516 /* FIXME: clearing any timer interrupt should set the relevant timer alarm */
517 break;
518
519 case VIA_IER: /* Interrupt Enable Register */
520 if (byte & VIA_IM_IRQ) {
521 /* set interrupts */
522 via_context->ier |= byte & 0x7f;
523 } else {
524 /* clear interrupts */
525 via_context->ier &= ~byte;
526 }
527 update_myviairq(via_context);
528 break;
529
530 /* Control */
531
532 case VIA_ACR:
533 /* bit 7 timer 1 output to PB7 */
534 update_myviatal(via_context, rclk);
535 if ((via_context->via[VIA_ACR] ^ byte) & 0x80) {
536 if (byte & 0x80) {
537 via_context->pb7 = 1 ^ via_context->pb7x;
538 }
539 }
540 if ((via_context->via[VIA_ACR] ^ byte) & 0x40) {
541 via_context->pb7 ^= via_context->pb7sx;
542 if ((byte & 0x40)) {
543 if (via_context->pb7x || via_context->pb7xx) {
544 if (via_context->tal) {
545 via_context->pb7o = 1;
546 } else {
547 via_context->pb7o = 0;
548 if ((via_context->via[VIA_ACR] & 0x80)
549 && via_context->pb7x
550 && (!(via_context->pb7xx))) {
551 via_context->pb7 ^= 1;
552 }
553 }
554 }
555 }
556 }
557 via_context->pb7sx = via_context->pb7x;
558
559 /* bit 1, 0 latch enable port B and A */
560 #ifdef MYVIA_NEED_LATCHING
561 /* switch on port A latching - FIXME: is this ok? */
562 if ((!(via_context->via[addr] & 1)) && (byte & 1)) {
563 via_context->ila = (via_context->read_pra)(via_context, addr);
564 }
565 /* switch on port B latching - FIXME: is this ok? */
566 if ((!(via_context->via[addr] & 2)) && (byte & 2)) {
567 via_context->ilb = (via_context->read_prb)(via_context);
568 }
569 #endif
570
571 /* switch between timer and pulse counting mode if bit 5 changes */
572 if ((via_context->via[VIA_ACR] ^ byte) & 0x20) {
573 if (byte & 0x20) {
574 /* Pulse counting mode: set t2 to the current T2 value;
575 PB6 should always update t2 and update irq on underflow */
576 CLOCK stop = myviatb(via_context);
577 via_context->t2cl = (uint8_t)(stop & 0xff);
578 via_context->t2ch = (uint8_t)((stop >> 8) & 0xff);
579
580 /* stop alarm to prevent t2 and T2 updates */
581 alarm_unset(via_context->t2_alarm);
582 via_context->tbi = 0;
583 } else {
584 /* Timer mode; set the next alarm to the low latch value as timer cascading mode change
585 matters at each underflow of the T2 low counter */
586 via_context->tbu = rclk + via_context->t2cl + 3;
587 via_context->tbi = rclk + via_context->t2cl + 1;
588 alarm_set(via_context->t2_alarm, via_context->tbi);
589 }
590 }
591
592 /* handle the t2 alarm for the serial shift register
593 *
594 * FIXME: it is not clear what happens when pulse counting mode is
595 * selected for t2
596 */
597 if ((byte & 0x20) == 0) {
598 if (((byte & 0x0c) == 0x04) || /* FIXME: shift register under t2 control */
599 ((byte & 0x1c) == 0x10)) { /* FIXME: shift register free running at t2 rate */
600 /* Timer mode; set the next alarm to the low latch value as timer cascading mode change
601 matters at each underflow of the T2 low counter */
602 via_context->tbu = rclk + via_context->t2cl + 3;
603 via_context->tbi = rclk + via_context->t2cl + 1;
604 alarm_set(via_context->t2_alarm, via_context->tbi);
605 }
606 }
607
608 /* bit 4, 3, 2 shift register control */
609 if ((byte & 0x0c) == 0x08) {
610 /* shift under control of phi2 */
611 if ((byte & 0x10) == 0x10) {
612 alarm_set(via_context->sr_alarm, rclk + 3); /* FIXME */
613 } else {
614 alarm_set(via_context->sr_alarm, rclk + 3); /* FIXME */
615 }
616 } else {
617 /* when disabled or external clock, stop the alarm */
618 alarm_unset(via_context->sr_alarm);
619 }
620
621 via_context->via[addr] = byte;
622 (via_context->store_acr)(via_context, byte);
623
624 break;
625
626 case VIA_PCR:
627
628 /* bit 7, 6, 5 CB2 handshake/interrupt control */
629 /* bit 4 CB1 interrupt control */
630
631 /* bit 3, 2, 1 CA2 handshake/interrupt control */
632 /* bit 0 CA1 interrupt control */
633
634 if ((byte & 0x0e) == 0x0c) { /* set output low */
635 via_context->ca2_state = 0;
636 } else
637 if ((byte & 0x0e) == 0x0e) { /* set output high */
638 via_context->ca2_state = 1;
639 } else { /* set to toggle/pulse/input */
640 /* FIXME: is this correct if handshake is already active? */
641 via_context->ca2_state = 1;
642 }
643 (via_context->set_ca2)(via_context, via_context->ca2_state);
644
645 if ((byte & 0xe0) == 0xc0) { /* set output low */
646 via_context->cb2_state = 0;
647 } else
648 if ((byte & 0xe0) == 0xe0) { /* set output high */
649 via_context->cb2_state = 1;
650 } else { /* set to toggle/pulse/input */
651 /* FIXME: is this correct if handshake is already active? */
652 via_context->cb2_state = 1;
653 }
654 (via_context->set_cb2)(via_context, via_context->cb2_state);
655
656 (via_context->store_pcr)(via_context, byte, addr);
657
658 via_context->via[addr] = byte;
659
660 break;
661
662 default:
663 via_context->via[addr] = byte;
664 }
665 }
666
667
668 /* ------------------------------------------------------------------------- */
669
viacore_read(via_context_t * via_context,uint16_t addr)670 uint8_t viacore_read(via_context_t *via_context, uint16_t addr)
671 {
672 #ifdef MYVIA_TIMER_DEBUG
673 uint8_t viacore_read_(via_context_t *via_context, uint16_t);
674 uint8_t retv = myvia_read_(via_context, addr);
675 addr &= 0x0f;
676 if ((addr > 3 && addr < 10) || app_resources.debugFlag) {
677 log_message(via_context->log,
678 "myvia_read(%x) -> %02x, clk=%d", addr, retv,
679 *(via_context->clk_ptr));
680 }
681 return retv;
682 }
683
viacore_read_(via_context_t * via_context,uint16_t addr)684 uint8_t viacore_read_(via_context_t *via_context, uint16_t addr)
685 {
686 #endif
687 uint8_t byte = 0xff;
688 CLOCK rclk;
689
690 addr &= 0xf;
691
692 via_context->read_clk = *(via_context->clk_ptr);
693 via_context->read_offset = 0;
694 rclk = *(via_context->clk_ptr);
695
696 if (addr >= VIA_T1CL && addr <= VIA_IER) {
697 if (via_context->tai && (via_context->tai < *(via_context->clk_ptr))) {
698 viacore_intt1(*(via_context->clk_ptr) - via_context->tai,
699 (void *)via_context);
700 }
701 if (via_context->tbi && (via_context->tbi < *(via_context->clk_ptr))) {
702 viacore_intt2(*(via_context->clk_ptr) - via_context->tbi,
703 (void *)via_context);
704 }
705 }
706
707 switch (addr) {
708 case VIA_PRA: /* port A */
709 via_context->ifr &= ~VIA_IM_CA1;
710 if ((via_context->via[VIA_PCR] & 0x0a) != 0x02) {
711 via_context->ifr &= ~VIA_IM_CA2;
712 }
713 if (IS_CA2_HANDSHAKE()) {
714 via_context->ca2_state = 0;
715 (via_context->set_ca2)(via_context, via_context->ca2_state);
716 if (IS_CA2_PULSE_MODE()) {
717 via_context->ca2_state = 1;
718 (via_context->set_ca2)(via_context, via_context->ca2_state);
719 }
720 }
721 if (via_context->ier & (VIA_IM_CA1 | VIA_IM_CA2)) {
722 update_myviairq(via_context);
723 }
724 /* falls through */
725
726 case VIA_PRA_NHS: /* port A, no handshake */
727 /* WARNING: this pin reads the voltage of the output pins, not
728 the ORA value as the other port. Value read might be different
729 from what is expected due to excessive load. */
730 #ifdef MYVIA_NEED_LATCHING
731 if (IS_PA_INPUT_LATCH()) {
732 byte = via_context->ila;
733 } else {
734 byte = (via_context->read_pra)(via_context, addr);
735 }
736 #else
737 byte = (via_context->read_pra)(via_context, addr);
738 #endif
739 via_context->ila = byte;
740 via_context->last_read = byte;
741 return byte;
742
743 case VIA_PRB: /* port B */
744 via_context->ifr &= ~VIA_IM_CB1;
745 if ((via_context->via[VIA_PCR] & 0xa0) != 0x20) {
746 via_context->ifr &= ~VIA_IM_CB2;
747 }
748 if (via_context->ier & (VIA_IM_CB1 | VIA_IM_CB2)) {
749 update_myviairq(via_context);
750 }
751
752 /* WARNING: this pin reads the ORA for output pins, not
753 the voltage on the pins as the other port. */
754 #ifdef MYVIA_NEED_LATCHING
755 if (IS_PB_INPUT_LATCH()) {
756 byte = via_context->ilb;
757 } else {
758 byte = (via_context->read_prb)(via_context);
759 }
760 #else
761 byte = (via_context->read_prb)(via_context);
762 #endif
763 via_context->ilb = byte;
764 byte = (byte & ~(via_context->via[VIA_DDRB]))
765 | (via_context->via[VIA_PRB] & via_context->via[VIA_DDRB]);
766
767 if (via_context->via[VIA_ACR] & 0x80) {
768 update_myviatal(via_context, rclk);
769 byte = (byte & 0x7f)
770 | (((via_context->pb7 ^ via_context->pb7x)
771 | via_context->pb7o) ? 0x80 : 0);
772 }
773 via_context->last_read = byte;
774 return byte;
775
776 /* Timers */
777
778 case VIA_T1CL /*TIMER_AL */: /* timer A low counter */
779 via_context->ifr &= ~VIA_IM_T1;
780 update_myviairq(via_context);
781 via_context->last_read = (uint8_t)(myviata(via_context) & 0xff);
782 return via_context->last_read;
783
784 case VIA_T1CH /*TIMER_AH */: /* timer A high counter */
785 via_context->last_read = (uint8_t)((myviata(via_context) >> 8) & 0xff);
786 return via_context->last_read;
787
788 case VIA_T2CL /*TIMER_BL */: /* timer B low counter */
789 via_context->ifr &= ~VIA_IM_T2;
790 update_myviairq(via_context);
791 via_context->last_read = (uint8_t)(myviatb(via_context) & 0xff);
792 return via_context->last_read;
793
794 case VIA_T2CH /*TIMER_BH */: /* timer B high counter */
795 via_context->last_read = (uint8_t)((myviatb(via_context) >> 8) & 0xff);
796 return via_context->last_read;
797
798 case VIA_SR: /* Serial Port Shift Register */
799 /* shift state can only be reset once 8 bits are complete */
800 if (via_context->ifr & VIA_IM_SR) {
801 via_context->ifr &= ~VIA_IM_SR;
802 update_myviairq(via_context);
803 via_context->shift_state = 0;
804 }
805 via_context->last_read = via_context->via[addr];
806 return via_context->last_read;
807
808 /* Interrupts */
809
810 case VIA_IFR: /* Interrupt Flag Register */
811 {
812 uint8_t t = via_context->ifr;
813 if (via_context->ifr & via_context->ier /*[VIA_IER] */) {
814 t |= 0x80;
815 }
816 via_context->last_read = t;
817 return (t);
818 }
819
820 case VIA_IER: /* 6522 Interrupt Control Register */
821 via_context->last_read = (via_context->ier /*[VIA_IER] */ | 0x80);
822 return via_context->last_read;
823 }
824
825 via_context->last_read = via_context->via[addr];
826
827 return via_context->via[addr];
828 }
829
830 /* return value of a register without side effects */
831 /* FIXME: this is buggy/incomplete */
viacore_peek(via_context_t * via_context,uint16_t addr)832 uint8_t viacore_peek(via_context_t *via_context, uint16_t addr)
833 {
834
835 addr &= 0xf;
836
837 switch (addr) {
838 case VIA_PRA:
839 case VIA_PRA_NHS: /* port A, no handshake */
840 {
841 uint8_t byte;
842 /* WARNING: this pin reads the voltage of the output pins, not
843 the ORA value as the other port. Value read might be different
844 from what is expected due to excessive load. */
845 #ifdef MYVIA_NEED_LATCHING
846 if (IS_PA_INPUT_LATCH()) {
847 byte = via_context->ila;
848 } else {
849 /* FIXME: side effects ? */
850 byte = (via_context->read_pra)(via_context, addr);
851 }
852 #else
853 /* FIXME: side effects ? */
854 byte = (via_context->read_pra)(via_context, addr);
855 #endif
856 return byte;
857 }
858
859 case VIA_PRB: /* port B */
860 {
861 uint8_t byte;
862 #ifdef MYVIA_NEED_LATCHING
863 if (IS_PB_INPUT_LATCH()) {
864 byte = via_context->ilb;
865 } else {
866 /* FIXME: side effects ? */
867 byte = (via_context->read_prb)(via_context);
868 }
869 #else
870 /* FIXME: side effects ? */
871 byte = (via_context->read_prb)(via_context);
872 #endif
873 byte = (byte & ~(via_context->via[VIA_DDRB]))
874 | (via_context->via[VIA_PRB] & via_context->via[VIA_DDRB]);
875 if (via_context->via[VIA_ACR] & 0x80) {
876 /* update_myviatal(via_context, rclk); */
877 byte = (byte & 0x7f) | (((via_context->pb7 ^ via_context->pb7x)
878 | via_context->pb7o) ? 0x80 : 0);
879 }
880 return byte;
881 }
882 case VIA_DDRA:
883 case VIA_DDRB:
884 break;
885
886 /* Timers */
887
888 case VIA_T1CL /*TIMER_AL */: /* timer A low */
889 return (uint8_t)(myviata(via_context) & 0xff);
890
891 case VIA_T1CH /*TIMER_AH */: /* timer A high */
892 return (uint8_t)((myviata(via_context) >> 8) & 0xff);
893
894 case VIA_T1LL: /* timer A low order latch */
895 case VIA_T1LH: /* timer A high order latch */
896 break;
897
898 case VIA_T2CL /*TIMER_BL */: /* timer B low */
899 return (uint8_t)(myviatb(via_context) & 0xff);
900
901 case VIA_T2CH /*TIMER_BH */: /* timer B high */
902 return (uint8_t)((myviatb(via_context) >> 8) & 0xff);
903
904 case VIA_IFR: /* Interrupt Flag Register */
905 return via_context->ifr;
906
907 case VIA_IER: /* 6522 Interrupt Control Register */
908 return via_context->ier | 0x80;
909
910 case VIA_PCR:
911 case VIA_ACR:
912 case VIA_SR:
913 break;
914 }
915
916 return via_context->via[addr];
917 }
918
919 /* ------------------------------------------------------------------------- */
920
viacore_intt1(CLOCK offset,void * data)921 static void viacore_intt1(CLOCK offset, void *data)
922 {
923 CLOCK rclk;
924 via_context_t *via_context = (via_context_t *)data;
925
926 rclk = *(via_context->clk_ptr) - offset;
927
928
929 #ifdef MYVIA_TIMER_DEBUG
930 if (app_resources.debugFlag) {
931 log_message(via_context->log, "myvia timer A interrupt");
932 }
933 #endif
934
935 if (!(via_context->via[VIA_ACR] & 0x40)) { /* one-shot mode */
936 #ifdef MYVIA_TIMER_DEBUG
937 log_message(via_context->log,
938 "MYVIA Timer A interrupt -- one-shot mode: next int won't happen");
939 #endif
940 alarm_unset(via_context->t1_alarm);
941 via_context->tai = 0;
942 } else { /* continuous mode */
943 /* load counter with latch value */
944 via_context->tai += via_context->tal + 2;
945 alarm_set(via_context->t1_alarm, via_context->tai);
946
947 /* Let tau also keep up with the cpu clock
948 this should avoid "% (via_context->tal + 2)" case */
949 via_context->tau += via_context->tal + 2;
950 }
951 via_context->ifr |= VIA_IM_T1;
952 update_myviairq_rclk(via_context, rclk);
953
954 /* TODO: toggle PB7? */
955 /*(viaier & VIA_IM_T1) ? 1:0; */
956 }
957
958 /* WARNING: this is a hack, used to interface with c64fastiec.c, c128fastiec.c */
viacore_set_sr(via_context_t * via_context,uint8_t data)959 void viacore_set_sr(via_context_t *via_context, uint8_t data)
960 {
961 if (!(via_context->via[VIA_ACR] & 0x10) && (via_context->via[VIA_ACR] & 0x0c)) {
962 via_context->via[VIA_SR] = data;
963 via_context->ifr |= VIA_IM_SR;
964 update_myviairq(via_context);
965 via_context->shift_state = 15;
966 }
967 }
968
do_shiftregister(CLOCK offset,void * data)969 static inline void do_shiftregister(CLOCK offset, void *data)
970 {
971 CLOCK rclk;
972 via_context_t *via_context = (via_context_t *)data;
973 rclk = *(via_context->clk_ptr) - offset;
974
975 if (via_context->shift_state < 16) {
976 /* FIXME: CB1 should be toggled, and interrupt flag set according to edge detection in PCR */
977 if (via_context->shift_state & 1) {
978 if (via_context->via[VIA_ACR] & 0x10) {
979 /* FIXME: shift out */
980 via_context->via[VIA_SR] = ((via_context->via[VIA_SR] << 1 ) & 0xfe) | ((via_context->via[VIA_SR] >> 7) & 1);
981 } else {
982 /* shift in */
983 /* FIXME: we should read CB2 here instead of 1, but CB2 state must not be controlled by PCR
984 until the signalling function is correct with shifter active, just use 1 instead */
985 via_context->via[VIA_SR] = (via_context->via[VIA_SR] << 1 ) | 1;
986 }
987 }
988 via_context->shift_state += 1;
989 /* next shifter bit; set SR interrupt if 8 bits are complete */
990 if (via_context->shift_state == 16) {
991 via_context->ifr |= VIA_IM_SR;
992 update_myviairq_rclk(via_context, rclk);
993 via_context->shift_state = 0;
994 }
995 }
996 }
997
998 /* T2 can be switched between 8 and 16 bit modes ad-hoc, any time, by setting
999 the shifter to be controlled by T2 via selecting the relevant ACR shift
1000 register operating mode.
1001 This change affects how the next T2 low underflow is handled */
viacore_intt2(CLOCK offset,void * data)1002 static void viacore_intt2(CLOCK offset, void *data)
1003 {
1004 CLOCK rclk;
1005 int next_alarm;
1006 via_context_t *via_context = (via_context_t *)data;
1007
1008 rclk = *(via_context->clk_ptr) - offset;
1009
1010 #ifdef MYVIA_TIMER_DEBUG
1011 if (app_resources.debugFlag) {
1012 log_message(via_context->log, "MYVIA timer B interrupt.");
1013 }
1014 #endif
1015 /* If the shifter is under T2 control, the T2 timer works differently, and have a period of T2 low.
1016 T2 high is still cascaded though and decreases at each T2 low underflow */
1017 if ((via_context->via[VIA_ACR] & 0x0c) == 0x04) {
1018 /* 8 bit timer mode; reload T2 low from latch */
1019 via_context->t2cl = via_context->via[VIA_T2LL];
1020
1021 /* set next alarm to T2 low period */
1022 next_alarm = via_context->via[VIA_T2LL] + 2;
1023
1024 /* T2 acts as a pulse generator for CB1
1025 every second underflow is a pulse updating the shift register,
1026 until all 8 bits are complete */
1027 do_shiftregister(offset, data);
1028 } else if ((via_context->via[VIA_ACR] & 0x1c) == 0x10) {
1029
1030 /* set next alarm to T2 low period */
1031 next_alarm = via_context->via[VIA_T2LL] + 2;
1032
1033 /* same as above, except bits will we clocked out CB2 repeatedly without
1034 * stopping after 8 bits */
1035 do_shiftregister(offset, data);
1036 } else {
1037 /* 16 bit timer mode; it is guaranteed that T2 low is in underflow */
1038 via_context->t2cl = 0xff;
1039
1040 /* set next alarm to 256 cycles later, until t2 high underflow */
1041 next_alarm = (via_context->t2ch) ? 256 : 0;
1042 }
1043
1044 /* T2 low count underflow always decreases T2 high count */
1045 via_context->t2ch--;
1046
1047 /* set the next T2 low underflow alarm, or turn off the alarm */
1048 if (next_alarm) {
1049 via_context->tbu += next_alarm;
1050 via_context->tbi += next_alarm;
1051 alarm_set(via_context->t2_alarm, via_context->tbi);
1052 } else {
1053 alarm_unset(via_context->t2_alarm);
1054 via_context->tbi = 0;
1055 }
1056
1057 /* 16 bit timer underflow generates an interrupt */
1058 /* FIXME: does 16 bit underflow generate an IRQ in 8 bit mode? 8 bit underflow does not */
1059 /* FIXME: no IRQ when shift register is in free running mode? */
1060 if (via_context->t2ch == 0xff) {
1061 via_context->ifr |= VIA_IM_T2;
1062 update_myviairq_rclk(via_context, rclk);
1063 }
1064 }
1065
1066 /* alarm callback for the case when the shift register is under phi2 control */
viacore_intsr(CLOCK offset,void * data)1067 static void viacore_intsr(CLOCK offset, void *data)
1068 {
1069 CLOCK rclk;
1070 via_context_t *via_context = (via_context_t *)data;
1071 rclk = *(via_context->clk_ptr) - offset;
1072 do_shiftregister(offset, data);
1073 alarm_set(via_context->sr_alarm, rclk + 1);
1074 }
1075
viacore_clk_overflow_callback(CLOCK sub,void * data)1076 static void viacore_clk_overflow_callback(CLOCK sub, void *data)
1077 {
1078 via_context_t *via_context;
1079
1080 via_context = (via_context_t *)data;
1081
1082 if (via_context->enabled == 0) {
1083 return;
1084 }
1085
1086 #if 0
1087 via_context->tau = via_context->tal + 2 -
1088 ((*(via_context->clk_ptr) + sub - via_context->tau)
1089 % (via_context->tal + 2));
1090
1091 via_context->tbu = via_context->tbl + 2 -
1092 ((*(via_context->clk_ptr) + sub - via_context->tbu)
1093 % (via_context->tbl + 2));
1094 #else
1095 via_context->tau -= sub;
1096 via_context->tbu -= sub;
1097 #endif
1098
1099 if (via_context->tai) {
1100 via_context->tai -= sub;
1101 }
1102
1103 if (via_context->tbi) {
1104 via_context->tbi -= sub;
1105 }
1106
1107 if (via_context->read_clk > sub) {
1108 via_context->read_clk -= sub;
1109 } else {
1110 via_context->read_clk = 0;
1111 }
1112 }
1113
viacore_setup_context(via_context_t * via_context)1114 void viacore_setup_context(via_context_t *via_context)
1115 {
1116 int i;
1117
1118 via_context->read_clk = 0;
1119 via_context->read_offset = 0;
1120 via_context->last_read = 0;
1121 via_context->log = LOG_ERR;
1122
1123 via_context->my_module_name_alt1 = NULL;
1124 via_context->my_module_name_alt2 = NULL;
1125
1126 via_context->write_offset = 1;
1127 /* assume all registers 0 at powerup */
1128 for (i = 0; i < 16; i++) {
1129 via_context->via[i] = 0;
1130 }
1131 /* timers and timer latches apparently do not contain 0 at powerup */
1132 via_context->via[4] = via_context->via[6] = 0xff;
1133 via_context->via[5] = via_context->via[7] = 223; /* my vic20 gives 223 here (gpz) */
1134 via_context->via[8] = 0xff;
1135 via_context->via[9] = 0xff;
1136 }
1137
viacore_init(via_context_t * via_context,alarm_context_t * alarm_context,interrupt_cpu_status_t * int_status,clk_guard_t * clk_guard)1138 void viacore_init(via_context_t *via_context, alarm_context_t *alarm_context,
1139 interrupt_cpu_status_t *int_status, clk_guard_t *clk_guard)
1140 {
1141 char *buffer;
1142
1143 if (via_context->log == LOG_ERR) {
1144 via_context->log = log_open(via_context->my_module_name);
1145 }
1146
1147 buffer = lib_msprintf("%sT1", via_context->myname);
1148 via_context->t1_alarm = alarm_new(alarm_context, buffer, viacore_intt1, via_context);
1149 lib_free(buffer);
1150
1151 buffer = lib_msprintf("%sT2", via_context->myname);
1152 via_context->t2_alarm = alarm_new(alarm_context, buffer, viacore_intt2, via_context);
1153 lib_free(buffer);
1154
1155 buffer = lib_msprintf("%sSR", via_context->myname);
1156 via_context->sr_alarm = alarm_new(alarm_context, buffer, viacore_intsr, via_context);
1157 lib_free(buffer);
1158
1159 via_context->int_num = interrupt_cpu_status_int_new(int_status, via_context->myname);
1160 clk_guard_add_callback(clk_guard, viacore_clk_overflow_callback, via_context);
1161 }
1162
viacore_shutdown(via_context_t * via_context)1163 void viacore_shutdown(via_context_t *via_context)
1164 {
1165 lib_free(via_context->prv);
1166 lib_free(via_context->myname);
1167 lib_free(via_context->my_module_name);
1168 lib_free(via_context->my_module_name_alt1);
1169 lib_free(via_context->my_module_name_alt2);
1170 lib_free(via_context);
1171 }
1172
1173 /*------------------------------------------------------------------------*/
1174
1175 /* The name of the modul must be defined before including this file. */
1176 #define VIA_DUMP_VER_MAJOR 2
1177 #define VIA_DUMP_VER_MINOR 1
1178
1179 /*
1180 * The dump data:
1181 *
1182 * UBYTE ORA
1183 * UBYTE DDRA
1184 * UBYTE ORB
1185 * UBYTE DDRB
1186 * UWORD T1L
1187 * UWORD T1C
1188 * UBYTE T2LL
1189 * UBYTE T2LH
1190 * UBYTE T2CL
1191 * UBYTE T2CH
1192 * UWORD T2C
1193 * UBYTE SR
1194 * UBYTE ACR
1195 * UBYTE PCR
1196 * UBYTE IFR active interrupts
1197 * UBYTE IER interrupt masks
1198 * UBYTE PB7 bit 7 = pb7 state
1199 * UBYTE SRHBITS shift register state helper
1200 * UBYTE CABSTATE bit 7 = ca2 state, bi 6 = cb2 state
1201 * UBYTE ILA input latch port A
1202 * UBYTE ILB input latch port B
1203 */
1204
1205 /* FIXME!!! Error check. */
1206
viacore_snapshot_write_module(via_context_t * via_context,snapshot_t * s)1207 int viacore_snapshot_write_module(via_context_t *via_context, snapshot_t *s)
1208 {
1209 snapshot_module_t *m;
1210
1211 if (via_context->tai && (via_context->tai <= *(via_context->clk_ptr))) {
1212 viacore_intt1(*(via_context->clk_ptr) - via_context->tai,
1213 (void *)via_context);
1214 }
1215 if (via_context->tbi && (via_context->tbi <= *(via_context->clk_ptr))) {
1216 viacore_intt2(*(via_context->clk_ptr) - via_context->tbi,
1217 (void *)via_context);
1218 }
1219
1220 m = snapshot_module_create(s, via_context->my_module_name, VIA_DUMP_VER_MAJOR, VIA_DUMP_VER_MINOR);
1221
1222 if (m == NULL) {
1223 return -1;
1224 }
1225
1226 if (0
1227 || SMW_B(m, via_context->via[VIA_PRA]) < 0
1228 || SMW_B(m, via_context->via[VIA_DDRA]) < 0
1229 || SMW_B(m, via_context->via[VIA_PRB]) < 0
1230 || SMW_B(m, via_context->via[VIA_DDRB]) < 0
1231 || SMW_W(m, (uint16_t)(via_context->tal)) < 0
1232 || SMW_W(m, (uint16_t)myviata(via_context)) < 0
1233 || SMW_B(m, via_context->via[VIA_T2LL]) < 0
1234 || SMW_B(m, via_context->via[VIA_T2LH]) < 0
1235 || SMW_B(m, via_context->t2cl) < 0
1236 || SMW_B(m, via_context->t2ch) < 0
1237 || SMW_W(m, (uint16_t)myviatb(via_context)) < 0
1238 || SMW_B(m, (uint8_t)((via_context->tai ? 0x80 : 0) | (via_context->tbi ? 0x40 : 0))) < 0
1239 || SMW_B(m, via_context->via[VIA_SR]) < 0
1240 || SMW_B(m, via_context->via[VIA_ACR]) < 0
1241 || SMW_B(m, via_context->via[VIA_PCR]) < 0
1242 || SMW_B(m, (uint8_t)(via_context->ifr)) < 0
1243 || SMW_B(m, (uint8_t)(via_context->ier)) < 0
1244 /* FIXME! */
1245 || SMW_B(m, (uint8_t)((((via_context->pb7 ^ via_context->pb7x) | via_context->pb7o) ? 0x80 : 0))) < 0
1246 /* SRHBITS */
1247 || SMW_B(m, (uint8_t)via_context->shift_state) < 0
1248 || SMW_B(m, (uint8_t)((via_context->ca2_state ? 0x80 : 0) | (via_context->cb2_state ? 0x40 : 0))) < 0
1249 || SMW_B(m, via_context->ila) < 0
1250 || SMW_B(m, via_context->ilb) < 0) {
1251 snapshot_module_close(m);
1252 return -1;
1253 }
1254
1255 return snapshot_module_close(m);
1256 }
1257
viacore_snapshot_read_module(via_context_t * via_context,snapshot_t * s)1258 int viacore_snapshot_read_module(via_context_t *via_context, snapshot_t *s)
1259 {
1260 uint8_t vmajor, vminor;
1261 uint8_t byte;
1262 uint8_t byte1, byte2, byte3, byte4, byte5, byte6;
1263 uint16_t word1, word2, word3;
1264 uint16_t addr;
1265 CLOCK rclk = *(via_context->clk_ptr);
1266 snapshot_module_t *m;
1267
1268 m = snapshot_module_open(s, via_context->my_module_name, &vmajor, &vminor);
1269
1270 if (m == NULL) {
1271 if (via_context->my_module_name_alt1 == NULL) {
1272 return -1;
1273 }
1274
1275 m = snapshot_module_open(s, via_context->my_module_name_alt1,
1276 &vmajor, &vminor);
1277 if (m == NULL) {
1278 if (via_context->my_module_name_alt2 == NULL) {
1279 return -1;
1280 }
1281
1282 m = snapshot_module_open(s, via_context->my_module_name_alt2,
1283 &vmajor, &vminor);
1284 if (m == NULL) {
1285 return -1;
1286 }
1287 }
1288 }
1289
1290 /* if major version does not match, the snapshot is not compatible */
1291 if (vmajor != VIA_DUMP_VER_MAJOR) {
1292 snapshot_set_error(SNAPSHOT_MODULE_INCOMPATIBLE);
1293 snapshot_module_close(m);
1294 return -1;
1295 }
1296 /* Do not accept versions higher than current */
1297 if (vminor > VIA_DUMP_VER_MINOR) {
1298 snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION);
1299 snapshot_module_close(m);
1300 return -1;
1301 }
1302
1303 alarm_unset(via_context->t1_alarm);
1304 alarm_unset(via_context->t2_alarm);
1305 alarm_unset(via_context->sr_alarm);
1306
1307 via_context->tai = 0;
1308 via_context->tbi = 0;
1309
1310 if (0
1311 || SMR_B(m, &(via_context->via[VIA_PRA])) < 0
1312 || SMR_B(m, &(via_context->via[VIA_DDRA])) < 0
1313 || SMR_B(m, &(via_context->via[VIA_PRB])) < 0
1314 || SMR_B(m, &(via_context->via[VIA_DDRB])) < 0
1315 || SMR_W(m, &word1) < 0
1316 || SMR_W(m, &word2) < 0
1317 || SMR_B(m, &(via_context->via[VIA_T2LL])) < 0
1318 || SMR_B(m, &(via_context->via[VIA_T2LH])) < 0
1319 || SMR_B(m, &(via_context->t2cl)) < 0
1320 || SMR_B(m, &(via_context->t2ch)) < 0
1321 || SMR_W(m, &word3) < 0
1322 || SMR_B(m, &byte1) < 0
1323 || SMR_B(m, &(via_context->via[VIA_SR])) < 0
1324 || SMR_B(m, &(via_context->via[VIA_ACR])) < 0
1325 || SMR_B(m, &(via_context->via[VIA_PCR])) < 0
1326 || SMR_B(m, &byte2) < 0
1327 || SMR_B(m, &byte3) < 0
1328 || SMR_B(m, &byte4) < 0
1329 /* SRHBITS */
1330 || SMR_B(m, &byte5) < 0
1331 /* CABSTATE */
1332 || SMR_B(m, &byte6) < 0
1333 || SMR_B(m, &(via_context->ila)) < 0
1334 || SMR_B(m, &(via_context->ilb)) < 0) {
1335 snapshot_module_close(m);
1336 return -1;
1337 }
1338
1339 addr = VIA_DDRA;
1340 byte = via_context->via[VIA_PRA] | ~(via_context->via[VIA_DDRA]);
1341 (via_context->undump_pra)(via_context, byte);
1342 via_context->oldpa = byte;
1343
1344 addr = VIA_DDRB;
1345 byte = via_context->via[VIA_PRB] | ~(via_context->via[VIA_DDRB]);
1346 (via_context->undump_prb)(via_context, byte);
1347 via_context->oldpb = byte;
1348
1349 via_context->tal = word1;
1350 via_context->via[VIA_T1LL] = via_context->tal & 0xff;
1351 via_context->via[VIA_T1LH] = (via_context->tal >> 8) & 0xff;
1352
1353 via_context->tau = rclk + word2 + 2 /* 3 */ + TAUOFFSET;
1354 via_context->tai = rclk + word2 + 1;
1355
1356 via_context->tbu = rclk + word3 + 2 /* 3 */;
1357 via_context->tbi = rclk + word3 + 0;
1358
1359 if (byte1 & 0x80) {
1360 alarm_set(via_context->t1_alarm, via_context->tai);
1361 } else {
1362 via_context->tai = 0;
1363 }
1364 if ((byte1 & 0x40) ||
1365 ((via_context->via[VIA_ACR] & 0x1c) == 0x04) ||
1366 ((via_context->via[VIA_ACR] & 0x1c) == 0x10) ||
1367 ((via_context->via[VIA_ACR] & 0x1c) == 0x14)){
1368 alarm_set(via_context->t2_alarm, via_context->tbi);
1369 } else {
1370 via_context->tbi = 0;
1371 }
1372 /* FIXME: SR alarm */
1373 if ((via_context->via[VIA_ACR] & 0x0c) == 0x08) {
1374 alarm_set(via_context->sr_alarm, rclk + 1);
1375 }
1376
1377 via_context->ifr = byte2;
1378 via_context->ier = byte3;
1379
1380 via_restore_int(via_context, via_context->ifr & via_context->ier & 0x7f);
1381
1382 /* FIXME! */
1383 via_context->pb7 = byte4 ? 1 : 0;
1384 via_context->pb7x = 0;
1385 via_context->pb7o = 0;
1386 via_context->shift_state = byte5;
1387
1388 via_context->ca2_state = byte6 & 0x80;
1389 via_context->cb2_state = byte6 & 0x40;
1390
1391 /* undump_pcr also restores the ca2_state/cb2_state effects if necessary;
1392 i.e. calls set_c*2(c*2_state) if necessary */
1393 addr = VIA_PCR;
1394 byte = via_context->via[addr];
1395 (via_context->undump_pcr)(via_context, byte);
1396
1397 addr = VIA_SR;
1398 byte = via_context->via[addr];
1399 (via_context->store_sr)(via_context, byte);
1400
1401 addr = VIA_ACR;
1402 byte = via_context->via[addr];
1403 (via_context->undump_acr)(via_context, byte);
1404
1405 return snapshot_module_close(m);
1406 }
1407
viacore_dump(via_context_t * via_context)1408 int viacore_dump(via_context_t *via_context)
1409 {
1410 mon_out("Port A: %02x DDR: %02x no HS: %02x\n",
1411 viacore_peek(via_context, 0x01), viacore_peek(via_context, 0x03), viacore_peek(via_context, 0x0f));
1412 mon_out("Port B: %02x DDR: %02x\n", viacore_peek(via_context, 0x00), viacore_peek(via_context, 0x02));
1413 mon_out("Timer 1: %04x Latch: %04x\n", viacore_peek(via_context, 0x04) + (viacore_peek(via_context, 0x05) * 256),
1414 viacore_peek(via_context, 0x06) + (viacore_peek(via_context, 0x07) * 256));
1415 mon_out("Timer 2: %04x\n", viacore_peek(via_context, 0x08) + (viacore_peek(via_context, 0x09) * 256));
1416 mon_out("Aux. control: %02x\n", viacore_peek(via_context, 0x0b));
1417 mon_out("Per. control: %02x\n", viacore_peek(via_context, 0x0c));
1418 mon_out("IRQ flags: %02x\n", viacore_peek(via_context, 0x0d));
1419 mon_out("IRQ enable: %02x\n", viacore_peek(via_context, 0x0e));
1420 mon_out("\nSynchronous Serial I/O Data Buffer: %02x (%s, shifting %s)\n",
1421 viacore_peek(via_context, 0x0a),
1422 ((via_context->via[VIA_ACR] & 0x1c) == 0) ? "disabled" : "enabled",
1423 (via_context->via[VIA_ACR] & 0x10) ? "out" : "in");
1424 return 0;
1425 }
1426