this repo has no description
at main 518 lines 12 kB view raw
1/* 2 RTCEMDEV.c 3 4 Copyright (C) 2003 Philip Cummins, Paul C. Pratt 5 6 You can redistribute this file and/or modify it under the terms 7 of version 2 of the GNU General Public License as published by 8 the Free Software Foundation. You should have received a copy 9 of the license along with this file; see the file COPYING. 10 11 This file is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 license for more details. 15*/ 16 17/* 18 Real Time Clock EMulated DEVice 19 20 Emulates the RTC found in the Mac Plus. 21 22 This code adapted from "RTC.c" in vMac by Philip Cummins. 23*/ 24 25#include "PICOMMON.h" 26 27#if EmRTC 28 29/* define _RTC_Debug */ 30#ifdef _RTC_Debug 31#include <stdio.h> 32#endif 33 34#include "RTCEMDEV.h" 35 36#define HaveXPRAM (CurEmMd >= kEmMd_Plus) 37 38/* 39 ReportAbnormalID unused 0x0805 - 0x08FF 40*/ 41 42#if HaveXPRAM 43#define PARAMRAMSize 256 44#else 45#define PARAMRAMSize 20 46#endif 47 48#if HaveXPRAM 49#define Group1Base 0x10 50#define Group2Base 0x08 51#else 52#define Group1Base 0x00 53#define Group2Base 0x10 54#endif 55 56typedef struct 57{ 58 /* RTC VIA Flags */ 59 ui3b WrProtect; 60 ui3b DataOut; 61 ui3b DataNextOut; 62 63 /* RTC Data */ 64 ui3b ShiftData; 65 ui3b Counter; 66 ui3b Mode; 67 ui3b SavedCmd; 68#if HaveXPRAM 69 ui3b Sector; 70#endif 71 72 /* RTC Registers */ 73 ui3b Seconds_1[4]; 74 ui3b PARAMRAM[PARAMRAMSize]; 75} RTC_Ty; 76 77LOCALVAR RTC_Ty RTC; 78 79/* RTC Functions */ 80 81LOCALVAR ui5b LastRealDate; 82 83#ifndef RTCinitPRAM 84#define RTCinitPRAM 1 85#endif 86 87#ifndef TrackSpeed /* in 0..4 */ 88#define TrackSpeed 0 89#endif 90 91#ifndef AlarmOn /* in 0..1 */ 92#define AlarmOn 0 93#endif 94 95#ifndef DiskCacheSz /* in 1,2,3,4,6,8,12 */ 96/* actual cache size is DiskCacheSz * 32k */ 97#if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) 98#define DiskCacheSz 1 99#else 100#define DiskCacheSz 4 101#endif 102#endif 103 104#ifndef StartUpDisk /* in 0..1 */ 105#define StartUpDisk 0 106#endif 107 108#ifndef DiskCacheOn /* in 0..1 */ 109#define DiskCacheOn 0 110#endif 111 112#ifndef MouseScalingOn /* in 0..1 */ 113#define MouseScalingOn 0 114#endif 115 116#define prb_fontHi 0 117#define prb_fontLo 2 118#define prb_kbdPrintHi (AutoKeyRate + (AutoKeyThresh << 4)) 119#define prb_kbdPrintLo 0 120#define prb_volClickHi (SpeakerVol + (TrackSpeed << 3) + (AlarmOn << 7)) 121#define prb_volClickLo (CaretBlinkTime + (DoubleClickTime << 4)) 122#define prb_miscHi DiskCacheSz 123#define prb_miscLo \ 124 ((MenuBlink << 2) + (StartUpDisk << 4) \ 125 + (DiskCacheOn << 5) + (MouseScalingOn << 6)) 126 127#if dbglog_HAVE && 0 128EXPORTPROC DumpRTC(void); 129 130GLOBALPROC DumpRTC(void) 131{ 132 int Counter; 133 134 dbglog_writeln("RTC Parameter RAM"); 135 for (Counter = 0; Counter < PARAMRAMSize; Counter++) { 136 dbglog_writeNum(Counter); 137 dbglog_writeCStr(", "); 138 dbglog_writeHex(RTC.PARAMRAM[Counter]); 139 dbglog_writeReturn(); 140 } 141} 142#endif 143 144GLOBALFUNC blnr RTC_Init(void) 145{ 146 int Counter; 147 ui5b secs; 148 149 RTC.Mode = RTC.ShiftData = RTC.Counter = 0; 150 RTC.DataOut = RTC.DataNextOut = 0; 151 RTC.WrProtect = falseblnr; 152 153 secs = CurMacDateInSeconds; 154 LastRealDate = secs; 155 156 RTC.Seconds_1[0] = secs & 0xFF; 157 RTC.Seconds_1[1] = (secs & 0xFF00) >> 8; 158 RTC.Seconds_1[2] = (secs & 0xFF0000) >> 16; 159 RTC.Seconds_1[3] = (secs & 0xFF000000) >> 24; 160 161 for (Counter = 0; Counter < PARAMRAMSize; Counter++) { 162 RTC.PARAMRAM[Counter] = 0; 163 } 164 165#if RTCinitPRAM 166 RTC.PARAMRAM[0 + Group1Base] = 168; /* valid */ 167 168#if EmLocalTalk 169 RTC.PARAMRAM[2 + Group1Base] = LT_NodeHint; 170 /* set to constant instead for testing collisions */ 171#else 172#if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) 173 RTC.PARAMRAM[2 + Group1Base] = 1; 174 /* node id hint for printer port (AppleTalk) */ 175#endif 176#endif 177 178#if EmLocalTalk 179 RTC.PARAMRAM[3 + Group1Base] = 0x21; 180#else 181 RTC.PARAMRAM[3 + Group1Base] = 0x22; 182#endif 183 /* 184 serial ports config bits: 4-7 A, 0-3 B 185 useFree 0 Use undefined 186 useATalk 1 AppleTalk 187 useAsync 2 Async 188 useExtClk 3 externally clocked 189 */ 190 191 RTC.PARAMRAM[4 + Group1Base] = 204; /* portA, high */ 192 RTC.PARAMRAM[5 + Group1Base] = 10; /* portA, low */ 193 RTC.PARAMRAM[6 + Group1Base] = 204; /* portB, high */ 194 RTC.PARAMRAM[7 + Group1Base] = 10; /* portB, low */ 195 RTC.PARAMRAM[13 + Group1Base] = prb_fontLo; 196 RTC.PARAMRAM[14 + Group1Base] = prb_kbdPrintHi; 197#if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) || EmLocalTalk 198 RTC.PARAMRAM[15 + Group1Base] = 1; 199 /* 200 printer, if any, connected to modem port 201 because printer port used for appletalk. 202 */ 203#endif 204 205#if prb_volClickHi != 0 206 RTC.PARAMRAM[0 + Group2Base] = prb_volClickHi; 207#endif 208 RTC.PARAMRAM[1 + Group2Base] = prb_volClickLo; 209 RTC.PARAMRAM[2 + Group2Base] = prb_miscHi; 210 RTC.PARAMRAM[3 + Group2Base] = prb_miscLo 211#if 0 != vMacScreenDepth 212 | 0x80 213#endif 214 ; 215 216#if HaveXPRAM /* extended parameter ram initialized */ 217#if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) 218 RTC.PARAMRAM[12] = 0x4e; 219 RTC.PARAMRAM[13] = 0x75; 220 RTC.PARAMRAM[14] = 0x4d; 221 RTC.PARAMRAM[15] = 0x63; 222#else 223 RTC.PARAMRAM[12] = 0x42; 224 RTC.PARAMRAM[13] = 0x75; 225 RTC.PARAMRAM[14] = 0x67; 226 RTC.PARAMRAM[15] = 0x73; 227#endif 228#endif 229 230#if ((CurEmMd >= kEmMd_SE) && (CurEmMd <= kEmMd_Classic)) \ 231 || (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) 232 233 RTC.PARAMRAM[0x01] = 0x80; 234 RTC.PARAMRAM[0x02] = 0x4F; 235#endif 236#if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) 237 RTC.PARAMRAM[0x03] = 0x48; 238 239 /* video board id */ 240 RTC.PARAMRAM[0x46] = /* 0x42 */ 0x76; /* 'v' */ 241 RTC.PARAMRAM[0x47] = /* 0x32 */ 0x4D; /* 'M' */ 242 /* mode */ 243#if (0 == vMacScreenDepth) || (vMacScreenDepth >= 4) 244 RTC.PARAMRAM[0x48] = 0x80; 245#else 246 RTC.PARAMRAM[0x48] = 0x81; 247 /* 0x81 doesn't quite work right at boot */ 248 /* no, it seems to work now (?) */ 249 /* but only if depth <= 3 */ 250#endif 251#endif 252 253#if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) 254 RTC.PARAMRAM[0x77] = 0x01; 255#endif 256 257#if ((CurEmMd >= kEmMd_SE) && (CurEmMd <= kEmMd_Classic)) \ 258 || (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) 259 260 /* start up disk (encoded how?) */ 261 RTC.PARAMRAM[0x78] = 0x00; 262 RTC.PARAMRAM[0x79] = 0x01; 263 RTC.PARAMRAM[0x7A] = 0xFF; 264 RTC.PARAMRAM[0x7B] = 0xFE; 265#endif 266 267#if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) 268 RTC.PARAMRAM[0x80] = 0x09; 269 RTC.PARAMRAM[0x81] = 0x80; 270#endif 271 272#if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) 273 274#define pr_HilColRedHi (pr_HilColRed >> 8) 275#if 0 != pr_HilColRedHi 276 RTC.PARAMRAM[0x82] = pr_HilColRedHi; 277#endif 278#define pr_HilColRedLo (pr_HilColRed & 0xFF) 279#if 0 != pr_HilColRedLo 280 RTC.PARAMRAM[0x83] = pr_HilColRedLo; 281#endif 282 283#define pr_HilColGreenHi (pr_HilColGreen >> 8) 284#if 0 != pr_HilColGreenHi 285 RTC.PARAMRAM[0x84] = pr_HilColGreenHi; 286#endif 287#define pr_HilColGreenLo (pr_HilColGreen & 0xFF) 288#if 0 != pr_HilColGreenLo 289 RTC.PARAMRAM[0x85] = pr_HilColGreenLo; 290#endif 291 292#define pr_HilColBlueHi (pr_HilColBlue >> 8) 293#if 0 != pr_HilColBlueHi 294 RTC.PARAMRAM[0x86] = pr_HilColBlueHi; 295#endif 296#define pr_HilColBlueLo (pr_HilColBlue & 0xFF) 297#if 0 != pr_HilColBlueLo 298 RTC.PARAMRAM[0x87] = pr_HilColBlueLo; 299#endif 300 301#endif /* (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) */ 302 303#if HaveXPRAM /* extended parameter ram initialized */ 304 do_put_mem_long(&RTC.PARAMRAM[0xE4], CurMacLatitude); 305 do_put_mem_long(&RTC.PARAMRAM[0xE8], CurMacLongitude); 306 do_put_mem_long(&RTC.PARAMRAM[0xEC], CurMacDelta); 307#endif 308 309#endif /* RTCinitPRAM */ 310 311 return trueblnr; 312} 313 314#ifdef RTC_OneSecond_PulseNtfy 315IMPORTPROC RTC_OneSecond_PulseNtfy(void); 316#endif 317 318GLOBALPROC RTC_Interrupt(void) 319{ 320 ui5b Seconds = 0; 321 ui5b NewRealDate = CurMacDateInSeconds; 322 ui5b DateDelta = NewRealDate - LastRealDate; 323 324 if (DateDelta != 0) { 325 Seconds = (RTC.Seconds_1[3] << 24) + (RTC.Seconds_1[2] << 16) 326 + (RTC.Seconds_1[1] << 8) + RTC.Seconds_1[0]; 327 Seconds += DateDelta; 328 RTC.Seconds_1[0] = Seconds & 0xFF; 329 RTC.Seconds_1[1] = (Seconds & 0xFF00) >> 8; 330 RTC.Seconds_1[2] = (Seconds & 0xFF0000) >> 16; 331 RTC.Seconds_1[3] = (Seconds & 0xFF000000) >> 24; 332 333 LastRealDate = NewRealDate; 334 335#ifdef RTC_OneSecond_PulseNtfy 336 RTC_OneSecond_PulseNtfy(); 337#endif 338 } 339} 340 341LOCALFUNC ui3b RTC_Access_PRAM_Reg(ui3b Data, blnr WriteReg, ui3b t) 342{ 343 if (WriteReg) { 344 if (! RTC.WrProtect) { 345 RTC.PARAMRAM[t] = Data; 346#ifdef _RTC_Debug 347 printf("Writing Address %2x, Data %2x\n", t, Data); 348#endif 349 } 350 } else { 351 Data = RTC.PARAMRAM[t]; 352 } 353 return Data; 354} 355 356LOCALFUNC ui3b RTC_Access_Reg(ui3b Data, blnr WriteReg, ui3b TheCmd) 357{ 358 ui3b t = (TheCmd & 0x7C) >> 2; 359 if (t < 8) { 360 if (WriteReg) { 361 if (! RTC.WrProtect) { 362 RTC.Seconds_1[t & 0x03] = Data; 363 } 364 } else { 365 Data = RTC.Seconds_1[t & 0x03]; 366 } 367 } else if (t < 12) { 368 Data = RTC_Access_PRAM_Reg(Data, WriteReg, 369 (t & 0x03) + Group2Base); 370 } else if (t < 16) { 371 if (WriteReg) { 372 switch (t) { 373 case 12 : 374 break; /* Test Write, do nothing */ 375 case 13 : 376 RTC.WrProtect = (Data & 0x80) != 0; 377 break; /* Write_Protect Register */ 378 default : 379 ReportAbnormalID(0x0801, "Write RTC Reg unknown"); 380 break; 381 } 382 } else { 383 ReportAbnormalID(0x0802, "Read RTC Reg unknown"); 384 } 385 } else { 386 Data = RTC_Access_PRAM_Reg(Data, WriteReg, 387 (t & 0x0F) + Group1Base); 388 } 389 return Data; 390} 391 392LOCALPROC RTC_DoCmd(void) 393{ 394 switch (RTC.Mode) { 395 case 0: /* This Byte is a RTC Command */ 396#if HaveXPRAM 397 if ((RTC.ShiftData & 0x78) == 0x38) { /* Extended Command */ 398 RTC.SavedCmd = RTC.ShiftData; 399 RTC.Mode = 2; 400#ifdef _RTC_Debug 401 printf("Extended command %2x\n", RTC.ShiftData); 402#endif 403 } else 404#endif 405 { 406 if ((RTC.ShiftData & 0x80) != 0x00) { /* Read Command */ 407 RTC.ShiftData = 408 RTC_Access_Reg(0, falseblnr, RTC.ShiftData); 409 RTC.DataNextOut = 1; 410 } else { /* Write Command */ 411 RTC.SavedCmd = RTC.ShiftData; 412 RTC.Mode = 1; 413 } 414 } 415 break; 416 case 1: /* This Byte is data for RTC Write */ 417 (void) RTC_Access_Reg(RTC.ShiftData, 418 trueblnr, RTC.SavedCmd); 419 RTC.Mode = 0; 420 break; 421#if HaveXPRAM 422 case 2: /* This Byte is rest of Extended RTC command address */ 423#ifdef _RTC_Debug 424 printf("Mode 2 %2x\n", RTC.ShiftData); 425#endif 426 RTC.Sector = ((RTC.SavedCmd & 0x07) << 5) 427 | ((RTC.ShiftData & 0x7C) >> 2); 428 if ((RTC.SavedCmd & 0x80) != 0x00) { /* Read Command */ 429 RTC.ShiftData = RTC.PARAMRAM[RTC.Sector]; 430 RTC.DataNextOut = 1; 431 RTC.Mode = 0; 432#ifdef _RTC_Debug 433 printf("Reading X Address %2x, Data %2x\n", 434 RTC.Sector, RTC.ShiftData); 435#endif 436 } else { 437 RTC.Mode = 3; 438#ifdef _RTC_Debug 439 printf("Writing X Address %2x\n", RTC.Sector); 440#endif 441 } 442 break; 443 case 3: /* This Byte is data for an Extended RTC Write */ 444 (void) RTC_Access_PRAM_Reg(RTC.ShiftData, 445 trueblnr, RTC.Sector); 446 RTC.Mode = 0; 447 break; 448#endif 449 } 450} 451 452GLOBALPROC RTCunEnabled_ChangeNtfy(void) 453{ 454 if (RTCunEnabled) { 455 /* abort anything going on */ 456 if (RTC.Counter != 0) { 457#ifdef _RTC_Debug 458 printf("aborting, %2x\n", RTC.Counter); 459#endif 460 ReportAbnormalID(0x0803, "RTC aborting"); 461 } 462 RTC.Mode = 0; 463 RTC.DataOut = 0; 464 RTC.DataNextOut = 0; 465 RTC.ShiftData = 0; 466 RTC.Counter = 0; 467 } 468} 469 470GLOBALPROC RTCclock_ChangeNtfy(void) 471{ 472 if (! RTCunEnabled) { 473 if (RTCclock) { 474 RTC.DataOut = RTC.DataNextOut; 475 RTC.Counter = (RTC.Counter - 1) & 0x07; 476 if (RTC.DataOut) { 477 RTCdataLine = ((RTC.ShiftData >> RTC.Counter) & 0x01); 478 /* 479 should notify VIA if changed, so can check 480 data direction 481 */ 482 if (RTC.Counter == 0) { 483 RTC.DataNextOut = 0; 484 } 485 } else { 486 RTC.ShiftData = (RTC.ShiftData << 1) | RTCdataLine; 487 if (RTC.Counter == 0) { 488 RTC_DoCmd(); 489 } 490 } 491 } 492 } 493} 494 495GLOBALPROC RTCdataLine_ChangeNtfy(void) 496{ 497#if dbglog_HAVE 498 if (RTC.DataOut) { 499 if (! RTC.DataNextOut) { 500 /* 501 ignore. The ROM doesn't read from the RTC the 502 way described in the Hardware Reference. 503 It reads the data after setting the clock to 504 one instead of before, and then immediately 505 changes the VIA direction. So the RTC 506 has no way of knowing to stop driving the 507 data line, which certainly can't really be 508 correct. 509 */ 510 } else { 511 ReportAbnormalID(0x0804, 512 "write RTC Data unexpected direction"); 513 } 514 } 515#endif 516} 517 518#endif /* EmRTC */