Xemu [doxygen]  hyppo 0a42be3a057156924bc1b626a687bd6e27349c45 @ Sat 19 Mar 02:15:11 CET 2022
cia6526.c
Go to the documentation of this file.
1 /* Part of the Xemu project, please visit: https://github.com/lgblgblgb/xemu
2  Copyright (C)2016-2021 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
3 
4  This is a *VERY* crude CIA 6526 emulation, lacks of TOD, mostly to SDR stuff, timing,
5  and other problems as well ... Hopefully enough for C65 to boot, what is its only reason ...
6 
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
20 
21 /* Based on an even more ugly JavaScript version, also from me
22  * -----------------------------------------------------------
23  * Quick&dirty 6526 CIA emulation
24  * (C)2013 LGB Gabor Lenart
25  * Note: this is not an exact nor complete emulation!
26  * The only goal is to support what Commodore 64/65(?) uses even
27  * implemented incorrectly (not cycle exact, simplified, ignored
28  * conditions, etc).
29  * Some doc:
30  * http://archive.6502.org/datasheets/mos_6526_cia_recreated.pdf
31  * http://www.c64-wiki.com/index.php/CIA
32  */
33 
34 
35 #include "xemu/emutools.h"
36 #include "xemu/cia6526.h"
37 
38 
39 #define ICR_CHECK() \
40  do { \
41  if (cia->ICRmask & cia->ICRdata & 31) { \
42  cia->ICRdata |= 128; \
43  if (!cia->intLevel) { cia->intLevel = 1; cia->setint(1); DEBUG("%s IRQ to 1" NL, cia->name); } \
44  } else { \
45  cia->ICRdata &= 127; \
46  if ( cia->intLevel) { cia->intLevel = 0; cia->setint(0); DEBUG("%s IRQ to 0" NL, cia->name); } \
47  } \
48  } while(0)
49 #define ICR_SET(mask) \
50  do { \
51  cia->ICRdata |= (mask) & 31; \
52  DEBUG("%s ICR set to data $%02X, mask is $%02X" NL, cia->name, cia->ICRdata, cia->ICRmask); \
53  ICR_CHECK(); \
54  } while(0)
55 #define ICR_CLEAR(mask) \
56  do { \
57  cia->ICRdata &= 255 - (mask); \
58  ICR_CHECK(); \
59  } while(0)
60 
61 
62 
63 void cia_reset ( struct Cia6526 *cia )
64 {
65  int a;
66  for (a = 0; a < 16; a++)
67  cia->regWritten[a] = -1;
68  cia->PRA = cia->PRB = cia->DDRA = cia->DDRB = 0;
69  cia->TCA = cia->TCB = 0;
70  cia->CRA = cia->CRB = 0;
71  cia->TLAL = cia->TLAH = cia->TLBL = cia->TLBH = 0;
72  cia->ICRmask = cia->ICRdata = 0;
73  cia->SDR = 0;
74  cia->tod[0] = cia->tod[1] = cia->tod[2] = cia->tod[3] = 0;
75  cia->intLevel = 0;
76  cia->setint(cia->intLevel);
77  DEBUG("%s: RESET" NL, cia->name);
78 }
79 
80 
81 
82 void cia_flag ( struct Cia6526 *cia )
83 {
84  ICR_SET(16);
85 }
86 
87 
88 
89 static void def_outa (Uint8 data) {}
90 static void def_outb (Uint8 data) {}
91 static void def_outsr (Uint8 data) {}
92 static Uint8 def_ina (void ) { return 0xFF; }
93 static Uint8 def_inb (void) { return 0xFF; }
94 static Uint8 def_insr (void) { return 0xFF; }
95 static void def_setint(int level) {}
96 
97 
98 void cia_init (
99  struct Cia6526 *cia, const char *name,
100  void (*outa)(Uint8 data),
101  void (*outb)(Uint8 data),
102  void (*outsr)(Uint8 data),
103  Uint8 (*ina)(void),
104  Uint8 (*inb)(void),
105  Uint8 (*insr)(void),
106  void (*setint)(int level)
107 ) {
108  cia->name = name;
109  cia->outa = outa ? outa : def_outa;
110  cia->outb = outb ? outb : def_outb;
111  cia->outsr = outsr ? outsr : def_outsr;
112  cia->ina = ina ? ina : def_ina;
113  cia->inb = inb ? inb : def_inb;
114  cia->insr = insr ? insr : def_insr;
115  cia->setint = setint ? setint : def_setint;
116  cia_reset(cia);
117 }
118 
119 
120 
121 Uint8 cia_read ( struct Cia6526 *cia, int addr )
122 {
123  Uint8 temp;
124  switch (addr & 0xF) {
125  case 0: // reg#0: port A data
126  // Note: actually - it seems - CIA always reads the pins even if output DDR is set
127  // We leave the implementation details of the emulator targets to think about this ...
128  return cia->ina();
129  case 1: // reg#1: port B data
130  // Note: see the note above, with port A
131  return cia->inb();
132  case 2: // reg#2: DDR A
133  return cia->DDRA;
134  case 3: // reg#3: DDR B
135  return cia->DDRB;
136  case 4: // reg#4: timer A counter low
137  return cia->TCA & 0xFF;
138  case 5: // reg#5: timer A counter high
139  return cia->TCA >> 8;
140  case 6: // reg#6: timer B counter low
141  return cia->TCB & 0xFF;
142  case 7: // reg#7: timer B counter high
143  return cia->TCB >> 8;
144  case 8: // reg#8: TOD 10ths
145  return cia->tod[0];
146  case 9: // reg#9: TOD sec
147  return cia->tod[1];
148  case 10: // reg#A: TOD min
149  return cia->tod[2];
150  case 11: // reg#B: TOD hours + PM
151  return cia->tod[3];
152  case 12: // reg#C: SP
153  return cia->SDR;
154  case 13: // reg#D: ICR data
155  temp = cia->ICRdata;
156  cia->ICRdata = 0;
157  ICR_CHECK();
158  return temp;
159  case 14: // reg#E: CRA
160  return cia->CRA;
161  case 15: // reg#F: CRB
162  return cia->CRB;
163  }
164  return 0; // to make GCC happy :-/
165 }
166 
167 
168 
169 void cia_write ( struct Cia6526 *cia, int addr, Uint8 data )
170 {
171  switch (addr & 0xF) {
172  case 0: // reg#0: port A
173  // Note: we leave the details for the emulator targets to handle
174  // the situation what is really output in relation of the DDR register too ...
175  cia->PRA = data;
176  cia->outa(data);
177  break;
178  case 1: // reg#1: port B
179  // Note: see the note above with Port A
180  cia->PRB = data;
181  cia->outb(data);
182  break;
183  case 2: // reg#2: DDR A
184  // Note: we "notify" the emulation target that DDR changed with re-output the value
185  // Note: see the notes with registers 0, 1 on output/DDR related thing
186  if (cia->DDRA != data) {
187  cia->DDRA = data;
188  cia->outa(cia->PRA);
189  }
190  break;
191  case 3: // reg#3: DDR B
192  // Note: see the note above with DDR of port A
193  if (cia->DDRB != data) {
194  cia->DDRB = data;
195  cia->outb(cia->PRB);
196  }
197  break;
198  case 4: // reg#4: timer A latch low
199  cia->TLAL = data;
200  break;
201  case 5: // reg#5: timer A latch high
202  cia->TLAH = data;
203  if (!(cia->CRA & 1) || (cia->CRA & 16))
204  cia->TCA = cia->TLAL | (cia->TLAH << 8);
205  break;
206  case 6: // reg#6: timer B latch low
207  cia->TLBL = data;
208  break;
209  case 7: // reg#7: timer B latch high
210  cia->TLBH = data;
211  if (!(cia->CRB & 1) || (cia->CRB & 16))
212  cia->TCB = cia->TLBL | (cia->TLBH << 8);
213  break;
214  case 8: // reg#8: TOD 10ths
215  if (cia->CRB & 128)
216  cia->todAlarm[0] = data & 15;
217  else
218  cia->tod[0] = data & 15;
219  break;
220  case 9: // reg#9: TOD sec
221  if (cia->CRB & 128)
222  cia->todAlarm[1] = data & 127;
223  else
224  cia->tod[1] = data & 127;
225  break;
226  case 10: // reg#A: TOD min
227  if (cia->CRB & 128)
228  cia->todAlarm[2] = data & 127;
229  else
230  cia->tod[2] = data & 127;
231  break;
232  case 11: // reg#B: TOD hours + PM
233  if (cia->CRB & 128)
234  cia->todAlarm[3] = data;
235  else
236  cia->tod[3] = data;
237  break;
238  case 12: // reg#C: SP
239  cia->SDR = data;
240  if (cia->CRA & 64)
241  cia->outsr(data);
242  break;
243  case 13: // reg#D: ICR mask
244  if (data & 128)
245  cia->ICRmask |= data & 31;
246  else
247  cia->ICRmask &= 255 - (data & 31);
248  DEBUG("%s set ICRmask to %02X with byte of %02X" NL, cia->name, cia->ICRmask, data);
249  ICR_CHECK();
250  break;
251  case 14: // reg#E: CRA
252  cia->CRA = data;
253  if (data & 16) { // force load?
254  cia->CRA &= 255 - 16; // strobe bit, force to be on zero
255  cia->TCA = cia->TLAL | (cia->TLAH << 8);
256  }
257  break;
258  case 15: // reg#F: CRB
259  cia->CRB = data;
260  if (data & 16) { // force load?
261  cia->CRB &= 255 - 16; // storbe bit, force to be on zero
262  cia->TCB = cia->TLBL | (cia->TLBH << 8);
263  }
264  break;
265  }
266  cia->regWritten[addr] = data;
267 }
268 
269 
270 void cia_ugly_tod_updater ( struct Cia6526 *cia, const struct tm *t, Uint8 sec10, int hour_offset )
271 {
272  // Ugly CIA trick to maintain realtime TOD in CIAs :)
273  // FIXME: of course, that's simple crazy, not in sync with emu, no "stopping" clock on read, no setting etc ...
274  cia->tod[0] = sec10;
275  cia->tod[1] = XEMU_BYTE_TO_BCD(t->tm_sec);
276  cia->tod[2] = XEMU_BYTE_TO_BCD(t->tm_min);
277  cia->tod[3] = xemu_hour_to_bcd12h(t->tm_hour, hour_offset);
278 }
279 
280 
281 void cia_tick ( struct Cia6526 *cia, int ticks )
282 {
283  int timer_a_underflow = 0; // used to emulate linked timer mode for a 32 bit counter
284  /* Timer A */
285  if (cia->CRA & 1) {
286  cia->TCA -= ticks;
287  if (cia->TCA <= 0) {
288  timer_a_underflow = 1;
289  DEBUG("%s timer-A expired!" NL, cia->name);
290  ICR_SET(1);
291  cia->TCA += cia->TLAL | (cia->TLAH << 8);
292  if (cia->TCA < 0)
293  cia->TCA = 0;
294  if (cia->CRA & 8)
295  cia->CRA &= 254; // one shot mode: reset bit 1 (timer stop)
296  }
297  }
298  /* Timer B */
299  if (cia->CRB & 1) {
300  // this is kinda bad, we assume "CNT" does not affect anything :-/
301  if ((cia->CRB & 64)) { // linked timers mode: timer-B counts of underflows of timer-A
302  if (timer_a_underflow)
303  cia->TCB--;
304  else
305  return;
306  } else { // independent timer-B: works the same as timer-A
307  cia->TCB -= ticks;
308  }
309  if (cia->TCB <= 0) {
310  DEBUG("%s timer-B expired!" NL, cia->name);
311  ICR_SET(2);
312  cia->TCB += cia->TLBL | (cia->TLBH << 8);
313  if (cia->TCB < 0)
314  cia->TCB = 0;
315  if (cia->CRB & 8)
316  cia->CRB &= 254; // one shot mode: reset bit 1 (timer stop)
317  }
318  }
319  /* TOD stuffs are ignored ;-/ */
320 }
321 
322 
323 void cia_dump_state ( struct Cia6526 *cia )
324 {
325  int a;
326  DEBUG("%s registers written:", cia->name);
327  for (a = 0; a < 16; a++)
328  if (cia->regWritten[a] >= 0)
329  DEBUG(" %02X", cia->regWritten[a]);
330  else
331  DEBUG(" ??");
332  DEBUG(NL "%s timer-A=%d time-B=%d" NL, cia->name, cia->TCA, cia->TCB);
333 }
334 
335 
336 /* --- SNAPSHOT RELATED --- */
337 
338 
339 #ifdef XEMU_SNAPSHOT_SUPPORT
340 
341 #include <string.h>
342 
343 #define SNAPSHOT_CIA_BLOCK_VERSION 0
344 #define SNAPSHOT_CIA_BLOCK_SIZE 256
345 
346 int cia_snapshot_load_state ( const struct xemu_snapshot_definition_st *def, struct xemu_snapshot_block_st *block )
347 {
348  Uint8 buffer[SNAPSHOT_CIA_BLOCK_SIZE];
349  struct Cia6526 *cia = (struct Cia6526 *)def->user_data;
350  int a;
351  if (block->block_version != SNAPSHOT_CIA_BLOCK_VERSION || block->sub_counter || block->sub_size != sizeof buffer)
352  RETURN_XSNAPERR_USER("Bad CIA block syntax");
353  a = xemusnap_read_file(buffer, sizeof buffer);
354  if (a) return a;
355  /* loading state ... */
356  for (a = 0; a < 16; a++) {
357  cia_write(cia, a, (cia->regWritten[a] = buffer[a + 16] ? -1 : buffer[a]));
358  }
359  cia->TCA = (int)P_AS_BE32(buffer + 128);
360  cia->TCB = (int)P_AS_BE32(buffer + 132);
361  cia->intLevel = (int)P_AS_BE32(buffer + 136);
362  cia->CRA = buffer[140];
363  cia->CRB = buffer[141];
364  cia->ICRdata = buffer[142];
365  cia->ICRmask = buffer[143];
366  ICR_CHECK();
367  cia->setint(cia->intLevel); // just to be sure ...
368  cia->outa(cia->PRA);
369  cia->outb(cia->PRB);
370  return 0;
371 }
372 
373 
374 int cia_snapshot_save_state ( const struct xemu_snapshot_definition_st *def )
375 {
376  Uint8 buffer[SNAPSHOT_CIA_BLOCK_SIZE];
377  struct Cia6526 *cia = (struct Cia6526 *)def->user_data;
378  int a = xemusnap_write_block_header(def->idstr, SNAPSHOT_CIA_BLOCK_VERSION);
379  if (a) return a;
380  memset(buffer, 0xFF, sizeof buffer);
381  /* saving state ... */
382  for (a = 0; a < 16; a++) {
383  buffer[a] = cia->regWritten[a] & 0xFF;
384  buffer[a + 16] = cia->regWritten[a] == -1 ? 0xFF : 0x00;
385  }
386  U32_AS_BE(buffer + 128, (Uint32)cia->TCA);
387  U32_AS_BE(buffer + 132, (Uint32)cia->TCB);
388  U32_AS_BE(buffer + 136, (Uint32)cia->intLevel);
389  buffer[140] = cia->CRA;
390  buffer[141] = cia->CRB;
391  buffer[142] = cia->ICRdata;
392  buffer[143] = cia->ICRmask;
393  return xemusnap_write_sub_block(buffer, sizeof buffer);
394 }
395 
396 #endif
Cia6526::regWritten
int regWritten[16]
Definition: cia6526.h:55
cia6526.h
Cia6526::inb
Uint8(* inb)(void)
Definition: cia6526.h:42
cia_ugly_tod_updater
void cia_ugly_tod_updater(struct Cia6526 *cia, const struct tm *t, Uint8 sec10, int hour_offset)
Definition: cia6526.c:270
cia_read
Uint8 cia_read(struct Cia6526 *cia, int addr)
Definition: cia6526.c:121
emutools.h
Cia6526::TLBH
Uint8 TLBH
Definition: cia6526.h:49
Cia6526::setint
void(* setint)(int level)
Definition: cia6526.h:44
Cia6526::DDRB
Uint8 DDRB
Definition: cia6526.h:46
ICR_SET
#define ICR_SET(mask)
Definition: cia6526.c:49
Cia6526::ICRmask
Uint8 ICRmask
Definition: cia6526.h:51
Cia6526::todAlarm
Uint8 todAlarm[4]
Definition: cia6526.h:54
Cia6526::TCB
int TCB
Definition: cia6526.h:47
cia_reset
void cia_reset(struct Cia6526 *cia)
Definition: cia6526.c:63
addr
int addr
Definition: dma65.c:81
Cia6526::SDR
Uint8 SDR
Definition: cia6526.h:52
m65-memcontent-generator.data
data
Definition: m65-memcontent-generator.py:119
Uint32
uint32_t Uint32
Definition: fat32.c:49
cia_tick
void cia_tick(struct Cia6526 *cia, int ticks)
Definition: cia6526.c:281
Uint8
uint8_t Uint8
Definition: fat32.c:51
Cia6526::DDRA
Uint8 DDRA
Definition: cia6526.h:46
Cia6526
Definition: cia6526.h:37
block
Uint32 block
Definition: fat32.c:156
Cia6526::insr
Uint8(* insr)(void)
Definition: cia6526.h:43
Cia6526::ICRdata
Uint8 ICRdata
Definition: cia6526.h:51
Cia6526::PRA
Uint8 PRA
Definition: cia6526.h:46
Cia6526::TLAH
Uint8 TLAH
Definition: cia6526.h:49
Cia6526::intLevel
int intLevel
Definition: cia6526.h:48
Cia6526::name
const char * name
Definition: cia6526.h:45
Cia6526::PRB
Uint8 PRB
Definition: cia6526.h:46
Cia6526::CRB
Uint8 CRB
Definition: cia6526.h:50
Cia6526::TLBL
Uint8 TLBL
Definition: cia6526.h:49
NL
#define NL
Definition: fat32.c:37
Cia6526::ina
Uint8(* ina)(void)
Definition: cia6526.h:41
cia_init
void cia_init(struct Cia6526 *cia, const char *name, void(*outa)(Uint8 data), void(*outb)(Uint8 data), void(*outsr)(Uint8 data), Uint8(*ina)(void), Uint8(*inb)(void), Uint8(*insr)(void), void(*setint)(int level))
Definition: cia6526.c:98
ICR_CHECK
#define ICR_CHECK()
Definition: cia6526.c:39
Cia6526::TCA
int TCA
Definition: cia6526.h:47
cia_dump_state
void cia_dump_state(struct Cia6526 *cia)
Definition: cia6526.c:323
Cia6526::outa
void(* outa)(Uint8 data)
Definition: cia6526.h:38
Cia6526::TLAL
Uint8 TLAL
Definition: cia6526.h:49
xemu_hour_to_bcd12h
Uint8 xemu_hour_to_bcd12h(Uint8 hours, int hour_offset)
Definition: emutools.c:211
Cia6526::tod
Uint8 tod[4]
Definition: cia6526.h:53
Cia6526::outb
void(* outb)(Uint8 data)
Definition: cia6526.h:39
name
const char * name
Definition: joystick.c:46
DEBUG
#define DEBUG(...)
Definition: emutools_basicdefs.h:167
Cia6526::CRA
Uint8 CRA
Definition: cia6526.h:50
Cia6526::outsr
void(* outsr)(Uint8 data)
Definition: cia6526.h:40
cia_flag
void cia_flag(struct Cia6526 *cia)
Definition: cia6526.c:82
cia_write
void cia_write(struct Cia6526 *cia, int addr, Uint8 data)
Definition: cia6526.c:169