fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 564 lines 10 kB view raw
1/***************************************************************************** 2 * pce * 3 *****************************************************************************/ 4 5/***************************************************************************** 6 * File name: src/arch/macplus/rtc.c * 7 * Created: 2007-11-16 by Hampa Hug <hampa@hampa.ch> * 8 * Copyright: (C) 2007-2019 Hampa Hug <hampa@hampa.ch> * 9 *****************************************************************************/ 10 11/***************************************************************************** 12 * This program is free software. You can redistribute it and / or modify it * 13 * under the terms of the GNU General Public License version 2 as published * 14 * by the Free Software Foundation. * 15 * * 16 * This program is distributed in the hope that it will be useful, but * 17 * WITHOUT ANY WARRANTY, without even the implied warranty of * 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * 19 * Public License for more details. * 20 *****************************************************************************/ 21 22 23#include "main.h" 24#include "rtc.h" 25 26#include <stdio.h> 27#include <time.h> 28 29 30static 31unsigned long mac_rtc_hms_to_time (unsigned h, unsigned m, unsigned s) 32{ 33 if ((h > 23) || (m > 59) || (s > 59)) { 34 return (0); 35 } 36 37 return (60UL * (60UL * h + m) + s); 38} 39 40static 41unsigned long mac_rtc_ymd_to_time (unsigned y, unsigned m, unsigned d) 42{ 43 unsigned long t; 44 unsigned i; 45 unsigned *month; 46 47 static unsigned months[2][12] = { 48 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 49 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 50 }; 51 52 if ((y < 1904U) || (m > 11)) { 53 return (0); 54 } 55 56 y -= 1904U; 57 58 t = (y / 4UL) * (4UL * 365UL + 1UL); 59 y = y % 4U; 60 61 t += 365UL * y + (y > 0); 62 63 month = (y == 0) ? months[1] : months[0]; 64 65 for (i = 0; i < m; i++) { 66 t += month[i]; 67 } 68 69 if (d >= month[m]) { 70 return (0); 71 } 72 73 t += d; 74 75 t *= (24UL * 60UL * 60UL); 76 77 return (t); 78} 79 80static 81void mac_rtc_get_uint (const char **str, unsigned *val) 82{ 83 const char *s; 84 unsigned v; 85 86 s = *str; 87 v = 0; 88 89 while ((*s < '0') || (*s > '9')) { 90 if (*s == 0) { 91 *str = s; 92 *val = 0; 93 return; 94 } 95 96 s += 1; 97 } 98 99 while ((*s >= '0') && (*s <= '9')) { 100 v = 10 * v + (*s - '0'); 101 s += 1; 102 } 103 104 *str = s; 105 *val = v; 106} 107 108unsigned long mac_rtc_time_from_string (const char *str) 109{ 110 unsigned i; 111 unsigned val[6]; 112 unsigned long ret; 113 114 for (i = 0; i < 6; i++) { 115 mac_rtc_get_uint (&str, &val[i]); 116 } 117 118 if (val[1] > 0) { 119 val[1] -= 1; 120 } 121 122 if (val[2] > 0) { 123 val[2] -= 1; 124 } 125 126 ret = mac_rtc_ymd_to_time (val[0], val[1], val[2]); 127 ret += mac_rtc_hms_to_time (val[3], val[4], val[5]); 128 129 return (ret); 130} 131 132void mac_rtc_init (mac_rtc_t *rtc) 133{ 134 rtc->set_data_ext = NULL; 135 rtc->set_data = NULL; 136 rtc->set_data_val = 0; 137 138 rtc->set_osi_ext = NULL; 139 rtc->set_osi = NULL; 140 rtc->set_osi_val = 0; 141 142 rtc->data_out = 0; 143 rtc->state = 0; 144 rtc->bitcnt = 0; 145 rtc->sigval = 0; 146 147 rtc->realtime = 0; 148 rtc->gmtoff = 0; 149 rtc->clkcnt = 0; 150 151 rtc->reg_wp = 0; 152 rtc->reg_test = 0; 153 154 rtc->clock = 0; 155 rtc->rtime = 0; 156 157 mac_rtc_set_defaults (rtc); 158} 159 160void mac_rtc_free (mac_rtc_t *rtc) 161{ 162} 163 164void mac_rtc_set_data_fct (mac_rtc_t *rtc, void *ext, void *fct) 165{ 166 rtc->set_data_ext = ext; 167 rtc->set_data = fct; 168} 169 170void mac_rtc_set_osi_fct (mac_rtc_t *rtc, void *ext, void *fct) 171{ 172 rtc->set_osi_ext = ext; 173 rtc->set_osi = fct; 174} 175 176void mac_rtc_set_realtime (mac_rtc_t *rtc, int realtime) 177{ 178 rtc->realtime = (realtime != 0); 179} 180 181void mac_rtc_set_defaults (mac_rtc_t *rtc) 182{ 183 unsigned i; 184 185 for (i = 0; i < 256; i++) { 186 rtc->data[i] = 0; 187 } 188} 189 190int mac_rtc_load_file (mac_rtc_t *rtc, const char *fname) 191{ 192 FILE *fp; 193 194 fp = fopen (fname, "rb"); 195 196 if (fp == NULL) { 197 return (1); 198 } 199 200 if (fread (rtc->data, 1, 256, fp) != 256) { 201 fclose (fp); 202 return (1); 203 } 204 205 fclose (fp); 206 207 rtc->reg_wp = 0x80; 208 rtc->reg_test = 0x00; 209 210 return (0); 211} 212 213int mac_rtc_save_file (mac_rtc_t *rtc, const char *fname) 214{ 215 FILE *fp; 216 217 fp = fopen (fname, "wb"); 218 219 if (fp == NULL) { 220 return (1); 221 } 222 223 if (fwrite (rtc->data, 1, 256, fp) != 256) { 224 fclose (fp); 225 return (1); 226 } 227 228 fclose (fp); 229 230 return (0); 231} 232 233static 234unsigned long mac_rtc_get_current_time (mac_rtc_t *rtc) 235{ 236 time_t ut; 237 unsigned long mt; 238 239 ut = time (NULL); 240 241 mt = (unsigned long) ut; 242 243 mt += rtc->gmtoff; 244 245 /* 1970-01-01 00:00:00 */ 246 mt += 2082844800; 247 248 return (mt); 249} 250 251static 252unsigned long mac_rtc_get_timezone (mac_rtc_t *rtc) 253{ 254 unsigned long tz; 255 256 tz = rtc->data[0xed]; 257 tz = (tz << 8) | rtc->data[0xee]; 258 tz = (tz << 8) | rtc->data[0xef]; 259 260 if (tz & 0x800000) { 261 tz |= 0xff000000; 262 } 263 264 return (tz); 265} 266 267void mac_rtc_set_time (mac_rtc_t *rtc, unsigned long time, int utc) 268{ 269 rtc->rtime = mac_rtc_get_current_time (rtc); 270 rtc->clock = time; 271 272 if (utc) { 273 rtc->clock += mac_rtc_get_timezone (rtc); 274 } 275} 276 277void mac_rtc_set_time_now (mac_rtc_t *rtc) 278{ 279 rtc->rtime = mac_rtc_get_current_time (rtc); 280 rtc->clock = rtc->rtime; 281 rtc->clock += mac_rtc_get_timezone (rtc); 282} 283 284void mac_rtc_set_time_str (mac_rtc_t *rtc, const char *str) 285{ 286 unsigned long time; 287 288 if (str == NULL) { 289 mac_rtc_set_time_now (rtc); 290 } 291 else { 292 time = mac_rtc_time_from_string (str); 293 294 mac_rtc_set_time (rtc, time, 0); 295 } 296} 297 298void mac_rtc_set_time_gmtoff (mac_rtc_t *rtc) 299{ 300 struct tm *tm; 301 time_t ut; 302 303 ut = time (NULL); 304 tm = localtime (&ut); 305 rtc->gmtoff = tm->tm_gmtoff; 306} 307 308static 309void mac_rtc_set_data (mac_rtc_t *rtc, unsigned char val) 310{ 311 /* data must always be set because it switches from input to output */ 312 313 rtc->set_data_val = (val != 0); 314 315 if (rtc->set_data != NULL) { 316 rtc->set_data (rtc->set_data_ext, rtc->set_data_val); 317 } 318} 319 320static 321void mac_rtc_set_osi (mac_rtc_t *rtc, unsigned char val) 322{ 323 val = (val != 0); 324 325 if (rtc->set_osi_val == val) { 326 return; 327 } 328 329 rtc->set_osi_val = val; 330 331 if (rtc->set_osi != NULL) { 332 rtc->set_osi (rtc->set_osi_ext, val); 333 } 334} 335 336static 337void mac_rtc_cmd1_read (mac_rtc_t *rtc) 338{ 339 unsigned char reg; 340 341 reg = (rtc->cmd1 >> 2) & 0x1f; 342 343 if ((rtc->cmd1 & 0xe3) == 0x81) { 344 rtc->shift = (rtc->clock >> (8 * (reg & 3))) & 0xff; 345 } 346 else if ((rtc->cmd1 & 0xf3) == 0xa1) { 347 rtc->shift = rtc->data[8 + ((rtc->cmd1 >> 2) & 3)]; 348 } 349 else if ((rtc->cmd1 & 0xc3) == 0xc1) { 350 rtc->shift = rtc->data[16 + ((rtc->cmd1 >> 2) & 15)]; 351 } 352 else { 353 rtc->shift = 0x00; 354 } 355 356#ifdef DEBUG_RTC 357 mac_log_deb ("rtc: read command 1: %02X (%02X)\n", 358 rtc->cmd1, rtc->shift 359 ); 360#endif 361} 362 363static 364void mac_rtc_cmd1_write (mac_rtc_t *rtc) 365{ 366#ifdef DEBUG_RTC 367 mac_log_deb ("rtc: write command 1: %02X (%02X)\n", 368 rtc->cmd1, rtc->shift 369 ); 370#endif 371 372 if (rtc->cmd1 == 0x35) { 373 rtc->reg_wp = rtc->shift & 0x80; 374 return; 375 } 376 377 if (rtc->reg_wp & 0x80) { 378 return; 379 } 380 381 if ((rtc->cmd1 & 0xe3) == 0x01) { 382 unsigned bit; 383 unsigned long val; 384 385 bit = 8 * ((rtc->cmd1 >> 2) & 3); 386 val = rtc->shift & 0xff; 387 388 rtc->clock &= ~(0x000000ffUL << bit); 389 rtc->clock |= val << bit; 390 } 391 else if ((rtc->cmd1 & 0xf3) == 0x21) { 392 rtc->data[8 + ((rtc->cmd1 >> 2) & 3)] = rtc->shift; 393 } 394 else if (rtc->cmd1 == 0x31) { 395 rtc->reg_test = rtc->shift; 396 } 397 else if ((rtc->cmd1 & 0xc3) == 0x41) { 398 rtc->data[16 + ((rtc->cmd1 >> 2) & 15)] = rtc->shift; 399 } 400} 401 402static 403void mac_rtc_cmd2_read (mac_rtc_t *rtc) 404{ 405 unsigned addr; 406 407 addr = ((rtc->cmd1 & 7) << 5) | ((rtc->cmd2 >> 2) & 0x1f); 408 409 if (addr < 256) { 410 rtc->shift = rtc->data[addr]; 411 } 412 else { 413 rtc->shift = 0; 414 } 415 416#ifdef DEBUG_RTC 417 mac_log_deb ("rtc: read command 2: %02X %02X S=%X A=%02X (%02X)\n", 418 rtc->cmd1, rtc->cmd2, rtc->cmd1 & 7, (rtc->cmd2 >> 2) & 0x1f, 419 rtc->shift 420 ); 421#endif 422} 423 424static 425void mac_rtc_cmd2_write (mac_rtc_t *rtc) 426{ 427 unsigned addr; 428 429#ifdef DEBUG_RTC 430 mac_log_deb ("rtc: write command 2: %02X %02X S=%X A=%02X (%02X)\n", 431 rtc->cmd1, rtc->cmd2, rtc->cmd1 & 7, (rtc->cmd2 >> 2) & 0x1f, 432 rtc->shift 433 ); 434#endif 435 436 if (rtc->reg_wp & 0x80) { 437 return; 438 } 439 440 addr = ((rtc->cmd1 & 7) << 5) | ((rtc->cmd2 >> 2) & 0x1f); 441 442 if (addr < 256) { 443 rtc->data[addr] = rtc->shift; 444 } 445} 446 447void mac_rtc_set_uint8 (mac_rtc_t *rtc, unsigned char val) 448{ 449 unsigned char dif; 450 451 dif = rtc->sigval ^ val; 452 rtc->sigval = val; 453 454 if (val & 0x04) { 455 /* serial disabled */ 456 rtc->state = 0; 457 rtc->data_out = 0; 458 rtc->bitcnt = 0; 459 return; 460 } 461 462 if ((dif & ~val & 0x02) == 0) { 463 return; 464 } 465 466 /* clock went low */ 467 468 if (rtc->data_out) { 469 /* send a byte to the cpu */ 470 mac_rtc_set_data (rtc, rtc->shift & 0x80); 471 472 rtc->shift = (rtc->shift << 1) | ((rtc->shift >> 7) & 0x01); 473 474 rtc->bitcnt += 1; 475 476 if (rtc->bitcnt >= 8) { 477 rtc->bitcnt = 0; 478 rtc->data_out = 0; 479 rtc->state = 0; 480 } 481 } 482 else { 483 /* receive a byte from the cpu */ 484 rtc->shift = (rtc->shift << 1) | (val & 0x01); 485 486 rtc->bitcnt += 1; 487 488 if (rtc->bitcnt >= 8) { 489 if (rtc->state == 0) { 490 /* cmd1 */ 491 rtc->cmd1 = rtc->shift; 492 493 if ((rtc->cmd1 & 0x78) == 0x38) { 494 /* extended command */ 495 rtc->state = 2; 496 } 497 else if (rtc->cmd1 & 0x80) { 498 /* read command */ 499 mac_rtc_cmd1_read (rtc); 500 rtc->state = 0; 501 rtc->data_out = 1; 502 } 503 else { 504 rtc->state = 1; 505 } 506 } 507 else if (rtc->state == 1) { 508 /* data byte for cmd1 */ 509 mac_rtc_cmd1_write (rtc); 510 rtc->state = 0; 511 } 512 else if (rtc->state == 2) { 513 /* cmd2 */ 514 rtc->cmd2 = rtc->shift; 515 if (rtc->cmd1 & 0x80) { 516 mac_rtc_cmd2_read (rtc); 517 rtc->state = 0; 518 rtc->data_out = 1; 519 } 520 else { 521 rtc->state = 3; 522 } 523 } 524 else if (rtc->state == 3) { 525 /* data byte for cmd2 */ 526 mac_rtc_cmd2_write (rtc); 527 rtc->state = 0; 528 } 529 530 rtc->bitcnt = 0; 531 } 532 } 533} 534 535void mac_rtc_clock (mac_rtc_t *rtc, unsigned long n) 536{ 537 unsigned long clock, rtime; 538 539 clock = rtc->clock; 540 541 if (rtc->realtime) { 542 rtime = rtc->rtime; 543 rtc->rtime = mac_rtc_get_current_time (rtc); 544 rtc->clock += rtc->rtime - rtime; 545 } 546 else { 547 rtc->clkcnt += n; 548 549 if (rtc->clkcnt > MAC_CPU_CLOCK) { 550 rtc->clkcnt -= MAC_CPU_CLOCK; 551 rtc->clock += 1; 552 } 553 } 554 555 rtc->clock &= 0xffffffff; 556 557 if (rtc->clock != clock) { 558#ifdef DEBUG_RTC 559 mac_log_deb ("rtc: osi (%lu)\n", rtc->clkcnt); 560#endif 561 mac_rtc_set_osi (rtc, 1); 562 mac_rtc_set_osi (rtc, 0); 563 } 564}